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