1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: demo_Particle.cpp
4
5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Revision: 28130 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nw/ut.h>
17 #include <nw/gfx.h>
18 #include <nw/demo.h>
19
20 #include <nw/demo/demo_Particle.h>
21
22 namespace nw
23 {
24 namespace demo
25 {
26
27 NW_UT_RUNTIME_TYPEINFO_DEFINITION(ParticleHandle, gfx::TransformNode);
28
29 //----------------------------------------
ParticleHandle(os::IAllocator * allocator,gfx::ResTransformNode resObj,const gfx::TransformNode::Description & description)30 ParticleHandle::ParticleHandle(
31 os::IAllocator* allocator,
32 gfx::ResTransformNode resObj,
33 const gfx::TransformNode::Description& description)
34 : gfx::TransformNode(allocator, resObj, description),
35 m_ModelInstances(allocator),
36 m_EmitterInstances(allocator)
37 {
38
39 }
40
41 //----------------------------------------
42 ParticleHandle*
Create(os::IAllocator * allocator)43 ParticleHandle::DynamicBuilder::Create(
44 os::IAllocator* allocator
45 )
46 {
47 NW_NULL_ASSERT(allocator);
48
49 void* memory = allocator->Alloc(sizeof(ParticleHandle));
50
51 if (memory == NULL)
52 {
53 return NULL;
54 }
55
56 ParticleHandle* node = new(memory) ParticleHandle(
57 allocator,
58 nw::gfx::ResTransformNode(),
59 m_Description);
60
61 {
62 gfx::Result result = node->Initialize(allocator);
63 if (!result.IsSuccess())
64 {
65 SafeDestroy(node);
66 return NULL;
67 }
68 }
69
70 return node;
71 }
72
73
74 //--------------------------------------------------------------------------
75
76 nw::demo::ResourceSet* ParticleEffect::m_ShaderResource = NULL;
77 os::IAllocator* ParticleEffect::m_ShaderAllocator = NULL;
78
79 ParticleEffect*
Create(os::IAllocator * mainAllocator,os::IAllocator * deviceAllocator,bool autoAlocate,gfx::ParticleContext * particleContext)80 ParticleEffect::Create(os::IAllocator* mainAllocator,
81 os::IAllocator* deviceAllocator,
82 bool autoAlocate,
83 gfx::ParticleContext* particleContext)
84 {
85 NW_NULL_ASSERT( mainAllocator );
86
87 void* memory = mainAllocator->Alloc( sizeof(ParticleEffect) );
88 NW_ASSERT( memory != NULL );
89 ParticleEffect* particleEffect = new(memory) ParticleEffect(mainAllocator,
90 deviceAllocator,
91 autoAlocate,
92 particleContext);
93
94 return particleEffect;
95 }
96
97
98 //--------------------------------------------------------------------------
99 void
Destroy()100 ParticleEffect::Destroy()
101 {
102 os::IAllocator* allocator = this->m_MainAllocator;
103
104 NW_ASSERT( allocator != NULL );
105
106 this->~ParticleEffect();
107 allocator->Free(this);
108 }
109
110
111 //----------------------------------------
112 void
Setup(gfx::ResGraphicsFile resource,bool useParticleMaterial)113 ParticleEffect::Setup(gfx::ResGraphicsFile resource, bool useParticleMaterial)
114 {
115 // テクスチャはVRAMに配置します。
116 resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
117
118 // パーティクルマテリアルを使用する場合は、フラグを使用フラグを立てます。
119 if (useParticleMaterial)
120 {
121 resource.ForeachModelMaterial(nw::gfx::ParticleMaterialFlagSetter());
122 }
123
124 // パーティクルシェーダバイナリがリソースに含まれない場合は、
125 // 外部から読みこんだシェーダをアタッチします。
126
127 nw::gfx::Result result = resource.Setup(m_DeviceAllocator);
128
129 if (result.IsFailure())
130 {
131 if (m_ShaderResource && (result.GetDescription() & nw::gfx::RESOURCE_RESULT_NOT_FOUND_SHADER))
132 {
133 // シェーダーが見つからなかったときは、外部ファイルを指定して再びセットアップします。
134 result = resource.Setup(m_DeviceAllocator, m_ShaderResource->resource);
135 }
136
137 if (result.IsFailure())
138 {
139 NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
140 }
141 }
142 }
143
144 //----------------------------------------
145 void
Register(gfx::ResGraphicsFile resource,const char ** nodeNames)146 ParticleEffect::Register(gfx::ResGraphicsFile resource, const char** nodeNames)
147 {
148 nw::gfx::ResModelArray models = resource.GetModels();
149 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
150 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
151 modelResource != modelsEnd; ++modelResource)
152 {
153 const char *resourceName = (*modelResource).GetName();
154
155 const char** name = nodeNames;
156 bool find = false;
157 while (!find && *name != NULL)
158 {
159 if (strcmp(resourceName, *name) == 0)
160 {
161 find = true;
162 }
163
164 ++name;
165 }
166
167 if (find)
168 {
169 m_ResModels.PushBack(nw::gfx::ResDynamicCast<nw::gfx::ResParticleModel>(*modelResource));
170 }
171 }
172
173 nw::gfx::ResEmitterArray emitters = resource.GetEmitters();
174 for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
175 emitterResource != emitters.end(); ++emitterResource)
176 {
177 const char *resourceName = (*emitterResource).GetName();
178
179 const char** name = nodeNames;
180 bool find = false;
181 while (!find && *name != NULL)
182 {
183 if (strcmp(resourceName, *name) == 0)
184 {
185 find = true;
186 }
187
188 ++name;
189 }
190
191 if (find)
192 {
193 m_ResEmitters.PushBack(*emitterResource);
194 }
195 }
196 }
197
198
199 //----------------------------------------
200 void
Register(gfx::ResGraphicsFile resource)201 ParticleEffect::Register(gfx::ResGraphicsFile resource)
202 {
203 nw::gfx::ResModelArray models = resource.GetModels();
204 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
205 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
206 modelResource != modelsEnd; ++modelResource)
207 {
208 nw::ut::ResTypeInfo resTypeInfo = (*modelResource).GetTypeInfo();
209 if ( resTypeInfo == nw::gfx::ResParticleModel::TYPE_INFO)
210 {
211 m_ResModels.PushBack(nw::gfx::ResDynamicCast<nw::gfx::ResParticleModel>(*modelResource));
212 }
213 }
214
215 nw::gfx::ResEmitterArray emitters = resource.GetEmitters();
216 for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
217 emitterResource != emitters.end(); ++emitterResource)
218 {
219 m_ResEmitters.PushBack(*emitterResource);
220 }
221 }
222
223
224 ParticleHandle*
Allocate()225 ParticleEffect::Allocate()
226 {
227 // ParticleHandleを生成します。
228 ParticleHandle* top = ParticleHandle::DynamicBuilder()
229 .MaxCallbacks(0)
230 .MaxChildren(this->m_ResModels.Size() + this->m_ResEmitters.Size())
231 .Create(this->m_MainAllocator);
232
233 top->SetID(this->m_NextId++);
234
235 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(this->m_MainAllocator);
236
237 // モデル生成
238 NW_FOREACH(const nw::gfx::ResParticleModel resModel, this->m_ResModels)
239 {
240 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
241 .Resource(resModel)
242 .CreateObject(this->m_MainAllocator, this->m_DeviceAllocator);
243
244 nw::gfx::SceneNode* node = nw::ut::DynamicCast<nw::gfx::SceneNode*>(sceneObject);
245 sceneNodeArray.PushBack(node);
246
247 nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(node);
248 top->RegisterParticleModel(model);
249 }
250
251 // エミッタ生成
252 NW_FOREACH(const nw::gfx::ResParticleEmitter resEmitter, this->m_ResEmitters)
253 {
254 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
255 .Resource(resEmitter)
256 .CreateObject(this->m_MainAllocator, this->m_DeviceAllocator);
257
258 nw::gfx::SceneNode* node = nw::ut::DynamicCast<nw::gfx::SceneNode*>(sceneObject);
259 sceneNodeArray.PushBack(node);
260
261 nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(node);
262 top->RegisterParticleEmitter(emitter);
263 }
264
265 // 階層再構築
266 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
267
268 // パーティクルの参照解決・初期化
269 nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, this->m_ParticleContext);
270
271 // トップノードにアタッチ
272 NW_FOREACH(nw::gfx::SceneNode* node, sceneNodeArray)
273 {
274 if (node->GetParent() == NULL)
275 {
276 top->AttachChild(node);
277 }
278 }
279
280 return top;
281 }
282
283 void
DestroyParticleHandle(ParticleNode * node)284 ParticleEffect::DestroyParticleHandle(ParticleNode* node)
285 {
286 NW_NULL_ASSERT(node);
287
288 nw::gfx::SafeDestroyBranch(node);
289 }
290
291
292 //! @brief ParticleHandleを生成します。
293 //! @return 生成されたParticleHandleインスタンスを返します。
294 ParticleHandle*
CreateMultiEmitterParticleHandle(u32 particleEmitterNum)295 ParticleEffect::CreateMultiEmitterParticleHandle(u32 particleEmitterNum)
296 {
297 NW_ASSERT( particleEmitterNum != 0 );
298
299 // ParticleHandleを生成します。
300 ParticleHandle* top = ParticleHandle::DynamicBuilder()
301 .MaxCallbacks(0)
302 .MaxChildren(this->m_ResModels.Size() + particleEmitterNum)
303 .Create(this->m_MainAllocator);
304
305 top->SetID(this->m_NextId++);
306
307 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(this->m_MainAllocator);
308
309 // モデルを生成します。
310 NW_FOREACH(const nw::gfx::ResParticleModel resModel, this->m_ResModels)
311 {
312 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
313 .Resource(this->m_ResModels[0])
314 .CreateObject(this->m_MainAllocator, this->m_DeviceAllocator);
315
316 nw::gfx::SceneNode* node = nw::ut::DynamicCast<nw::gfx::SceneNode*>(sceneObject);
317 sceneNodeArray.PushBack(node);
318
319 nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(node);
320 top->RegisterParticleModel(model);
321 }
322
323 // エミッタを指定個数だけ生成します。
324 for (u32 i = 0; i < particleEmitterNum; ++i)
325 {
326 // エミッタ生成
327 NW_FOREACH(const nw::gfx::ResParticleEmitter resEmitter, this->m_ResEmitters)
328 {
329 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
330 .Resource(this->m_ResEmitters[0])
331 .CreateObject(this->m_MainAllocator, this->m_DeviceAllocator);
332
333 nw::gfx::SceneNode* node = nw::ut::DynamicCast<nw::gfx::SceneNode*>(sceneObject);
334 sceneNodeArray.PushBack(node);
335
336 nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(node);
337 top->RegisterParticleEmitter(emitter);
338 }
339 }
340
341 // 階層再構築
342 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
343
344 // パーティクルの参照解決・初期化
345 nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, this->m_ParticleContext);
346
347 // トップノードにアタッチ
348 NW_FOREACH(nw::gfx::SceneNode* node, sceneNodeArray)
349 {
350 if (node->GetParent() == NULL)
351 {
352 top->AttachChild(node);
353 }
354 }
355
356 return top;
357 }
358
359
360 //! @brief 外部シェーダファイルをロードします。
361 void
InitializeShaderBinary(const wchar_t * shaderFilePath,os::IAllocator * deviceAllocator)362 ParticleEffect::InitializeShaderBinary(const wchar_t* shaderFilePath, os::IAllocator* deviceAllocator)
363 {
364 NW_NULL_ASSERT(shaderFilePath);
365 NW_NULL_ASSERT(deviceAllocator);
366
367 if (m_ShaderResource) return;
368
369 m_ShaderAllocator = deviceAllocator;
370
371 // ファイルからシェーダリソースを読み込みます。
372 m_ShaderResource = deviceAllocator->AllocAndConstruct<nw::demo::ResourceSet>(1);
373 m_ShaderResource->buffer = nw::demo::Utility::LoadFile(m_ShaderAllocator, shaderFilePath);
374
375 NW_NULL_ASSERT(m_ShaderResource->buffer);
376
377 m_ShaderResource->resource = nw::gfx::ResGraphicsFile(&(m_ShaderResource->buffer.front()));
378 }
379
380 //! @brief ロードした外部シェーダファイルを破棄します。
FinalizeShaderBinary()381 void ParticleEffect::FinalizeShaderBinary()
382 {
383 nw::ut::SafeCleanup(m_ShaderResource->resource);
384 m_ShaderAllocator->DestructAndFree(m_ShaderResource, 1);
385
386 m_ShaderResource = NULL;
387 m_ShaderAllocator = NULL;
388 }
389
390 } // namespace demo
391 } // namespace nw
392