1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     SceneTreeDemo.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: 25401 $
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 
36 //----------------------------------------
37 // ファイル名の定義です。
38 const wchar_t* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
39 const wchar_t* FONT_FILE_NAME        = NW_DEMO_FILE_PATH(L"Font.bcfnt");
40 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
41 
42 const wchar_t* MODEL_RESOURCE_FILES[] =
43 {
44     NW_DEMO_FILE_PATH(L"SceneTree.bcmdl"),
45 };
46 
47 //----------------------------------------
48 // プロファイル関係
49 const int NW_LOAD_METER_INTERVAL = 60;
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 
60 static nw::demo::GraphicsDrawing  s_GraphicsDrawing;
61 //----------------------------------------
62 // リソース関係
63 nw::demo::ResourceArray s_Resources;
64 
65 //----------------------------------------
66 // シーン関係
67 nw::gfx::TransformNode* s_SceneRoot = NULL;
68 nw::gfx::TransformNode* s_ModelRoot = NULL;
69 nw::gfx::TransformNode* s_CameraRoot = NULL;
70 nw::gfx::TransformNode* s_LightRoot = NULL;
71 nw::gfx::TransformNode* s_FogRoot = NULL;
72 s32 s_FrameCount = 0;
73 nw::gfx::Camera* s_BaseCamera = NULL;
74 nw::gfx::Camera* s_LeftCamera = NULL;
75 nw::gfx::Camera* s_RightCamera = NULL;
76 const f32 s_fNearPlane = 0.1f;
77 
78 const s32 s_BaseCameraIndex = 0;
79 
80 /*!--------------------------------------------------------------------------*
81   @brief        グラフィックス関連の初期化を行います。
82  *---------------------------------------------------------------------------*/
83 void
InitializeGraphics()84 InitializeGraphics()
85 {
86     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
87 
88     // renderDescriptionへステレオの設定を行います。
89     nw::demo::RenderSystem::Description renderDescription;
90 
91     renderDescription.reusableCommandBufferSize = 0x100000;
92     renderDescription.reusableCommandRequestCount      = 512;
93     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
94 
95     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
96 
97     s_GraphicsDrawing.SetScreenSize(
98         renderDescription.lowerScreenDescription.width,
99         renderDescription.lowerScreenDescription.height
100     );
101 
102     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
103 
104     NN_ASSERTMSG(result, "Fail to load Font.");
105 
106     s_RenderTargets.push_back(
107         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
108     );
109     NW_ASSERT(!s_RenderTargets.empty());
110     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
111 
112     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
113     nw::demo::SceneSystem::Description sceneDescription;
114     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
115 
116     // デモ用の最遠景モデルをレンダリングシステムに設定します。
117     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
118     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
119 
120     NW_GL_ASSERT();
121 }
122 
123 /*!--------------------------------------------------------------------------*
124   @brief        グラフィックス関連の後始末をします。
125  *---------------------------------------------------------------------------*/
126 void
TerminateGraphics()127 TerminateGraphics()
128 {
129     nw::gfx::SafeDestroy(s_LeftCamera);
130 
131     nw::gfx::SafeDestroy(s_RightCamera);
132 
133     nw::gfx::SafeDestroy(s_SceneSystem);
134 
135     nw::gfx::SafeDestroyAll(s_RenderTargets);
136 
137     s_GraphicsDrawing.Finalize();
138 
139     nw::gfx::SafeDestroy(s_RenderSystem);
140 
141     NW_GL_ASSERT();
142 }
143 
144 /*!--------------------------------------------------------------------------*
145   @brief        ルートノード関連の構築をします。
146  *---------------------------------------------------------------------------*/
147 void
BuildRootNodes()148 BuildRootNodes()
149 {
150     NW_ASSERT(s_SceneRoot == NULL);
151     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
152         .IsFixedSizeMemory(false)
153         .Create(&s_DeviceAllocator);
154     NW_NULL_ASSERT(s_SceneRoot);
155 
156     NW_ASSERT(s_ModelRoot == NULL);
157     s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
158         .IsFixedSizeMemory(false)
159         .Create(&s_DeviceAllocator);
160     s_SceneRoot->AttachChild(s_ModelRoot);
161     NW_NULL_ASSERT(s_ModelRoot);
162 
163     NW_ASSERT(s_CameraRoot == NULL);
164     s_CameraRoot = nw::gfx::TransformNode::DynamicBuilder()
165         .IsFixedSizeMemory(false)
166         .Create(&s_DeviceAllocator);
167     s_SceneRoot->AttachChild(s_CameraRoot);
168     NW_NULL_ASSERT(s_CameraRoot);
169 
170     NW_ASSERT(s_LightRoot == NULL);
171     s_LightRoot = nw::gfx::TransformNode::DynamicBuilder()
172         .IsFixedSizeMemory(false)
173         .Create(&s_DeviceAllocator);
174     s_SceneRoot->AttachChild(s_LightRoot);
175     NW_NULL_ASSERT(s_LightRoot);
176 
177     NW_ASSERT(s_FogRoot == NULL);
178     s_FogRoot = nw::gfx::TransformNode::DynamicBuilder()
179         .IsFixedSizeMemory(false)
180         .Create(&s_DeviceAllocator);
181     s_SceneRoot->AttachChild(s_FogRoot);
182     NW_NULL_ASSERT(s_FogRoot);
183 
184     // テスト用にノードを生成して追加します。
185     s_SceneRoot->AttachChild(nw::gfx::SceneNode::DynamicBuilder()
186         .MaxChildren(4)
187         .Create(&s_DeviceAllocator));
188 }
189 
190 /*!--------------------------------------------------------------------------*
191   @brief        カメラ関連の構築をします。
192  *---------------------------------------------------------------------------*/
193 void
BuildCameras()194 BuildCameras()
195 {
196     // シーンツリーを構築します。
197     // カメラを生成します。
198     // カメラルートはシーンルートの子ノードになり親のトランスフォームの影響を受けます。
199 
200     nw::demo::Utility::CreateStereoCameras(
201         &s_BaseCamera,
202         &s_LeftCamera,
203         &s_RightCamera,
204         &s_DeviceAllocator,
205         nw::math::VEC3(45.0f, 30.0f, 45.0f),
206         nw::math::VEC3(-45.0f, -15.0f, -45.0f),
207         s_fNearPlane
208     );
209 
210     // ビューアップデータがカメラのトランスフォームの影響を受けるようにします。
211     nw::gfx::ResCameraViewUpdater resViewUpdater = s_BaseCamera->GetViewUpdater()->GetResource();
212     nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater =
213         nw::gfx::ResDynamicCast<nw::gfx::ResLookAtTargetViewUpdater>(resViewUpdater);
214     resLookAtTargetViewUpdater.SetFlags(
215         nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_ROTATE |
216         nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_TRANSLATE |
217         nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_UP_ROTATE);
218 
219     s_CameraRoot->AttachChild(s_BaseCamera);
220     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
221 }
222 
223 /*!--------------------------------------------------------------------------*
224   @brief        ライト関連の構築をします。
225  *---------------------------------------------------------------------------*/
226 void
BuildLights()227 BuildLights()
228 {
229     // ライトを生成します。
230     nw::gfx::AmbientLight* ambientLight = nw::gfx::AmbientLight::DynamicBuilder()
231         .MaxCallbacks(0)
232         .MaxChildren(0)
233         .Create(&s_DeviceAllocator);
234     s_LightRoot->AttachChild(ambientLight);
235 
236     nw::gfx::ResAmbientLight resAmbientLight(ambientLight->GetResAmbientLight());
237     resAmbientLight.SetAmbient(0.2f, 0.2f, 0.2f);
238 
239     nw::gfx::HemiSphereLight* hemiSphereLight = nw::gfx::HemiSphereLight::DynamicBuilder()
240         .MaxCallbacks(0)
241         .MaxChildren(0)
242         .Create(&s_DeviceAllocator);
243     s_LightRoot->AttachChild(hemiSphereLight);
244 
245     nw::gfx::ResHemiSphereLight resHemiSphereLight(hemiSphereLight->GetResHemiSphereLight());
246     resHemiSphereLight.SetSkyColor(0.9f, 0.9f, 1.0f);
247     resHemiSphereLight.SetGroundColor(0.1f, 0.0f, 0.0f);
248     resHemiSphereLight.SetDirection(0.0f, 1.0f, 0.0f);
249     resHemiSphereLight.SetLerpFactor(0.5f);
250 
251     nw::gfx::VertexLight* vertexLight = nw::gfx::VertexLight::DynamicBuilder()
252         .MaxCallbacks(0)
253         .MaxChildren(0)
254         .Create(&s_DeviceAllocator);
255     s_LightRoot->AttachChild(vertexLight);
256 
257     nw::gfx::ResVertexLight resVertexLight(vertexLight->GetResVertexLight());
258     resVertexLight.SetLightKind(nw::gfx::ResVertexLight::KIND_SPOT);
259     resVertexLight.GetTransform().translate.Set(0.0f, 15.0f, 5.0f);
260     resVertexLight.SetAmbient(0.2f, 0.2f, 0.2f);
261     resVertexLight.SetDiffuse(1.0f, 1.0f, 1.0f);
262     resVertexLight.SetDistanceAttenuation(0.01f, 0.001f, 0.0001f);
263     resVertexLight.SetDistanceAttenuationEnabled(true);
264     resVertexLight.SetSpotFactor(1.0f, NW_MATH_DEG_TO_RAD(90.0f));
265     nw::math::VEC3 vertexLightDirection(0.0f, 0.0f, -1.0f);
266     vertexLightDirection.Normalize();
267     resVertexLight.SetDirection(vertexLightDirection);
268 
269     nw::gfx::FragmentLight* fragmentLight = nw::gfx::FragmentLight::DynamicBuilder()
270         .MaxCallbacks(0)
271         .MaxChildren(0)
272         .Create(&s_DeviceAllocator);
273     s_LightRoot->AttachChild(fragmentLight);
274 
275     nw::gfx::ResFragmentLight resFragmentLight(fragmentLight->GetResFragmentLight());
276     resFragmentLight.SetLightKind(nw::gfx::ResFragmentLight::KIND_DIRECTIONAL);
277     nw::math::VEC3 fragmentLightDirection(-0.5f, -1.0f, -0.5f);
278     fragmentLightDirection.Normalize();
279     resFragmentLight.SetDirection(fragmentLightDirection);
280     resFragmentLight.SetAmbient(0.2f, 0.2f, 0.2f);
281     resFragmentLight.SetDiffuse(1.0f, 1.0f, 1.0f);
282     resFragmentLight.SetSpecular0(0.8f, 0.8f, 0.8f);
283     resFragmentLight.SetSpecular1(0.8f, 0.8f, 0.8f);
284 }
285 
286 /*!--------------------------------------------------------------------------*
287   @brief        フォグ関連の構築をします。
288  *---------------------------------------------------------------------------*/
289 void
BuildFogs()290 BuildFogs()
291 {
292     // フォグを生成します。
293     nw::gfx::Fog* fog = nw::gfx::Fog::DynamicBuilder()
294         .MaxCallbacks(0)
295         .MaxChildren(0)
296         .Create(&s_DeviceAllocator);
297     s_FogRoot->AttachChild(fog);
298 
299     nw::gfx::ResFog resFog(fog->GetResFog());
300 
301     resFog.SetColor(0.3f, 0.3f, 0.5f);
302 
303     nw::gfx::ResFogUpdater resFogUpdater = resFog.GetFogUpdater();
304     resFogUpdater.SetFogUpdaterType(nw::gfx::ResFogUpdater::FOG_UPDATER_TYPE_EXPONENT_SQUARE);
305     resFogUpdater.SetDensity(10.0f);
306     resFogUpdater.SetMinFogDepth(10.0f);
307     resFogUpdater.SetMaxFogDepth(500.0f);
308 }
309 
310 /*!--------------------------------------------------------------------------*
311   @brief        リソース関連の構築をします。
312  *---------------------------------------------------------------------------*/
313 void
BuildResources(nw::demo::ResourceSet * resourceSet)314 BuildResources(nw::demo::ResourceSet* resourceSet)
315 {
316     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
317     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
318     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
319 
320     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
321 
322     if (result.IsFailure())
323     {
324         NW_FATAL_ERROR("Fail to set up model. A result code is %x", result.GetCode());
325     }
326 
327     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
328 
329     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
330     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
331     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
332          modelResource != modelsEnd; ++modelResource)
333     {
334         // マテリアルバッファを利用します。
335         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
336             &s_DeviceAllocator,
337             (*modelResource),
338             false,
339             nw::gfx::Model::MULTI_FLAG_BUFFER_MATERIAL
340         );
341         NW_NULL_ASSERT(node);
342         sceneNodeArray.push_back(node);
343 
344         if (nw::ut::IsTypeOf<nw::gfx::SkeletalModel>(node))
345         {
346             nw::gfx::SkeletalModel* skeletalModel = static_cast<nw::gfx::SkeletalModel*>(node);
347             nw::gfx::Skeleton* skeleton = skeletalModel->GetSkeleton();
348             NW_NULL_ASSERT(skeleton);
349 
350             nw::gfx::ResSkeleton resSkeleton = skeleton->GetResSkeleton();
351             NW_ASSERT(resSkeleton.IsValid());
352         }
353 
354     }
355 
356     // モデルをシーンに追加
357     nw::gfx::SceneHelper::ForeachRootNodes(
358         sceneNodeArray.Begin(),
359         sceneNodeArray.End(),
360         nw::gfx::AttachNode(s_ModelRoot)
361     );
362 }
363 
364 /*!--------------------------------------------------------------------------*
365   @brief        シーンを初期化します。
366  *---------------------------------------------------------------------------*/
367 void
InitializeScenes()368 InitializeScenes()
369 {
370     BuildRootNodes();
371 
372     BuildCameras();
373 
374     BuildLights();
375 
376     BuildFogs();
377 
378     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
379     {
380         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
381     }
382 
383     // シーンツリーを巡回して初期化を行います。
384     s_SceneSystem->InitializeScene(s_SceneRoot);
385     s_SceneSystem->UpdateScene();
386 
387     // カメラを設定します。
388     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
389     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
390     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
391 
392     NW_GL_ASSERT();
393 
394     s_FrameCount = 0;
395 }
396 
397 /*!--------------------------------------------------------------------------*
398   @brief        シーン関連の後始末をします。
399  *---------------------------------------------------------------------------*/
400 void
TerminateScenes()401 TerminateScenes()
402 {
403     nw::gfx::SafeDestroyBranch(s_SceneRoot);
404     nw::demo::SafeCleanupResources(s_Resources);
405 
406     NW_GL_ASSERT();
407 
408     s_Resources.clear();
409     s_ModelRoot = NULL;
410     s_CameraRoot = NULL;
411     s_LightRoot = NULL;
412     s_FogRoot = NULL;
413 }
414 
415 /*!--------------------------------------------------------------------------*
416   @brief        シーンを更新します。
417  *---------------------------------------------------------------------------*/
418 void
UpdateScene()419 UpdateScene()
420 {
421     float radian = static_cast<float>((s_FrameCount * 5) % (314 * 2)) * 0.01f;
422 
423     // カメラルートがY軸中心に回転します。
424     nw::gfx::TransformNode* cameraNode =
425         nw::ut::DynamicCast<nw::gfx::TransformNode*>(s_CameraRoot);
426     NW_NULL_ASSERT(cameraNode);
427 
428     cameraNode->Transform().SetRotateXYZ(0.0f, radian, 0.0f);
429 
430     // モデルルートがY軸に沿って上下します。
431     nw::gfx::TransformNode* modelNode =
432         nw::ut::DynamicCast<nw::gfx::TransformNode*>(s_ModelRoot);
433     NW_NULL_ASSERT(modelNode);
434 
435     modelNode->Transform().SetTranslate(0.0f, nw::math::SinRad(radian) * 10.0f, 0.0f);
436 
437     nw::gfx::SceneNodeArray::iterator end = modelNode->GetChildEnd();
438     for (nw::gfx::SceneNodeArray::iterator node = modelNode->GetChildBegin(); node != end; ++node)
439     {
440         // Model クラスの Transform を変更します。
441         if (nw::ut::IsTypeOf<nw::gfx::Model>(*node))
442         {
443             nw::gfx::Model* model = static_cast<nw::gfx::Model*>(*node);
444             model->Transform().SetScale(radian, radian, radian);
445             model->Transform().SetRotateXYZ(radian, 0.0f, 0.0f);
446         }
447     }
448 
449     s_SceneSystem->GetCameraController()->Update();
450 
451     s_SceneSystem->UpdateScene();
452 
453     s_BaseCamera->UpdateCameraMatrix();
454 
455     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
456 
457     ++s_FrameCount;
458 }
459 
460 /*!--------------------------------------------------------------------------*
461   @brief        負荷表示やテスト機能の処理をおこないます。
462  *---------------------------------------------------------------------------*/
463 void
ReportDemo()464 ReportDemo()
465 {
466     NW_PROFILE("ReportDemo");
467 
468     // 負荷表示からはこれらの負荷は除きます。
469     s_RenderSystem->SuspendLoadMeter();
470 
471     s_GraphicsDrawing.BeginDrawingString();
472 
473     nw::demo::DebugUtility::DrawLoadMeter(
474         s_RenderSystem,
475         &s_GraphicsDrawing,
476         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
477     );
478 
479     s_GraphicsDrawing.FlushDrawing();
480 
481     s_RenderSystem->ResumeLoadMeter();
482 }
483 
484 /*!--------------------------------------------------------------------------*
485   @brief        シーンをデモンストレーションします。
486  *---------------------------------------------------------------------------*/
487 void
DemoScene()488 DemoScene()
489 {
490     NW_ASSERT(!s_RenderTargets.empty());
491 
492     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
493 
494     InitializeScenes();
495 
496     bool isContinuing = true;
497 
498     while ( isContinuing )
499     {
500         nw::demo::DebugUtility::AdvanceAutoTestFrame();
501 
502         nw::demo::PadFactory::GetPad()->Update();
503 
504         UpdateScene();
505 
506         // SceneTreeDemo は SceneEnvironmentSetting を読み込まず
507         // SceneEnvironment に直接ライト、フォグを設定しています。
508         s_RenderSystem->SetEnvironment(s_SceneSystem);
509 
510         renderContext->SetActiveCamera(s_BaseCameraIndex);
511         s_RenderSystem->SubmitView(s_SceneSystem);
512 
513         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
514         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
515 
516         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
517         ReportDemo();
518         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
519 
520         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
521 
522         renderContext->ResetState();
523 
524         if (nw::demo::Utility::IsTerminating())
525         {
526             isContinuing = false;
527         }
528     }
529 
530     TerminateScenes();
531 }
532 
533 } // namespace
534 
535 /*!--------------------------------------------------------------------------*
536   @brief        メイン関数です。
537  *---------------------------------------------------------------------------*/
538 void
nnMain()539 nnMain()
540 {
541     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
542 
543     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
544 
545     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
546     {
547         InitializeGraphics();
548 
549         DemoScene();
550 
551         TerminateGraphics();
552     }
553 
554     nw::demo::PadFactory::Finalize();
555 
556     nw::demo::FinalizeGraphicsSystem();
557 }
558