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