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