1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: AnimationChangeDemo.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: 22362 $
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
23 #include <nw/demo.h>
24 #include <nw/dev.h>
25 #include <nw/gfx.h>
26 #include <nw/ut.h>
27 #include <nw/anim.h>
28
29 namespace
30 {
31
32 //----------------------------------------
33 // メモリ関係
34
35 // デバイスメモリを確保するためのアロケータです。
36 nw::demo::DemoAllocator s_DeviceAllocator;
37
38 //----------------------------------------
39 // ファイル名の定義です。
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"Male.bcmdl"),
45 NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
46 NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
47 };
48
49 const wchar_t* SKELETAL_ANIM_RESOURCE_FILES[] =
50 {
51 NW_DEMO_FILE_PATH(L"Walk.bcskla"),
52 NW_DEMO_FILE_PATH(L"Run.bcskla")
53 };
54
55 //----------------------------------------
56 // 描画関係
57 const int RENDER_TARGET_COUNT = 1;
58 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
59
60 RenderTargetArray s_RenderTargets;
61 nw::demo::SceneSystem* s_SceneSystem = NULL;
62 nw::demo::RenderSystem* s_RenderSystem = NULL;
63
64 nw::demo::GraphicsDrawing s_GraphicsDrawing;
65
66 //----------------------------------------
67 // リソース関係
68 nw::demo::ResourceArray s_Resources;
69
70 //----------------------------------------
71 // シーン関係
72 const int SCENE_NODE_COUNT = 4;
73 nw::gfx::SceneNode* s_SceneRoot = NULL;
74 nw::gfx::SceneNode* s_ModelRoot = NULL;
75 s32 s_FrameCount = 0;
76 nw::gfx::Camera* s_BaseCamera = NULL;
77 nw::gfx::Camera* s_LeftCamera = NULL;
78 nw::gfx::Camera* s_RightCamera = NULL;
79 const f32 s_fNearPlane = 0.1f;
80
81 //----------------------------------------
82 // シーン環境関係
83 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
84
85 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
86 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
87
88 const s32 s_BaseCameraIndex = 0;
89
90 //----------------------------------------
91 // アニメーション関係
92 nw::gfx::SkeletalModel* s_AnimModel = NULL;
93 nw::gfx::TransformAnimEvaluator* s_AnimEvaluator;
94 nw::anim::res::ResAnim s_ResAnim0;
95 nw::anim::res::ResAnim s_ResAnim1;
96 nw::anim::res::ResAnim s_ResAnimEmpty;
97
98 /*!--------------------------------------------------------------------------*
99 @brief グラフィックス関連の初期化を行います。
100 *---------------------------------------------------------------------------*/
101 void
InitializeGraphics()102 InitializeGraphics()
103 {
104 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
105
106 // renderDescriptionへステレオの設定を行います。
107 nw::demo::RenderSystem::Description renderDescription;
108
109 renderDescription.reusableCommandBufferSize = 0x100000;
110 renderDescription.reusableCommandRequestCount = 512;
111 renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
112
113 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
114
115 s_GraphicsDrawing.SetScreenSize(
116 renderDescription.lowerScreenDescription.width,
117 renderDescription.lowerScreenDescription.height
118 );
119
120 nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
121
122 s_RenderTargets.push_back(
123 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
124 );
125 NW_ASSERT(!s_RenderTargets.empty());
126 s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
127
128 // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
129 nw::demo::SceneSystem::Description sceneDescription;
130 sceneDescription.isFixedSizeMemory = true;
131 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
132
133 // デモ用の最遠景モデルをレンダリングシステムに設定します。
134 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
135 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
136
137 NW_GL_ASSERT();
138 }
139
140 /*!--------------------------------------------------------------------------*
141 @brief グラフィックス関連の後始末をします。
142 *---------------------------------------------------------------------------*/
143 void
TerminateGraphics()144 TerminateGraphics()
145 {
146 nw::gfx::SafeDestroy(s_LeftCamera);
147
148 nw::gfx::SafeDestroy(s_RightCamera);
149
150 nw::gfx::SafeDestroy(s_SceneSystem);
151
152 nw::gfx::SafeDestroyAll(s_RenderTargets);
153
154 s_GraphicsDrawing.Finalize();
155
156 nw::gfx::SafeDestroy(s_RenderSystem);
157
158 NW_GL_ASSERT();
159 }
160
161 /*!--------------------------------------------------------------------------*
162 @brief ファイルからトランスフォームアニメーションリソースを読み込みます。
163
164 @param[in] filePath トランスフォームアニメーションファイルのフルパスです。
165
166 @return トランスフォームアニメーションリソースです。
167 *---------------------------------------------------------------------------*/
168 nw::anim::res::ResAnim
BuildTransformAnimResource(const wchar_t * filePath)169 BuildTransformAnimResource(const wchar_t* filePath)
170 {
171 //----------------------------------------
172 // アニメーションリソースを生成します。
173 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, filePath, &s_DeviceAllocator);
174 if (resourceSet->resource.GetSkeletalAnimsCount() == 0)
175 {
176 return nw::anim::res::ResAnim(NULL);
177 }
178 return resourceSet->resource.GetSkeletalAnims(0);
179 }
180
181 /*!--------------------------------------------------------------------------*
182 @brief ファイルからトランスフォームアニメーション評価を生成します。
183
184 他のデモと違い、アニメーションリソースの読み込みを行いません。
185
186 @param[in] maxBones 最大メンバ数です。
187 @param[in] maxAnimMembers 最大アニメーションメンバ数です。
188 @param[in] translateAnimEnabled 移動アニメーションが有効かどうかです。
189 @param[in] resAnim アニメーションリソースです。
190
191 @return トランスフォームアニメーション評価です。
192 *---------------------------------------------------------------------------*/
193 nw::gfx::TransformAnimEvaluator*
CreateTransformAnimEvaluator(const int maxMembers,const int maxAnimMembers,const bool translateAnimEnabled,nw::anim::res::ResAnim resAnim)194 CreateTransformAnimEvaluator(
195 const int maxMembers,
196 const int maxAnimMembers,
197 const bool translateAnimEnabled,
198 nw::anim::res::ResAnim resAnim
199 )
200 {
201 nw::gfx::TransformAnimEvaluator* evaluator = nw::gfx::TransformAnimEvaluator::Builder()
202 .AnimData(resAnim)
203 .MaxMembers(maxMembers)
204 .MaxAnimMembers(maxAnimMembers)
205 .AllocCache(false)
206 .Create(&s_DeviceAllocator);
207
208 // 移動アニメーションの無効化フラグを設定します。
209 evaluator->SetIsTranslateDisabled(!translateAnimEnabled);
210
211 return evaluator;
212 }
213
214 /*!--------------------------------------------------------------------------*
215 @brief スケルタルアニメーションを初期化します。
216
217 後で切り替えるために、複数のアニメーションリソースを読み込んでおきます。
218 また、空のアニメーションリソースも生成しておき、これに切り替えられるようにします。
219
220 @param[in] model スケルタルモデルです。
221
222 @return トランスフォームアニメーション評価です。
223 *---------------------------------------------------------------------------*/
224 nw::gfx::TransformAnimEvaluator*
InitializeSkeletalAnim(nw::gfx::SkeletalModel * model)225 InitializeSkeletalAnim(nw::gfx::SkeletalModel* model)
226 {
227 nw::gfx::AnimGroup* animGroup = model->GetSkeletalAnimGroup();
228 if (animGroup == NULL)
229 {
230 return NULL;
231 }
232
233 nw::gfx::ResSkeletalModel resModel = model->GetResSkeletalModel();
234 nw::gfx::ResSkeleton resSkeleton = resModel.GetSkeleton();
235 const int maxBones = resSkeleton.GetBonesCount();
236 const bool translateAnimEnabled =
237 nw::ut::CheckFlag(resSkeleton.GetFlags(), nw::gfx::ResSkeletonData::FLAG_TRANSLATE_ANIMATION_ENABLED);
238
239 // アニメーションリソースを読み込みます。
240 s_ResAnim0 = BuildTransformAnimResource(SKELETAL_ANIM_RESOURCE_FILES[0]);
241 s_ResAnim1 = BuildTransformAnimResource(SKELETAL_ANIM_RESOURCE_FILES[1]);
242 NW_ASSERT(s_ResAnim0.IsValid());
243 NW_ASSERT(s_ResAnim1.IsValid());
244
245 // 空のアニメーションリソースを生成します。
246 s_ResAnimEmpty = nw::anim::res::ResAnim::CreateEmptySkeletalAnim(&s_DeviceAllocator);
247
248 // 最大アニメーションメンバ数を所得します。
249 const int maxAnimMembers =
250 nw::ut::Max(s_ResAnim0.GetMemberAnimSetCount(), s_ResAnim1.GetMemberAnimSetCount());
251
252 nw::gfx::TransformAnimEvaluator* evaluator0 = CreateTransformAnimEvaluator(
253 maxBones, maxAnimMembers, translateAnimEnabled, s_ResAnim0);
254 if (evaluator0 == NULL)
255 {
256 return NULL;
257 }
258
259 bool bindResult = evaluator0->Bind(animGroup);
260 model->SetSkeletalAnimObject(evaluator0);
261
262 return evaluator0;
263 }
264
265 /*!--------------------------------------------------------------------------*
266 @brief アニメーション評価のアニメーションリソースを変更します。
267
268 @param[in] model モデルです。
269 *---------------------------------------------------------------------------*/
270 void
ChangeAnimation(nw::gfx::SkeletalModel * model)271 ChangeAnimation(nw::gfx::SkeletalModel* model)
272 {
273 NW_NULL_ASSERT(model);
274
275 nw::gfx::AnimObject* animObject = model->GetSkeletalAnimObject();
276 nw::gfx::TransformAnimEvaluator* evaluator =
277 nw::ut::DynamicCast<nw::gfx::TransformAnimEvaluator*>(animObject);
278 if (evaluator != NULL)
279 {
280 nw::demo::Pad* pad = nw::demo::PadFactory::GetPad();
281
282 // 十字キーの左右でアニメーションを切り替えます。
283 if (pad->IsButtonDown(nw::demo::Pad::BUTTON_LEFT))
284 {
285 evaluator->ChangeAnim(s_ResAnim0);
286 }
287 if (pad->IsButtonDown(nw::demo::Pad::BUTTON_RIGHT))
288 {
289 evaluator->ChangeAnim(s_ResAnim1);
290 }
291
292 // L キーで空アニメーションに切り替えます。
293 if (pad->IsButtonDown(nw::demo::Pad::BUTTON_L))
294 {
295 evaluator->ChangeAnim(s_ResAnimEmpty);
296 }
297
298 // R キーでバインドポーズに戻します。
299 if (pad->IsButtonDown(nw::demo::Pad::BUTTON_R))
300 {
301 evaluator->Reset();
302 }
303 }
304 }
305
306 /*!--------------------------------------------------------------------------*
307 @brief ルートノード関連の構築をします。
308 *---------------------------------------------------------------------------*/
309 void
BuildRootNodes()310 BuildRootNodes()
311 {
312 NW_ASSERT(s_SceneRoot == NULL);
313 s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
314 .Create(&s_DeviceAllocator);
315 NW_NULL_ASSERT(s_SceneRoot);
316
317 NW_ASSERT(s_ModelRoot == NULL);
318 s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
319 .Create(&s_DeviceAllocator);
320 s_SceneRoot->AttachChild(s_ModelRoot);
321 NW_NULL_ASSERT(s_ModelRoot);
322 }
323
324 /*!--------------------------------------------------------------------------*
325 @brief カメラ関連の構築をします。
326 *---------------------------------------------------------------------------*/
327 void
BuildCameras()328 BuildCameras()
329 {
330 nw::demo::Utility::CreateStereoCameras(
331 &s_BaseCamera,
332 &s_LeftCamera,
333 &s_RightCamera,
334 &s_DeviceAllocator,
335 nw::math::VEC3(20.0f, 15.0f, 20.0f),
336 nw::math::VEC3(0.0f, 10.0f, 0.0f),
337 s_fNearPlane
338 );
339
340 s_SceneRoot->AttachChild(s_BaseCamera);
341 s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
342 }
343
344 /*!--------------------------------------------------------------------------*
345 @brief リソース関連の構築をします。
346 *---------------------------------------------------------------------------*/
347 void
BuildResources(nw::demo::ResourceSet * resourceSet)348 BuildResources(nw::demo::ResourceSet* resourceSet)
349 {
350 resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
351 resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
352 resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
353
354 nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
355 if (result.IsFailure())
356 {
357 NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
358 }
359
360 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
361
362 nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
363 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
364 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
365 modelResource != modelsEnd; ++modelResource)
366 {
367 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
368 &s_DeviceAllocator,
369 (*modelResource)
370 );
371 NW_NULL_ASSERT(node);
372 sceneNodeArray.push_back(node);
373 s_AnimModel = nw::ut::DynamicCast<nw::gfx::SkeletalModel*>(node);
374 }
375
376 nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
377 nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
378 for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
379 lightResource != lightsEnd; ++lightResource)
380 {
381 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
382 &s_DeviceAllocator,
383 (*lightResource)
384 );
385 NW_NULL_ASSERT(node);
386 sceneNodeArray.push_back(node);
387 }
388
389 // 親子付け参照関係を解決
390 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
391
392 // モデルをシーンに追加
393 nw::gfx::SceneHelper::ForeachRootNodes(
394 sceneNodeArray.Begin(),
395 sceneNodeArray.End(),
396 nw::gfx::AttachNode(s_ModelRoot)
397 );
398
399 nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
400 nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
401 for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
402 settingResource != settingsEnd; ++settingResource)
403 {
404 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
405 .Resource(*settingResource)
406 .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
407
408 nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
409 nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
410
411 NW_NULL_ASSERT(sceneEnvironmentSetting);
412 s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
413 }
414 }
415
416 /*!--------------------------------------------------------------------------*
417 @brief シーンを初期化します。
418 *---------------------------------------------------------------------------*/
419 void
InitializeScenes()420 InitializeScenes()
421 {
422 BuildRootNodes();
423
424 BuildCameras();
425
426 NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
427 {
428 BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
429 }
430
431 s_AnimEvaluator = InitializeSkeletalAnim(s_AnimModel);
432 NW_NULL_ASSERT(s_AnimEvaluator);
433
434 // シーンツリーを巡回して初期化を行います。
435 s_SceneSystem->InitializeScene(s_SceneRoot);
436 s_SceneSystem->UpdateScene();
437
438 // シーン環境の参照解決を行い設定します。
439 s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
440
441 // カメラを設定します。
442 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
443 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
444 nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
445
446 NW_GL_ASSERT();
447
448 s_FrameCount = 0;
449 }
450
451 /*!--------------------------------------------------------------------------*
452 @brief シーン関連の後始末をします。
453 *---------------------------------------------------------------------------*/
454 void
TerminateScenes()455 TerminateScenes()
456 {
457 nw::gfx::SafeDestroyBranch(s_SceneRoot);
458 nw::demo::SafeCleanupResources(s_Resources);
459 nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
460
461 // 空のアニメーションリソースを破棄します。
462 s_DeviceAllocator.Free(s_ResAnimEmpty.ptr());
463 s_ResAnimEmpty = nw::anim::res::ResAnim(NULL);
464
465 nw::ut::SafeDestroy(s_AnimEvaluator);
466
467 NW_GL_ASSERT();
468
469 s_Resources.clear();
470 s_SceneEnvironmentSettings.clear();
471 s_ModelRoot = NULL;
472 }
473
474 /*!--------------------------------------------------------------------------*
475 @brief シーンを更新します。
476 *---------------------------------------------------------------------------*/
477 void
UpdateScene()478 UpdateScene()
479 {
480 ChangeAnimation(s_AnimModel);
481
482 s_SceneSystem->GetCameraController()->Update();
483
484 s_SceneSystem->UpdateScene();
485
486 s_BaseCamera->UpdateCameraMatrix();
487
488 s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
489
490 ++s_FrameCount;
491 }
492
493 /*!--------------------------------------------------------------------------*
494 @brief 負荷表示やテスト機能の処理をおこないます。
495 *---------------------------------------------------------------------------*/
496 void
ReportDemo()497 ReportDemo()
498 {
499 NW_PROFILE("ReportDemo");
500
501 // 負荷表示からはこれらの負荷は除きます。
502 s_RenderSystem->SuspendLoadMeter();
503
504 nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
505
506 s_GraphicsDrawing.BeginDrawingShape();
507
508 nw::demo::DebugUtility::DrawLoadMeter(
509 s_RenderSystem,
510 &s_GraphicsDrawing
511 );
512
513 s_GraphicsDrawing.EndDrawingShape();
514
515 s_GraphicsDrawing.BeginDrawingString();
516
517 nw::demo::DebugUtility::DrawLoadMeterText(
518 s_RenderSystem,
519 &s_GraphicsDrawing
520 );
521
522 s_GraphicsDrawing.EndDrawingString();
523
524 s_RenderSystem->ResumeLoadMeter();
525 }
526
527 /*!--------------------------------------------------------------------------*
528 @brief シーンをデモンストレーションします。
529 *---------------------------------------------------------------------------*/
530 void
DemoScene()531 DemoScene()
532 {
533 NW_ASSERT(!s_RenderTargets.empty());
534
535 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
536
537 InitializeScenes();
538
539 nw::demo::DebugUtility::PostInitializeScenes();
540
541 NW_LOG("[Animation Change Demo usage]\n");
542 NW_LOG("left/right: change animation\n");
543 NW_LOG("l : change to empty animation\n");
544 NW_LOG("r : reset\n");
545
546 bool isContinuing = true;
547
548 while ( isContinuing )
549 {
550 nw::demo::DebugUtility::AdvanceAutoTestFrame();
551
552 nw::demo::PadFactory::GetPad()->Update();
553
554 UpdateScene();
555
556 renderContext->SetActiveCamera(s_BaseCameraIndex);
557 s_RenderSystem->SubmitView(s_SceneSystem);
558
559 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
560 s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
561
562 s_RenderSystem->ClearBySkyModel(s_BaseCamera);
563 ReportDemo();
564 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
565
566 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
567
568 renderContext->ResetState();
569
570 if (nw::demo::Utility::IsTerminating())
571 {
572 isContinuing = false;
573 }
574 }
575
576 nw::demo::DebugUtility::PreTerminateScenes();
577
578 TerminateScenes();
579 }
580
581 } // namespace
582
583 /*!--------------------------------------------------------------------------*
584 @brief メイン関数です。
585 *---------------------------------------------------------------------------*/
586 void
nnMain()587 nnMain()
588 {
589 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
590
591 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
592
593 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
594 {
595 InitializeGraphics();
596
597 DemoScene();
598
599 TerminateGraphics();
600 }
601
602 nw::demo::PadFactory::Finalize();
603
604 nw::demo::FinalizeGraphicsSystem();
605 }
606