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