1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleChokeDemo.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: 28152 $
14  *---------------------------------------------------------------------------*/
15 /*
16 エミッタからの放出を停止し、全てのパーティクルの終了を待つデモです。
17 */
18 
19 #define NW_DEBUG_CHECK_MEMORY_LEAK
20 
21 #include <nn/os.h>
22 #include <nn/fs.h>
23 
24 #include <nw/types.h>
25 #include <nw/demo.h>
26 #include <nw/dev.h>
27 #include <nw/gfx.h>
28 #include <nw/ut.h>
29 
30 namespace
31 {
32 
33 //----------------------------------------
34 // メモリ関係
35 
36 // デバイスメモリを確保するためのアロケータです。
37 nw::demo::DemoAllocator s_DeviceAllocator;
38 nw::demo::DemoAllocator s_ParticleAllocator;
39 
40 //----------------------------------------
41 // ファイル名の定義です。
42 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
43 
44 const wchar_t* MODEL_RESOURCE_FILES[] =
45 {
46     NW_DEMO_FILE_PATH(L"fountain_particle_all.bcptl"),
47     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
48     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
49 };
50 
51 //----------------------------------------
52 // 描画関係
53 const int RENDER_TARGET_COUNT = 1;
54 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
55 
56 RenderTargetArray s_RenderTargets;
57 nw::demo::SceneSystem*  s_SceneSystem = NULL;
58 nw::demo::RenderSystem* s_RenderSystem = NULL;
59 nw::gfx::ParticleContext* s_ParticleContext = NULL;
60 
61 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
62 
63 //----------------------------------------
64 // リソース関係
65 nw::demo::ResourceArray s_Resources;
66 
67 //----------------------------------------
68 // シーン関係
69 nw::gfx::SceneNode* s_SceneRoot = NULL;
70 s32 s_FrameCount = 0;
71 nw::gfx::Camera* s_BaseCamera = NULL;
72 nw::gfx::Camera* s_LeftCamera = NULL;
73 nw::gfx::Camera* s_RightCamera = NULL;
74 const f32 s_fNearPlane = 0.1f;
75 
76 const s32 s_BaseCameraIndex = 0;
77 
78 //----------------------------------------
79 // パーティクル関係
80 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
81 
82 nw::demo::FlushCache* s_FlushCache;
83 
84 
85 /*!--------------------------------------------------------------------------*
86   @brief        グラフィックス関連の初期化を行います。
87  *---------------------------------------------------------------------------*/
88 void
InitializeGraphics()89 InitializeGraphics()
90 {
91     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
92 
93     // renderDescriptionへステレオの設定を行います。
94     nw::demo::RenderSystem::Description renderDescription;
95 
96     renderDescription.reusableCommandBufferSize = 0x100000;
97     renderDescription.reusableCommandRequestCount      = 512;
98     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
99 
100     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
101 
102     s_GraphicsDrawing.SetScreenSize(
103         renderDescription.lowerScreenDescription.width,
104         renderDescription.lowerScreenDescription.height
105     );
106 
107     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
108 
109     s_RenderTargets.push_back(
110         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
111     );
112     NW_ASSERT(!s_RenderTargets.empty());
113     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
114 
115     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
116     nw::demo::SceneSystem::Description sceneDescription;
117     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
118 
119     s_ParticleContext = nw::gfx::ParticleContext::Builder()
120         .Create(&s_DeviceAllocator);
121 
122     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
123         .Create(&s_DeviceAllocator);
124 
125     // デモ用の最遠景モデルをレンダリングシステムに設定します。
126     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
127     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
128 
129     NW_GL_ASSERT();
130 }
131 
132 /*!--------------------------------------------------------------------------*
133   @brief        グラフィックス関連の後始末をします。
134  *---------------------------------------------------------------------------*/
135 void
TerminateGraphics()136 TerminateGraphics()
137 {
138     nw::gfx::SafeDestroy(s_LeftCamera);
139 
140     nw::gfx::SafeDestroy(s_RightCamera);
141 
142     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
143 
144     nw::gfx::SafeDestroy(s_ParticleContext);
145 
146     nw::gfx::SafeDestroy(s_SceneSystem);
147 
148     nw::gfx::SafeDestroyAll(s_RenderTargets);
149 
150     s_GraphicsDrawing.Finalize();
151 
152     nw::gfx::SafeDestroy(s_RenderSystem);
153 
154     NW_GL_ASSERT();
155 }
156 
157 
158 /*!--------------------------------------------------------------------------*
159   @brief        ルートノード関連の構築をします。
160  *---------------------------------------------------------------------------*/
161 void
BuildRootNodes()162 BuildRootNodes()
163 {
164     NW_ASSERT(s_SceneRoot == NULL);
165     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
166         .IsFixedSizeMemory(false)
167         .Create(&s_DeviceAllocator);
168     NW_NULL_ASSERT(s_SceneRoot);
169 }
170 
171 /*!--------------------------------------------------------------------------*
172   @brief        カメラ関連の構築をします。
173  *---------------------------------------------------------------------------*/
174 void
BuildCameras()175 BuildCameras()
176 {
177     nw::demo::Utility::CreateStereoCameras(
178         &s_BaseCamera,
179         &s_LeftCamera,
180         &s_RightCamera,
181         &s_DeviceAllocator,
182         nw::math::VEC3(28.0f, 22.0f, 28.0f),
183         nw::math::VEC3(0.0f, 0.0f, 0.0f),
184         s_fNearPlane
185     );
186 
187     s_SceneRoot->AttachChild(s_BaseCamera);
188     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
189 }
190 
191 
192 /*!--------------------------------------------------------------------------*
193   @brief        シーンを初期化します。
194  *---------------------------------------------------------------------------*/
195 void
InitializeScenes()196 InitializeScenes()
197 {
198     BuildRootNodes();
199 
200     BuildCameras();
201 
202     // シーンツリーを巡回して初期化を行います。
203     s_SceneSystem->InitializeScene(s_SceneRoot);
204     s_SceneSystem->UpdateScene();
205 
206     // カメラを設定します。
207     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
208     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
209     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
210 
211     NW_GL_ASSERT();
212 
213     //-----------------------------------------------------------------------------
214     s_FrameCount = 0;
215 }
216 
217 /*!--------------------------------------------------------------------------*
218   @brief        シーン関連の後始末をします。
219  *---------------------------------------------------------------------------*/
220 void
TerminateScenes()221 TerminateScenes()
222 {
223     nw::gfx::SafeDestroyBranch(s_SceneRoot);
224     nw::demo::SafeCleanupResources(s_Resources);
225 
226     NW_GL_ASSERT();
227 
228     s_Resources.clear();
229 }
230 
231 /*!--------------------------------------------------------------------------*
232   @brief        シーンを更新します。
233  *---------------------------------------------------------------------------*/
234 void
UpdateScene()235 UpdateScene()
236 {
237     NW_ASSERT(0 < s_RenderTargets.size());
238 
239     s_SceneSystem->GetCameraController()->Update();
240 
241     s_SceneSystem->UpdateScene();
242 
243     s_BaseCamera->UpdateCameraMatrix();
244 
245     NW_NULL_ASSERT(s_ParticleSceneUpdater);
246     s_ParticleSceneUpdater->UpdateNode(
247         s_SceneSystem->GetSceneContext(),
248         s_ParticleContext);
249 
250     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
251 
252     s_FrameCount++;
253 
254     s_FlushCache->Execute();
255 }
256 
257 /*!--------------------------------------------------------------------------*
258   @brief        負荷表示やテスト機能の処理をおこないます。
259  *---------------------------------------------------------------------------*/
260 void
ReportDemo()261 ReportDemo()
262 {
263     NW_PROFILE("ReportDemo");
264 
265     // 負荷表示からはこれらの負荷は除きます。
266     s_RenderSystem->SuspendLoadMeter();
267 
268     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
269 
270     s_GraphicsDrawing.BeginDrawingShape();
271 
272     nw::demo::DebugUtility::DrawLoadMeter(
273         s_RenderSystem,
274         &s_GraphicsDrawing
275     );
276 
277     s_GraphicsDrawing.EndDrawingShape();
278 
279     s_GraphicsDrawing.BeginDrawingString();
280 
281     nw::demo::DebugUtility::DrawLoadMeterText(
282         s_RenderSystem,
283         &s_GraphicsDrawing
284     );
285 
286     s_GraphicsDrawing.EndDrawingString();
287 
288     s_RenderSystem->ResumeLoadMeter();
289 }
290 
291 
292 
293 
294 //----------------------------------------
295 // デモ固有の変数
296 
297 // パーティクルエフェクトクラス
298 nw::demo::ParticleEffect* s_ParticleEffect = NULL;
299 
300 // パーティクルノードクラス
301 nw::demo::ParticleNode* s_particleNode = NULL;
302 
303 // 親ノード
304 nw::gfx::SceneNode* s_ParentNode = NULL;
305 
306 // 再生が終了しているか?
307 bool s_IsDone = false;
308 
309 // ロードするエフェクトファイル名
310 const wchar_t* EFFECT_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"light_particle.bcptl");
311 
312 // ロードするエフェクトシェーダファイル
313 const wchar_t* SHADER_RESOURCE_FILE_NAME = NW_DEMO_FILE_PATH(L"nwgfx_ParticleDefaultShader.bcsdr");
314 
315 
316 /*!--------------------------------------------------------------------------*
317   @brief        ParticleChokeDemoの初期化を行います。
318  *---------------------------------------------------------------------------*/
319 void
InitializeParticleChokeDemo()320 InitializeParticleChokeDemo()
321 {
322     // このデモは、パーティクルの終了を検知、パーティクルの再利用を行っています。
323 
324     // シェーダバイナリをロードします。
325     nw::demo::ParticleEffect::InitializeShaderBinary(SHADER_RESOURCE_FILE_NAME, &s_DeviceAllocator);
326 
327     // パーティクルエフェクトクラスを生成します。
328     s_ParticleEffect = nw::demo::ParticleEffect::Create(&s_DeviceAllocator, &s_DeviceAllocator, false, s_ParticleContext);
329 
330     // エフェクトデータをロードしてセットアップします。
331     nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, EFFECT_RESOURCE_FILE, &s_DeviceAllocator);
332 
333     // リソースをセットアップを行います。
334     s_ParticleEffect->Setup(resourceSet->resource, true);
335 
336     // ParticleEffectにリソースをセットします。
337     s_ParticleEffect->Register(resourceSet->resource);
338 
339     // ParticleEffect内にインスタンスを1つだけ準備します。
340     s_ParticleEffect->AddPool(1);
341 
342     // ParticleEffect内に準備されたインスタンスを借りてきます。
343     s_particleNode = s_ParticleEffect->LeaseInstance();
344 
345     // インスタンスをシーンに追加し、シーンの更新を行います。
346     s_SceneRoot->AttachChild(s_particleNode);
347     s_SceneSystem->InitializeScene(s_SceneRoot);
348     s_SceneSystem->UpdateScene();
349 
350     // このデモでは、親ノードへAttach,Detachを行うので、親ノードを保持します。
351     s_ParentNode = s_particleNode->GetParent();
352 
353     // 操作説明をログ出力します。
354     NW_DEV_LOG("[ParticleChokeDemo]\n");
355     NW_DEV_LOG("Button R : Restart Partcile\n");
356 }
357 
358 /*!--------------------------------------------------------------------------*
359   @brief        ParticleChokeDemoの定期処理です。
360  *---------------------------------------------------------------------------*/
361 void
UpdateParticleChokeDemo()362 UpdateParticleChokeDemo()
363 {
364     // 再生が終了しているかチェックします。
365     // IsDoneメソッド内では、ParticleModelが保持するパーティクル数と、
366     // ParticleEmitterの放出完了かどうかをチェックします。
367     if ( !s_IsDone && s_particleNode->IsDone() )
368     {
369         // 再生が終了しているのであれば、Detachを行います。
370         // 再生終了したエフェクトのDetachを行うことで、
371         // 余計なシーングラフのコストを省きます。
372         s_ParentNode->DetachChild(s_particleNode);
373         s_SceneSystem->InitializeScene(s_SceneRoot);
374         s_IsDone = true;
375     }
376 
377     // 終了状態、且つ、Rボタンでリセットします。
378     if (s_IsDone && nw::demo::PadFactory::GetPad()->IsButtonDown(nw::demo::Pad::BUTTON_R))
379     {
380         // Resetメソッド内では、ParticleEmitterのリセット処理、
381         // ParticleModel内、アニメーションフレームの0初期化、
382         // 及び、ParticleCollectionのClear処理が行われています。
383         // また、コマンド2重化時には、ResetメソッドをGPU処理中にコールすることができません。
384         // Detachした後、GPU処理が終了の後、コールしてください。
385         s_particleNode->Reset();
386 
387         // リセット処理ののち、シーングラフ再度Attachを行います。
388         s_ParentNode->AttachChild(s_particleNode);
389         s_SceneSystem->InitializeScene(s_SceneRoot);
390         s_IsDone = false;
391     }
392 }
393 
394 /*!--------------------------------------------------------------------------*
395   @brief        ParticleChokeDemoのスクリーンデバッグ表示です。
396  *---------------------------------------------------------------------------*/
397 void
ReportParticleChokeDemo()398 ReportParticleChokeDemo()
399 {
400     s_GraphicsDrawing.DrawString(10, 10, "Particle Num  :%d\n", s_particleNode->GetParticleSize() );
401 
402     if (s_IsDone)
403     {
404         s_GraphicsDrawing.DrawString(10, 22, "Done:Push R Restart!\n" );
405     }
406     else
407     {
408         s_GraphicsDrawing.DrawString(10, 22, "Playing\n" );
409     }
410 }
411 
412 
413 /*!--------------------------------------------------------------------------*
414   @brief        ParticleChokeDemoの終了処理を行います。
415  *---------------------------------------------------------------------------*/
416 void
TerminateParticleChokeDemo()417 TerminateParticleChokeDemo()
418 {
419     nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0);
420     while (prevTarget != NULL)
421     {
422         s_ParticleEffect->ReleaseInstance(prevTarget);
423         prevTarget = s_ParticleEffect->GetActiveEffect(0);
424     }
425 
426     s_ParticleEffect->FreePool();
427 
428     nw::gfx::SafeDestroy(s_ParticleEffect);
429 
430     // ロードしたパーティクルシェーダを破棄します。
431     nw::demo::ParticleEffect::FinalizeShaderBinary();
432 }
433 
434 
435 
436 
437 /*!--------------------------------------------------------------------------*
438   @brief        シーンをデモンストレーションします。
439  *---------------------------------------------------------------------------*/
440 void
DemoScene()441 DemoScene()
442 {
443     NW_ASSERT(!s_RenderTargets.empty());
444 
445     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
446 
447     InitializeScenes();
448 
449     // ParticleChokeDemoの初期化処理です。
450     InitializeParticleChokeDemo();
451 
452     nw::demo::DebugUtility::PostInitializeScenes();
453 
454     int count = 0;
455     bool isContinuing = true;
456 
457     while ( isContinuing )
458     {
459         nw::demo::DebugUtility::AdvanceAutoTestFrame();
460 
461         nw::demo::PadFactory::GetPad()->Update();
462 
463         ++count;
464 
465         // ParticleChokeDemoの定期処理です。
466         UpdateParticleChokeDemo();
467 
468         UpdateScene();
469 
470         renderContext->SetActiveCamera(s_BaseCameraIndex);
471         s_RenderSystem->SubmitView(s_SceneSystem);
472 
473         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
474         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
475 
476         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
477         ReportDemo();
478 
479         // ParticleCtrlEmissionDemoのレポートを表示します。
480         ReportParticleChokeDemo();
481 
482         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
483 
484         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
485 
486         renderContext->ResetState();
487 
488         if (nw::demo::Utility::IsTerminating())
489         {
490             isContinuing = false;
491         }
492     }
493 
494     nw::demo::DebugUtility::PreTerminateScenes();
495 
496     // ParticleChokeDemoの終了処理です。
497     TerminateParticleChokeDemo();
498 
499     TerminateScenes();
500 }
501 
502 } // namespace
503 
504 /*!--------------------------------------------------------------------------*
505   @brief        メイン関数です。
506  *---------------------------------------------------------------------------*/
507 void
nnMain()508 nnMain()
509 {
510     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
511     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
512 
513     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
514 
515     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
516     {
517         InitializeGraphics();
518 
519         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
520 
521         DemoScene();
522 
523         nw::ut::SafeDestroy(s_FlushCache);
524 
525         TerminateGraphics();
526     }
527 
528     nw::demo::PadFactory::Finalize();
529 
530     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
531 
532     nw::demo::FinalizeGraphicsSystem();
533 }
534