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