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