1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ParticleCombinationNodeDemo.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: $
16  *---------------------------------------------------------------------------*/
17 
18 #define NW_DEBUG_CHECK_MEMORY_LEAK
19 
20 #include <nn/os.h>
21 #include <nn/fs.h>
22 
23 #include <nw/types.h>
24 #include <nw/demo.h>
25 #include <nw/dev.h>
26 #include <nw/gfx.h>
27 #include <nw/ut.h>
28 
29 namespace
30 {
31 
32 //----------------------------------------
33 // メモリ関係
34 
35 // デバイスメモリを確保するためのアロケータです。
36 nw::demo::DemoAllocator s_DeviceAllocator;
37 nw::demo::DemoAllocator s_ParticleAllocator;
38 
39 //----------------------------------------
40 // ファイル名の定義です。
41 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
42 
43 //----------------------------------------
44 // 描画関係
45 const int RENDER_TARGET_COUNT = 1;
46 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
47 
48 RenderTargetArray s_RenderTargets;
49 nw::demo::SceneSystem*  s_SceneSystem = NULL;
50 nw::demo::RenderSystem* s_RenderSystem = NULL;
51 nw::gfx::ParticleContext* s_ParticleContext = NULL;
52 
53 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
54 
55 //----------------------------------------
56 // リソース関係
57 nw::demo::ResourceArray s_Resources;
58 
59 //----------------------------------------
60 // シーン関係
61 nw::gfx::SceneNode* s_SceneRoot = NULL;
62 s32 s_FrameCount = 0;
63 nw::gfx::Camera* s_BaseCamera = NULL;
64 nw::gfx::Camera* s_LeftCamera = NULL;
65 nw::gfx::Camera* s_RightCamera = NULL;
66 const f32 s_fNearPlane = 0.1f;
67 
68 const s32 s_BaseCameraIndex = 0;
69 
70 //----------------------------------------
71 // パーティクル関係
72 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
73 
74 nw::demo::FlushCache* s_FlushCache;
75 
76 /*!--------------------------------------------------------------------------*
77   @brief        グラフィックス関連の初期化を行います。
78  *---------------------------------------------------------------------------*/
79 void
InitializeGraphics()80 InitializeGraphics()
81 {
82     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
83 
84     // renderDescriptionへステレオの設定を行います。
85     nw::demo::RenderSystem::Description renderDescription;
86 
87     renderDescription.reusableCommandBufferSize = 0x100000;
88     renderDescription.reusableCommandRequestCount      = 512;
89     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
90 
91     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
92 
93     s_GraphicsDrawing.SetScreenSize(
94         renderDescription.lowerScreenDescription.width,
95         renderDescription.lowerScreenDescription.height
96     );
97 
98     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
99 
100     s_RenderTargets.push_back(
101         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
102     );
103     NW_ASSERT(!s_RenderTargets.empty());
104     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
105 
106     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
107     nw::demo::SceneSystem::Description sceneDescription;
108     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
109 
110     s_ParticleContext = nw::gfx::ParticleContext::Builder()
111         .MaxEmission(1000)
112         .Create(&s_DeviceAllocator);
113 
114     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
115         .Create(&s_DeviceAllocator);
116 
117     // デモ用の最遠景モデルをレンダリングシステムに設定します。
118     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
119     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
120 
121     NW_GL_ASSERT();
122 }
123 
124 /*!--------------------------------------------------------------------------*
125   @brief        グラフィックス関連の後始末をします。
126  *---------------------------------------------------------------------------*/
127 void
TerminateGraphics()128 TerminateGraphics()
129 {
130     nw::gfx::SafeDestroy(s_LeftCamera);
131 
132     nw::gfx::SafeDestroy(s_RightCamera);
133 
134     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
135 
136     nw::gfx::SafeDestroy(s_ParticleContext);
137 
138     nw::gfx::SafeDestroy(s_SceneSystem);
139 
140     nw::gfx::SafeDestroyAll(s_RenderTargets);
141 
142     s_GraphicsDrawing.Finalize();
143 
144     nw::gfx::SafeDestroy(s_RenderSystem);
145 
146     NW_GL_ASSERT();
147 }
148 
149 /*!--------------------------------------------------------------------------*
150   @brief        ルートノード関連の構築をします。
151  *---------------------------------------------------------------------------*/
152 void
BuildRootNodes()153 BuildRootNodes()
154 {
155     NW_ASSERT(s_SceneRoot == NULL);
156     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
157         .IsFixedSizeMemory(false)
158         .Create(&s_DeviceAllocator);
159     NW_NULL_ASSERT(s_SceneRoot);
160 }
161 
162 /*!--------------------------------------------------------------------------*
163   @brief        カメラ関連の構築をします。
164  *---------------------------------------------------------------------------*/
165 void
BuildCameras()166 BuildCameras()
167 {
168     nw::demo::Utility::CreateStereoCameras(
169         &s_BaseCamera,
170         &s_LeftCamera,
171         &s_RightCamera,
172         &s_DeviceAllocator,
173         nw::math::VEC3(0.0f, 13.0f, 70.f),
174         nw::math::VEC3(0.0f, 13.0f, 0.0f),
175         s_fNearPlane
176     );
177 
178     s_SceneRoot->AttachChild(s_BaseCamera);
179     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
180 }
181 
182 
183 /*!--------------------------------------------------------------------------*
184   @brief        シーンを初期化します。
185  *---------------------------------------------------------------------------*/
186 void
InitializeScenes()187 InitializeScenes()
188 {
189     BuildRootNodes();
190 
191     BuildCameras();
192 
193     // シーンツリーを巡回して初期化を行います。
194     s_SceneSystem->InitializeScene(s_SceneRoot);
195     s_SceneSystem->UpdateScene();
196 
197     // カメラを設定します。
198     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
199     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
200     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
201 
202     NW_GL_ASSERT();
203 
204     s_FrameCount = 0;
205 }
206 
207 /*!--------------------------------------------------------------------------*
208   @brief        シーン関連の後始末をします。
209  *---------------------------------------------------------------------------*/
210 void
TerminateScenes()211 TerminateScenes()
212 {
213     nw::gfx::SafeDestroyBranch(s_SceneRoot);
214     nw::demo::SafeCleanupResources(s_Resources);
215 
216     NW_GL_ASSERT();
217 
218     s_Resources.clear();
219 }
220 
221 /*!--------------------------------------------------------------------------*
222   @brief        シーンを更新します。
223  *---------------------------------------------------------------------------*/
224 void
UpdateScene()225 UpdateScene()
226 {
227     NW_ASSERT(0 < s_RenderTargets.size());
228 
229     s_SceneSystem->GetCameraController()->Update();
230 
231     s_SceneSystem->UpdateScene();
232 
233     s_BaseCamera->UpdateCameraMatrix();
234 
235     NW_NULL_ASSERT(s_ParticleSceneUpdater);
236     s_ParticleSceneUpdater->UpdateNode(
237         s_SceneSystem->GetSceneContext(),
238         s_ParticleContext);
239 
240     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
241 
242     s_FrameCount++;
243 
244     s_FlushCache->Execute();
245 }
246 
247 /*!--------------------------------------------------------------------------*
248   @brief        負荷表示やテスト機能の処理をおこないます。
249  *---------------------------------------------------------------------------*/
250 void
ReportDemo()251 ReportDemo()
252 {
253     NW_PROFILE("ReportDemo");
254 
255     // 負荷表示からはこれらの負荷は除きます。
256     s_RenderSystem->SuspendLoadMeter();
257 
258     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
259 
260     s_GraphicsDrawing.BeginDrawingShape();
261 
262     nw::demo::DebugUtility::DrawLoadMeter(
263         s_RenderSystem,
264         &s_GraphicsDrawing
265     );
266 
267     s_GraphicsDrawing.EndDrawingShape();
268 
269     s_GraphicsDrawing.BeginDrawingString();
270 
271     nw::demo::DebugUtility::DrawLoadMeterText(
272         s_RenderSystem,
273         &s_GraphicsDrawing
274     );
275 
276     s_GraphicsDrawing.EndDrawingString();
277 
278     s_RenderSystem->ResumeLoadMeter();
279 }
280 
281 
282 
283 
284 //----------------------------------------
285 // デモ固有の変数
286 
287 // パーティクルエフェクトクラス
288 nw::demo::ParticleEffect* s_ParticleEffect = NULL;
289 
290 // 配置数
291 #define DEMO_FIRE_DRAW_NUM  (5)
292 
293 // パーティクルハンドルクラス
294 nw::demo::ParticleHandle* s_PaticleHandle5M5E[DEMO_FIRE_DRAW_NUM];
295 nw::demo::ParticleHandle* s_PaticleHandle1M5E = NULL;
296 nw::demo::ParticleHandle* s_PaticleHandle1M1E = NULL;
297 
298 // カウンタ
299 u32 s_Count = 0;
300 
301 // アニメーションステート
302 enum
303 {
304     DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER   = 0,
305     DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER   = 1,
306     DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER   = 2,
307     DEMO_ASSORTMENT_STATE_MAX               = 3
308 };
309 u32 s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER;
310 
311 // ロードするエフェクトファイル
312 const wchar_t* EFFECT_RESOURCE_FILE  = NW_DEMO_FILE_PATH(L"fire_particle_mem5.bcptl");
313 
314 // ロードするエフェクトシェーダファイル
315 const wchar_t* SHADER_RESOURCE_FILE_NAME = NW_DEMO_FILE_PATH(L"nwgfx_ParticleDefaultShader.bcsdr");
316 
317 
318 /*!--------------------------------------------------------------------------*
319   @brief        ParticleNodeCombinationDemoの初期化を行います。
320  *---------------------------------------------------------------------------*/
321 void
InitializeParticleNodeCombinationDemo()322 InitializeParticleNodeCombinationDemo()
323 {
324     // 以下のパーティクルモデル/エミッタ組み合わせを用いて、
325     // 炎エフェクトを画面に5つ表示するデモです。
326     // 5 ParticleModel - 5 ParticleEmitter(5M5E)
327     //   配置等の扱いは容易ですが、メモリ・処理速度面で不利です。
328     //
329     // 1 ParticleModel - 5 ParticleEmitter(1M5E)
330     //   自由度が低くなりますが、処理速度やメモリ使用量で有利です。
331     //
332     // 1 ParticleModel - 1 ParticleEmitter(1M1E)
333     //   自由度が低くなりますが、処理速度やメモリ使用量で有利です。
334     //   また、この手法は放出間隔が1フレームのデータにしか適用できません。
335     //   メモリ面では(1M1E)、速度面では(1M5E)の方が有利です。
336 
337     s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER;
338     s_Count = 0;
339     s_ParticleEffect = NULL;
340 
341     // シェーダバイナリをロードします。
342     nw::demo::ParticleEffect::InitializeShaderBinary(SHADER_RESOURCE_FILE_NAME, &s_DeviceAllocator);
343 
344     // パーティクルエフェクトクラスを生成します。
345     s_ParticleEffect = nw::demo::ParticleEffect::Create(&s_DeviceAllocator, &s_DeviceAllocator, false, s_ParticleContext);
346 
347     // エフェクトデータをロードしてセットアップします。
348     nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, EFFECT_RESOURCE_FILE, &s_DeviceAllocator);
349 
350     // リソースのセットアップを行います。
351     s_ParticleEffect->Setup(resourceSet->resource, false);
352 
353     // ParticleEffectにリソースをセットします。
354     s_ParticleEffect->Register(resourceSet->resource);
355     s_ParticleEffect->AddPool(6);
356 
357     // (5M5E)の準備を行います。
358     for (s32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i)
359     {
360         s_PaticleHandle5M5E[i] = s_ParticleEffect->LeaseInstance();
361         if (s_PaticleHandle5M5E[i])
362         {
363             s_PaticleHandle5M5E[i]->SetTranslate(10.0f * (i - 2), 0.f, 0.f);
364         }
365 
366         // シーンに追加します。
367         s_SceneRoot->AttachChild(s_PaticleHandle5M5E[i]);
368     }
369 
370     // (1M5E)の準備を行います。
371     s_PaticleHandle1M5E = s_ParticleEffect->CreateMultiEmitterParticleHandle( DEMO_FIRE_DRAW_NUM );
372     if (s_PaticleHandle1M5E)
373     {
374         for (s32 i = 0; i < s_PaticleHandle1M5E->GetParticleEmitterSize(); ++i)
375         {
376             s_PaticleHandle1M5E->GetParticleEmitter(i)->Transform().SetTranslate(10.0f * (i - 2), 0.f, 0.f);
377         }
378     }
379 
380     // (1M1E)の準備を行います。
381     s_PaticleHandle1M1E = s_ParticleEffect->LeaseInstance();
382     s_PaticleHandle1M1E->SetTranslate(0.f, 0.f, 0.f);
383     s_SceneRoot->AttachChild(s_PaticleHandle1M1E);
384 
385     // シーンを更新します。
386     s_SceneSystem->InitializeScene(s_SceneRoot);
387     s_SceneSystem->UpdateScene();
388 }
389 
390 /*!--------------------------------------------------------------------------*
391   @brief        ParticleNodeCombinationDemoの定期処理です。
392  *---------------------------------------------------------------------------*/
393 void
UpdateParticleNodeCombinationDemo()394 UpdateParticleNodeCombinationDemo()
395 {
396     ++s_Count;
397 
398     // 600フレームごとに組み合わせパターンを変更します。
399     if ( s_Count%600 == 0 )
400     {
401         s_Count = 0;
402 
403         switch(s_AnimationState)
404         {
405         case DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER:
406             {
407                 // (5M5E)ノードをデタッチします。
408                 for (u32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i)
409                 {
410                     s_SceneRoot->DetachChild(s_PaticleHandle5M5E[i]);
411                 }
412 
413                 // (1M5E)ノードをアタッチします。
414                 s_SceneRoot->AttachChild(s_PaticleHandle1M5E);
415 
416                 // シーンを更新します。
417                 s_SceneSystem->InitializeScene(s_SceneRoot);
418                 s_SceneSystem->UpdateScene();
419 
420                 s_AnimationState = DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER;
421             }
422             break;
423 
424         case DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER:
425             {
426                 // (1M5E)ノードをデタッチします。
427                 s_SceneRoot->DetachChild(s_PaticleHandle1M5E);
428 
429                 // (1M1E)ノードをアタッチします。
430                 s_SceneRoot->AttachChild(s_PaticleHandle1M1E);
431 
432                 // シーンを更新します。
433                 s_SceneSystem->InitializeScene(s_SceneRoot);
434                 s_SceneSystem->UpdateScene();
435 
436                 s_AnimationState = DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER;
437             }
438             break;
439 
440         case DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER:
441             {
442                 // (1M1E)ノードをデタッチします。
443                 s_SceneRoot->DetachChild(s_PaticleHandle1M1E);
444 
445                 // (5M5E)ノードをアタッチします。
446                 for (u32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i)
447                 {
448                     s_SceneRoot->AttachChild(s_PaticleHandle5M5E[i]);
449                 }
450 
451                 // シーンを更新します。
452                 s_SceneSystem->InitializeScene(s_SceneRoot);
453                 s_SceneSystem->UpdateScene();
454 
455                 s_AnimationState = DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER;
456             }
457             break;
458 
459         default:
460             break;
461         }
462     }
463 
464     // (1M1E)の場合は、毎フレーム放出位置の変更と放出処理を行う必要があります。
465     // 放出処理の後、Reset処理を行うので、放出間隔1フレーム以外の値を
466     // 指定しているデータにおいても、毎フレーム放出を行ってしまうので注意が必要です。
467     if( s_AnimationState == DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER )
468     {
469         nw::gfx::ParticleEmitter* emitter = s_PaticleHandle1M1E->GetParticleEmitter(0);
470         if (emitter)
471         {
472             for (s32 i = 0; i < DEMO_FIRE_DRAW_NUM; ++i)
473             {
474                 // 放出位置を設定します。
475                 emitter->WorldMatrix().SetupTranslate(nn::math::VEC3(nw::math::VEC3(10.0f * (i - 2), 0.f, 0.f)));
476 
477                 // 放出処理を行い、リセットを行います。
478                 emitter->UpdateParticleFrame();
479                 emitter->Emission(s_ParticleContext);
480                 emitter->Reset();
481             }
482         }
483     }
484 }
485 
486 /*!--------------------------------------------------------------------------*
487   @brief        ParticleNodeCombinationDemoのスクリーンデバッグ表示です。
488  *---------------------------------------------------------------------------*/
489 void
ReportParticleNodeCombinationDemo()490 ReportParticleNodeCombinationDemo()
491 {
492     s_GraphicsDrawing.DrawString(10, 10, "Counter              : %d\n", (600 - s_Count) );
493 
494     switch(s_AnimationState)
495     {
496     case DEMO_ASSORTMENT_STATE_5MODEL_5EMITTER:
497         {
498             s_GraphicsDrawing.DrawString(10, 22, "Particle Model   Num : 5\n" );
499             s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 5\n" );
500         }
501         break;
502 
503     case DEMO_ASSORTMENT_STATE_1MODEL_5EMITTER:
504         {
505             s_GraphicsDrawing.DrawString(10, 22, "Particle Model   Num : 1\n" );
506             s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 5\n" );
507         }
508         break;
509 
510     case DEMO_ASSORTMENT_STATE_1MODEL_1EMITTER:
511         {
512             s_GraphicsDrawing.DrawString(10, 22, "Particle Model   Num : 1\n" );
513             s_GraphicsDrawing.DrawString(10, 34, "Particle Emitter Num : 1\n" );
514         }
515         break;
516     }
517 }
518 
519 /*!--------------------------------------------------------------------------*
520   @brief        ParticleNodeCombinationDemoの終了処理を行います。
521  *---------------------------------------------------------------------------*/
522 void
TerminateParticleNodeCombinationDemo()523 TerminateParticleNodeCombinationDemo()
524 {
525 //    s_ParticleEffect->DestroyParticleHandle(s_PaticleHandle1M1E);
526     nw::demo::ParticleNode* prevTarget = s_ParticleEffect->GetActiveEffect(0);
527     while (prevTarget != NULL)
528     {
529         s_ParticleEffect->ReleaseInstance(prevTarget);
530         prevTarget = s_ParticleEffect->GetActiveEffect(0);
531     }
532 
533     // CreateMultiEmitterParticleHandle で生成したので、ハンドルの破棄が必要です。
534     s_ParticleEffect->DestroyParticleHandle(s_PaticleHandle1M5E);
535 
536     s_ParticleEffect->FreePool();
537 
538     nw::ut::SafeDestroy(s_ParticleEffect);
539 
540     // ロードしたパーティクルシェーダを破棄します。
541     nw::demo::ParticleEffect::FinalizeShaderBinary();
542 }
543 
544 
545 
546 
547 /*!--------------------------------------------------------------------------*
548   @brief        シーンをデモンストレーションします。
549  *---------------------------------------------------------------------------*/
550 void
DemoScene()551 DemoScene()
552 {
553     NW_ASSERT(!s_RenderTargets.empty());
554 
555     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
556 
557     InitializeScenes();
558 
559     // ParticleNodeCombinationDemoの初期化処理です。
560     InitializeParticleNodeCombinationDemo();
561 
562     bool isContinuing = true;
563 
564     while ( isContinuing )
565     {
566         nw::demo::DebugUtility::AdvanceAutoTestFrame();
567 
568         nw::demo::PadFactory::GetPad()->Update();
569 
570 
571         // ParticleNodeCombinationDemoの定期処理です。
572         UpdateParticleNodeCombinationDemo();
573 
574         UpdateScene();
575 
576         renderContext->SetActiveCamera(s_BaseCameraIndex);
577         s_RenderSystem->SubmitView(s_SceneSystem);
578 
579         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
580         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
581 
582         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
583         ReportDemo();
584 
585         // ParticleNodeCombinationDemoのレポートを表示します。
586         ReportParticleNodeCombinationDemo();
587 
588         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
589 
590         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
591 
592         renderContext->ResetState();
593 
594         if (nw::demo::Utility::IsTerminating())
595         {
596             isContinuing = false;
597         }
598     }
599 
600     // ParticleNodeCombinationDemoの終了処理です。
601     TerminateParticleNodeCombinationDemo();
602 
603     TerminateScenes();
604 }
605 
606 } // namespace
607 
608 /*!--------------------------------------------------------------------------*
609   @brief        メイン関数です。
610  *---------------------------------------------------------------------------*/
611 void
nnMain()612 nnMain()
613 {
614     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
615     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
616 
617     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
618 
619     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
620     {
621         InitializeGraphics();
622 
623         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
624 
625         DemoScene();
626 
627         nw::ut::SafeDestroy(s_FlushCache);
628 
629         TerminateGraphics();
630     }
631 
632     nw::demo::PadFactory::Finalize();
633 
634     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
635 
636     nw::demo::FinalizeGraphicsSystem();
637 }
638