1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: ProjectionShadowDemo.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: 29438 $
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 // シャドウの状態を表す UserFlag です
35 enum UserFlags
36 {
37 SHADOW_CASTER_SHIFT = 0,
38 SHADOW_RECEIVER_SHIFT = 1,
39
40 SHADOW_CASTER = 0x1 << SHADOW_CASTER_SHIFT,
41 SHADOW_RECEIVER = 0x1 << SHADOW_RECEIVER_SHIFT
42 };
43
44 // Shadow の Caster のみを描画要素に加える関数オブジェクトです。
45 class IsShadowCasterModelFunctor : public nw::gfx::ISceneUpdater::IsVisibleModelFunctor
46 {
47 public:
IsVisible(const nw::gfx::Model * model)48 virtual bool IsVisible(const nw::gfx::Model* model)
49 {
50 return nw::ut::CheckFlag(model->GetUserParameter<u32>(), SHADOW_CASTER);
51 }
52 };
53
54 IsShadowCasterModelFunctor s_ShadowCasterModel;
55
56 // シャドウの設定を行うレンダーコマンドです。
57 class StartShadowRenderCommand : public nw::gfx::RenderCommand
58 {
59 NW_DISALLOW_COPY_AND_ASSIGN(StartShadowRenderCommand);
60
61 public:
StartShadowRenderCommand(nw::demo::CommandListSwapper * commandListSwapper,nw::gfx::IRenderTarget * renderTarget,s32 shadowCameraIndex,nw::gfx::Material * shadowMaterial)62 StartShadowRenderCommand(
63 nw::demo::CommandListSwapper* commandListSwapper,
64 nw::gfx::IRenderTarget* renderTarget,
65 s32 shadowCameraIndex,
66 nw::gfx::Material* shadowMaterial)
67 : m_CommandListSwapper(commandListSwapper),
68 m_RenderTarget(renderTarget),
69 m_ShadowCameraIndex(shadowCameraIndex),
70 m_ShadowMaterial(shadowMaterial),
71 m_CommandSize(0),
72 m_ProfilerPoint(0)
73 {}
~StartShadowRenderCommand()74 virtual ~StartShadowRenderCommand() {}
75
Invoke(nw::gfx::RenderContext * renderContext)76 virtual void Invoke(nw::gfx::RenderContext* renderContext)
77 {
78 m_CommandSize = m_CommandListSwapper->GetCommandBufferSize();
79 m_ProfilerPoint = m_CommandListSwapper->AddGpuProfilingStartPoint(true);
80
81 // オフスクリーンバッファに切り替えます。
82 renderContext->SetRenderTarget(m_RenderTarget);
83 renderContext->ClearBuffer(GL_COLOR_BUFFER_BIT, nw::ut::FloatColor(1.0f, 1.0f, 1.0f, 1.0f), 1.0f);
84
85 // シャドウ用のマテリアル、カメラを設定します。
86 renderContext->SetActiveCamera(m_ShadowCameraIndex);
87 renderContext->SetMaterial(m_ShadowMaterial);
88 nw::gfx::Camera* shadowCamera = renderContext->GetActiveCamera();
89 renderContext->SetCameraMatrix(shadowCamera);
90 renderContext->ActivateContext();
91
92 // 1Pass では RENDERMODE_IGNORE_MATERIAL を用いて以降のマテリアル設定を行いません。
93 renderContext->SetRenderMode(nw::gfx::RenderContext::RENDERMODE_IGNORE_MATERIAL);
94 }
95
GetCommandSize() const96 s32 GetCommandSize() const { return this->m_CommandSize; }
GetProfilerPoint() const97 s32 GetProfilerPoint() const { return this->m_ProfilerPoint; }
98
99 private:
100 nw::demo::CommandListSwapper* m_CommandListSwapper;
101 nw::gfx::IRenderTarget* m_RenderTarget;
102 s32 m_ShadowCameraIndex;
103 nw::gfx::Material* m_ShadowMaterial;
104 s32 m_CommandSize;
105 s32 m_ProfilerPoint;
106 };
107
108 // シャドウの後処理を行うレンダーコマンドです。
109 class EndShadowRenderCommand : public nw::gfx::RenderCommand
110 {
111 NW_DISALLOW_COPY_AND_ASSIGN(EndShadowRenderCommand);
112
113 public:
EndShadowRenderCommand(nw::demo::CommandListSwapper * commandListSwapper,StartShadowRenderCommand * startCommand)114 EndShadowRenderCommand(nw::demo::CommandListSwapper* commandListSwapper, StartShadowRenderCommand* startCommand)
115 : m_CommandListSwapper(commandListSwapper),
116 m_StartCommand(startCommand),
117 m_CommandSize(0)
118 {}
~EndShadowRenderCommand()119 virtual ~EndShadowRenderCommand() {}
120
Invoke(nw::gfx::RenderContext * renderContext)121 virtual void Invoke(nw::gfx::RenderContext* renderContext)
122 {
123 // レンダーモードをデフォルトに戻し、マテリアル設定が通常通り行われるようにします。
124 renderContext->SetRenderMode(nw::gfx::RenderContext::RENDERMODE_DEFAULT);
125
126 // 描画キャッシュを破棄するために ResetState を行います。
127 renderContext->ResetState();
128
129 m_CommandSize = m_CommandListSwapper->GetCommandBufferSize();
130 int profilerPoint = m_StartCommand->GetProfilerPoint();
131 m_CommandListSwapper->SetGpuProfilingEndPoint(profilerPoint);
132 }
133
GetCommandSize() const134 s32 GetCommandSize() const { return this->m_CommandSize; }
135
136 private:
137 nw::demo::CommandListSwapper* m_CommandListSwapper;
138 StartShadowRenderCommand* m_StartCommand;
139 s32 m_CommandSize;
140 };
141
142 // 描画開始の設定を行うレンダーコマンドです。
143 class StartRenderCommand : public nw::gfx::RenderCommand
144 {
145 NW_DISALLOW_COPY_AND_ASSIGN(StartRenderCommand);
146
147 public:
StartRenderCommand(nw::demo::RenderSystem * renderSystem,nw::gfx::IRenderTarget * renderTarget,s32 baseCameraIndex)148 StartRenderCommand(nw::demo::RenderSystem* renderSystem, nw::gfx::IRenderTarget* renderTarget, s32 baseCameraIndex)
149 : m_RenderSystem(renderSystem),
150 m_RenderTarget(renderTarget),
151 m_BaseCameraIndex(baseCameraIndex),
152 m_CommandSize(0)
153 {}
154
~StartRenderCommand()155 virtual ~StartRenderCommand() {}
156
Invoke(nw::gfx::RenderContext * renderContext)157 virtual void Invoke(nw::gfx::RenderContext* renderContext)
158 {
159 nw::demo::CommandListSwapper* commandListSwapper = m_RenderSystem->GetCommandListSwapper();
160
161 // 描画対象をオンスクリーンバッファに切り替えます
162 renderContext->SetRenderTarget(m_RenderTarget);
163 // ライト、環境マップなどの計算用カメラを設定します。
164 renderContext->SetActiveCamera(m_BaseCameraIndex);
165
166 // ステレオ表示用コマンドの作成を開始します。作成したコマンドは複数回描画するために再利用されます。
167 commandListSwapper->StartCommandSave();
168
169 m_CommandSize = commandListSwapper->GetCommandBufferSize();
170
171 m_RenderSystem->ClearBySkyModel(renderContext->GetActiveCamera());
172 }
173
GetCommandSize() const174 s32 GetCommandSize() const { return this->m_CommandSize; }
175
176 private:
177 nw::demo::RenderSystem* m_RenderSystem;
178 nw::gfx::IRenderTarget* m_RenderTarget;
179 s32 m_BaseCameraIndex;
180 s32 m_CommandSize;
181 };
182
183 // 描画終了の設定を行うレンダーコマンドです。
184 class EndRenderCommand : public nw::gfx::RenderCommand
185 {
186 NW_DISALLOW_COPY_AND_ASSIGN(EndRenderCommand);
187
188 public:
EndRenderCommand(nw::demo::RenderSystem * renderSystem,nw::gfx::Camera * leftCamera,nw::gfx::Camera * rightCamera,StartRenderCommand * startCommand)189 EndRenderCommand(
190 nw::demo::RenderSystem* renderSystem,
191 nw::gfx::Camera* leftCamera,
192 nw::gfx::Camera* rightCamera,
193 StartRenderCommand* startCommand)
194 : m_RenderSystem(renderSystem),
195 m_LeftCamera(leftCamera),
196 m_RightCamera(rightCamera),
197 m_StartCommand(startCommand)
198 {}
~EndRenderCommand()199 virtual ~EndRenderCommand() {}
200
Invoke(nw::gfx::RenderContext * renderContext)201 virtual void Invoke(nw::gfx::RenderContext* renderContext)
202 {
203 int commandSize = m_RenderSystem->GetCommandListSwapper()->GetCommandBufferSize();
204 m_RenderSystem->AddLoadMeterCommandSize(commandSize - m_StartCommand->GetCommandSize());
205
206 nw::demo::CommandListSwapper* commandListSwapper = m_RenderSystem->GetCommandListSwapper();
207
208 // ステレオ表示用コマンドの作成を終了します。
209 commandListSwapper->EndCommandSave();
210
211 // GPU処理時間計測開始
212 int profilerLeft = commandListSwapper->AddGpuProfilingStartPoint(true);
213
214 // 保存したコマンドを左目用の描画として再利用します。
215 renderContext->SetCameraMatrix(m_LeftCamera);
216 commandListSwapper->ReuseCommand(false);
217
218 // GPU処理時間計測終了
219 commandListSwapper->SetGpuProfilingEndPoint(profilerLeft);
220
221 m_RenderSystem->TransferBuffer(nw::demo::UPPER_SCREEN);
222
223 // GPU処理時間計測開始
224 int profilerRight = commandListSwapper->AddGpuProfilingStartPoint(true);
225
226 // 保存したコマンドを右目用の描画として再利用します。
227 renderContext->SetCameraMatrix(m_RightCamera);
228 commandListSwapper->ReuseCommand(false);
229
230 // GPU処理時間計測終了
231 commandListSwapper->SetGpuProfilingEndPoint(profilerRight);
232
233 m_RenderSystem->TransferBuffer(nw::demo::EXTENSION_SCREEN);
234 }
235 private:
236 nw::demo::RenderSystem* m_RenderSystem;
237 nw::gfx::Camera* m_LeftCamera;
238 nw::gfx::Camera* m_RightCamera;
239 StartRenderCommand* m_StartCommand;
240 };
241
242 enum CameraKind
243 {
244 PERSPECTIVE_CAMERA,
245 FRUSTUM_CAMERA,
246 ORTHO_CAMERA
247 };
248
249 nw::gfx::Camera* s_ShadowCamera = NULL;
250 // シャドウに用いるカメラの種類です。
251 CameraKind s_CameraKind = PERSPECTIVE_CAMERA;
252 // シャドウ用のカメラのパラメータです。
253 const f32 s_OrthoCameraHeight = 32.0f;
254 const f32 s_ShadowNear = 1.0f;
255 const f32 s_ShadowFar = 500.0f;
256
257 StartShadowRenderCommand* s_StartShadowRenderCommand = NULL;
258 EndShadowRenderCommand* s_EndShadowRenderCommand = NULL;
259 StartRenderCommand* s_StartRenderCommand = NULL;
260 EndRenderCommand* s_EndRenderCommand = NULL;
261
262 // シャドウのマテリアル、シェーダー設定用モデルです。
263 // このモデルはマテリアルとシェーダーの設定に利用されます。
264 // 実際には描画されません。
265 nw::gfx::Model* s_ShadowDummyModel = NULL;
266 // シャドウ用のテクスチャです。
267 nw::gfx::ResImageTexture s_ShadowTexture;
268 // シャドウテクスチャのサイズです。
269 const s32 s_ShadowTextureSize = 512;
270 // 影の強度(濃さ)です。
271 const f32 s_ShadowIntensity = 0.2f;
272
273 //----------------------------------------
274 // メモリ関係
275
276 // デバイスメモリを確保するためのアロケータです。
277 nw::demo::DemoAllocator s_DeviceAllocator;
278
279 //----------------------------------------
280 // ファイル名の定義です。
281 const wchar_t* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
282 const wchar_t* FONT_FILE_NAME = NW_DEMO_FILE_PATH(L"Font.bcfnt");
283 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
284
285 const wchar_t* MODEL_RESOURCE_FILES[] =
286 {
287 NW_DEMO_FILE_PATH(L"MaleShadow.bcmdl"),
288 NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
289 NW_DEMO_FILE_PATH(L"SpotLight.bcenv"),
290 NW_DEMO_FILE_PATH(L"AmbientLight.bcenv"),
291 };
292
293 const wchar_t* SKELETAL_ANIM_RESOURCE_FILE = NW_DEMO_FILE_PATH(L"WalkAimAt.bcskla");
294
295 const wchar_t* SHADOW_MATERIAL_FILE_NAME = NW_DEMO_FILE_PATH(L"ShadowModel.bcmdl");
296
297 //----------------------------------------
298 // プロファイル関係
299 const int NW_LOAD_METER_INTERVAL = 60;
300
301 //----------------------------------------
302 // 描画関係
303 const int RENDER_TARGET_COUNT = 2;
304 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
305
306 RenderTargetArray s_RenderTargets;
307 nw::demo::SceneSystem* s_SceneSystem = NULL;
308 nw::demo::RenderSystem* s_RenderSystem = NULL;
309
310 nw::demo::GraphicsDrawing s_GraphicsDrawing;
311
312 //----------------------------------------
313 // リソース関係
314 nw::demo::ResourceArray s_Resources;
315
316 //----------------------------------------
317 // シーン関係
318 nw::gfx::SceneNode* s_SceneRoot = NULL;
319 nw::gfx::SceneNode* s_ModelRoot = NULL;
320 nw::gfx::TransformNode* s_LightRoot = NULL;
321 s32 s_FrameCount = 0;
322 nw::gfx::Camera* s_BaseCamera = NULL;
323 nw::gfx::Camera* s_LeftCamera = NULL;
324 nw::gfx::Camera* s_RightCamera = NULL;
325 nw::gfx::FragmentLight* s_SpotLight = NULL;
326
327 const f32 s_fNearPlane = 0.1f;
328 const f32 s_fFarPlane = 1000.0f;
329
330 //----------------------------------------
331 // シーン環境関係
332 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
333
334 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
335 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
336
337 const s32 s_BaseCameraIndex = 0;
338 const s32 s_ShadowCameraIndex = 1;
339
340 //----------------------------------------
341 // アニメーション関係
342 nw::gfx::SkeletalModel* s_AnimModel = NULL;
343 const int MAX_ANIM_OBJECTS = 8;
344 nw::ut::FixedSizeArray<nw::gfx::AnimObject*, MAX_ANIM_OBJECTS> s_AnimObjects;
345
346 /*!--------------------------------------------------------------------------*
347 @brief グラフィックス関連の初期化を行います。
348 *---------------------------------------------------------------------------*/
349 void
InitializeGraphics()350 InitializeGraphics()
351 {
352 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
353
354 // renderDescriptionへステレオの設定を行います。
355 nw::demo::RenderSystem::Description renderDescription;
356
357 renderDescription.reusableCommandBufferSize = 0x100000;
358 renderDescription.reusableCommandRequestCount = 512;
359 renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
360
361 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
362
363 s_GraphicsDrawing.SetScreenSize(
364 renderDescription.lowerScreenDescription.width,
365 renderDescription.lowerScreenDescription.height
366 );
367
368 bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
369
370 NN_ASSERTMSG(result, "Fail to load Font.");
371
372 s_RenderTargets.push_back(
373 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
374 );
375
376 s_ShadowTexture =
377 nw::gfx::ResImageTexture::DynamicBuilder()
378 .Width(s_ShadowTextureSize)
379 .Height(s_ShadowTextureSize)
380 .MipmapSize(1)
381 .LocationFlag(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP)
382 .Format(nw::gfx::ResPixelBasedTexture::FORMAT_HW_RGBA8)
383 .ExecutingMemoryFill(true)
384 .Create(&s_DeviceAllocator);
385 s_ShadowTexture.Setup(&s_DeviceAllocator, nw::gfx::ResGraphicsFile(NULL));
386
387 // オフスクリーンバッファを作成します。
388 nw::gfx::IRenderTarget* offScreenTarget =
389 nw::gfx::IRenderTarget::CreateOffScreenBuffer(&s_DeviceAllocator, s_ShadowTexture);
390
391 s_RenderTargets.push_back(offScreenTarget);
392
393 NW_ASSERT(!s_RenderTargets.empty());
394 s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets[0]);
395
396 // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
397 nw::demo::SceneSystem::Description sceneDescription;
398 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
399
400 // デモ用の最遠景モデルをレンダリングシステムに設定します。
401 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
402 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
403
404 NW_GL_ASSERT();
405 }
406
407 /*!--------------------------------------------------------------------------*
408 @brief グラフィックス関連の後始末をします。
409 *---------------------------------------------------------------------------*/
410 void
TerminateGraphics()411 TerminateGraphics()
412 {
413 s_ShadowTexture.Cleanup();
414 if (s_ShadowTexture.IsValid())
415 {
416 s_ShadowTexture.DynamicDestroy();
417 }
418
419 nw::gfx::SafeDestroy(s_LeftCamera);
420
421 nw::gfx::SafeDestroy(s_RightCamera);
422
423 nw::gfx::SafeDestroy(s_SceneSystem);
424
425 nw::gfx::SafeDestroyAll(s_RenderTargets);
426
427 s_GraphicsDrawing.Finalize();
428
429 nw::gfx::SafeDestroy(s_RenderSystem);
430
431 NW_GL_ASSERT();
432 }
433
434 /*!--------------------------------------------------------------------------*
435 @brief ファイルからトランスフォームアニメーション評価を生成します。
436
437 @param[in] maxBones 最大メンバ数です。
438 @param[in] translateAnimEnabled 移動アニメーションが有効かどうかです。
439 @param[in] filePath トランスフォームアニメーションファイルのフルパスです。
440
441 @return トランスフォームアニメーション評価です。
442 *---------------------------------------------------------------------------*/
443 nw::gfx::TransformAnimEvaluator*
CreateTransformAnimEvaluator(const int maxMembers,const bool translateAnimEnabled,const wchar_t * filePath)444 CreateTransformAnimEvaluator(
445 const int maxMembers,
446 const bool translateAnimEnabled,
447 const wchar_t* filePath
448 )
449 {
450 //----------------------------------------
451 // アニメーションリソースを生成します。
452 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, filePath, &s_DeviceAllocator);
453 if (resourceSet->resource.GetSkeletalAnimsCount() == 0)
454 {
455 return NULL;
456 }
457 nw::anim::ResAnim resAnim = resourceSet->resource.GetSkeletalAnims(0);
458
459 if (!resAnim.IsValid())
460 {
461 return NULL;
462 }
463
464 //----------------------------------------
465 // トランスフォームアニメーション評価を生成します。
466 //
467 // アニメーションを1つのモデルにのみ適用する場合や、
468 // コマ形式データの場合は、 AllocCache を false にすると処理負荷が下がります。
469 nw::gfx::TransformAnimEvaluator* evaluator = nw::gfx::TransformAnimEvaluator::Builder()
470 .AnimData(resAnim)
471 .MaxMembers(maxMembers)
472 .AllocCache(false)
473 .Create(&s_DeviceAllocator);
474
475 // 移動アニメーションの無効化フラグを設定します。
476 evaluator->SetIsTranslateDisabled(!translateAnimEnabled);
477
478 return evaluator;
479 }
480
481 /*!--------------------------------------------------------------------------*
482 @brief スケルタルアニメーションを初期化します。
483
484 @param[in] model スケルタルモデルです。
485 *---------------------------------------------------------------------------*/
486 void
InitializeSkeletalAnim(nw::gfx::SkeletalModel * model)487 InitializeSkeletalAnim(nw::gfx::SkeletalModel* model)
488 {
489 nw::gfx::AnimGroup* animGroup = model->GetSkeletalAnimGroup();
490 if (animGroup == NULL) // スケルタルアニメーション用のアニメーショングループがありません。
491 {
492 return;
493 }
494
495 nw::gfx::ResSkeletalModel resModel = model->GetResSkeletalModel();
496 nw::gfx::ResSkeleton resSkeleton = resModel.GetSkeleton();
497 const int maxBones = resSkeleton.GetBonesCount();
498 const bool translateAnimEnabled =
499 nw::ut::CheckFlag(resSkeleton.GetFlags(), nw::gfx::ResSkeletonData::FLAG_TRANSLATE_ANIMATION_ENABLED);
500
501 //----------------------------------------
502 // アニメーション評価を生成します。
503 nw::gfx::TransformAnimEvaluator* evaluator = CreateTransformAnimEvaluator(
504 maxBones, translateAnimEnabled, SKELETAL_ANIM_RESOURCE_FILE);
505 if (evaluator == NULL)
506 {
507 return;
508 }
509
510 // アニメーションをバインドします。
511 bool bindResult = evaluator->Bind(animGroup);
512
513 //----------------------------------------
514 // アニメーションをモデルに登録します。
515 model->SetSkeletalAnimObject(evaluator);
516 s_AnimObjects.PushBack(evaluator);
517 }
518
519 /*!--------------------------------------------------------------------------*
520 @brief アニメーションの後始末をします。
521 *---------------------------------------------------------------------------*/
522 void
TerminateAnim(void)523 TerminateAnim(void)
524 {
525 for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx)
526 {
527 nw::gfx::SafeDestroy(s_AnimObjects[animIdx]);
528 }
529 s_AnimObjects.clear();
530 }
531
532 /*!--------------------------------------------------------------------------*
533 @brief ルートノード関連の構築をします。
534 *---------------------------------------------------------------------------*/
535 void
BuildRootNodes()536 BuildRootNodes()
537 {
538 NW_ASSERT(s_SceneRoot == NULL);
539 s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
540 .IsFixedSizeMemory(false)
541 .Create(&s_DeviceAllocator);
542 NW_NULL_ASSERT(s_SceneRoot);
543
544 NW_ASSERT(s_ModelRoot == NULL);
545 s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
546 .IsFixedSizeMemory(false)
547 .Create(&s_DeviceAllocator);
548 s_SceneRoot->AttachChild(s_ModelRoot);
549 NW_NULL_ASSERT(s_ModelRoot);
550
551 NW_ASSERT(s_LightRoot == NULL);
552 s_LightRoot = nw::gfx::TransformNode::DynamicBuilder()
553 .IsFixedSizeMemory(false)
554 .Create(&s_DeviceAllocator);
555 s_SceneRoot->AttachChild(s_LightRoot);
556 NW_NULL_ASSERT(s_LightRoot);
557 }
558
559 /*!--------------------------------------------------------------------------*
560 @brief カメラ関連の構築をします。
561 *---------------------------------------------------------------------------*/
562 void
BuildCameras()563 BuildCameras()
564 {
565 nw::demo::Utility::CreateStereoCameras(
566 &s_BaseCamera,
567 &s_LeftCamera,
568 &s_RightCamera,
569 &s_DeviceAllocator,
570 nw::math::VEC3(20.0f, 15.0f, 20.0f),
571 nw::math::VEC3(0.0f, 10.0f, 0.0f),
572 s_fNearPlane,
573 s_fFarPlane
574 );
575 s_SceneRoot->AttachChild(s_BaseCamera);
576 s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
577
578 // シャドウ用のカメラを作成します。
579 switch (s_CameraKind)
580 {
581 case PERSPECTIVE_CAMERA:
582 {
583 s_ShadowCamera =
584 nw::demo::Utility::CreateCamera(
585 &s_DeviceAllocator,
586 nw::math::VEC3(20.0f, 15.0f, 20.0f),
587 nw::math::VEC3(0.0f, 10.0f, 0.0f),
588 s_ShadowNear,
589 s_ShadowFar,
590 NW_MATH_DEG_TO_RAD(45.0f),
591 nw::math::PIVOT_NONE);
592 }
593 break;
594 case FRUSTUM_CAMERA:
595 {
596 s_ShadowCamera =
597 nw::demo::Utility::CreateFrustumCamera(
598 &s_DeviceAllocator,
599 nw::math::VEC3(20.0f, 15.0f, 20.0f),
600 nw::math::VEC3(0.0f, 10.0f, 0.0f),
601 s_ShadowNear,
602 s_ShadowFar,
603 nw::math::VEC2(0.0f, 0.0f),
604 1.0f,
605 nw::math::PIVOT_NONE);
606 }
607 break;
608 case ORTHO_CAMERA:
609 {
610 s_ShadowCamera =
611 nw::demo::Utility::CreateOrthoCamera(
612 &s_DeviceAllocator,
613 nw::math::VEC3(20.0f, 15.0f, 20.0f),
614 nw::math::VEC3(0.0f, 10.0f, 0.0f),
615 s_ShadowNear,
616 s_ShadowFar,
617 nw::math::VEC2(0.0f, 0.0f),
618 s_OrthoCameraHeight,
619 nw::math::PIVOT_NONE);
620 }
621 break;
622 default:
623 {
624 NW_FATAL_ERROR("Unsupported camera type.");
625 }
626 break;
627 }
628
629 NW_NULL_ASSERT(s_ShadowCamera);
630
631 s_SceneRoot->AttachChild(s_ShadowCamera);
632 }
633
634 /*!--------------------------------------------------------------------------*
635 @brief シャドウ用のテクスチャコンバイナ関連の構築をします。
636 *---------------------------------------------------------------------------*/
637 void
SetupShadowMaterial(nw::gfx::ResMaterial resMaterial)638 SetupShadowMaterial(nw::gfx::ResMaterial resMaterial)
639 {
640 nw::gfx::ResTextureCoordinator resTexCoord = resMaterial.GetTextureCoordinators(0);
641 resTexCoord.SetReferenceCamera(1);
642 nw::gfx::ResPixelBasedTextureMapper resTextureMapper = resMaterial.GetTextureMappers(0);
643 // ダミーのテクスチャをシャドウ用のテクスチャに差し替えます。
644 nw::gfx::ResTexture dummyTexture = resTextureMapper.GetTexture().Dereference();
645 dummyTexture.Cleanup();
646 resTextureMapper.SetTexture(s_ShadowTexture);
647 }
648
649 /*!--------------------------------------------------------------------------*
650 @brief リソース関連の構築をします。
651 *---------------------------------------------------------------------------*/
652 void
BuildResources(nw::demo::ResourceSet * resourceSet)653 BuildResources(nw::demo::ResourceSet* resourceSet)
654 {
655 resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
656 resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
657 resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
658
659 nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
660 if (result.IsFailure())
661 {
662 NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
663 }
664
665 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
666
667 nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
668 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
669 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
670 modelResource != modelsEnd; ++modelResource)
671 {
672 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
673 &s_DeviceAllocator,
674 (*modelResource)
675 );
676
677 // plane の Texture0 にオフスクリーンバッファをテクスチャとしてセットする
678 if (::std::strcmp((*modelResource).GetName(), "Plane") == 0)
679 {
680 nw::gfx::Model* model = nw::ut::DynamicCast<nw::gfx::Model*>(node);
681 NW_ASSERT(model->GetMaterialCount() != 0);
682
683 nw::gfx::Material* material = model->GetMaterial(0);
684 nw::gfx::ResMaterial resMaterial = material->GetOriginal();
685 NW_ASSERT(resMaterial.IsValid());
686 SetupShadowMaterial(resMaterial);
687 }
688 else if (::std::strcmp((*modelResource).GetName(), "Male") == 0)
689 {
690 nw::gfx::SkeletalModel* skeletalModel = nw::ut::DynamicCast<nw::gfx::SkeletalModel*>(node);
691 s_AnimModel = skeletalModel;
692
693 // 影を生成するモデルにフラグを設定します。
694 skeletalModel->SetUserParameter(SHADOW_CASTER);
695 }
696
697 sceneNodeArray.push_back(node);
698 }
699
700 nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
701 nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
702 for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
703 lightResource != lightsEnd; ++lightResource)
704 {
705 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
706 &s_DeviceAllocator,
707 (*lightResource)
708 );
709
710 if (::std::strcmp((*lightResource).GetName(), "SpotLight") == 0)
711 {
712 s_SpotLight = nw::ut::DynamicCast<nw::gfx::FragmentLight*>(node);
713 s_LightRoot->AttachChild(s_SpotLight);
714 }
715
716 sceneNodeArray.push_back(node);
717 }
718
719 // 親子付け参照関係を解決
720 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
721
722 // モデルをシーンに追加
723 nw::gfx::SceneHelper::ForeachRootNodes(
724 sceneNodeArray.Begin(),
725 sceneNodeArray.End(),
726 nw::gfx::AttachNode(s_ModelRoot)
727 );
728
729 nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
730 nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
731 for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
732 settingResource != settingsEnd; ++settingResource)
733 {
734 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
735 .Resource(*settingResource)
736 .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
737
738 nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
739 nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
740
741 NW_NULL_ASSERT(sceneEnvironmentSetting);
742 s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
743 }
744 }
745
746 /*!--------------------------------------------------------------------------*
747 @brief シーンを初期化します。
748 *---------------------------------------------------------------------------*/
749 void
InitializeScenes()750 InitializeScenes()
751 {
752 BuildRootNodes();
753
754 BuildCameras();
755
756 NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
757 {
758 BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
759 }
760
761 if (s_AnimModel != NULL)
762 {
763 InitializeSkeletalAnim(s_AnimModel);
764 }
765
766 // シーンツリーを巡回して初期化を行います。
767 s_SceneSystem->InitializeScene(s_SceneRoot);
768 s_SceneSystem->UpdateScene();
769
770 // シーン環境の参照解決を行い設定します。
771 s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
772
773 // カメラを設定します。
774 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
775 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
776 sceneEnvironment.SetCamera(s_ShadowCameraIndex, s_ShadowCamera);
777 nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
778
779 // シャドウ用のマテリアルとシェーダーを含むモデルを読み込みます。
780 nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, SHADOW_MATERIAL_FILE_NAME, &s_DeviceAllocator);
781 nw::gfx::ResModel resShadowModel = resourceSet->resource.GetModels("ShadowModel");
782 nw::gfx::Result result = resShadowModel.Setup(&s_DeviceAllocator, resourceSet->resource);
783 NW_ASSERT(result.IsSuccess());
784 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
785 &s_DeviceAllocator,
786 resShadowModel
787 );
788 s_ShadowDummyModel = nw::ut::DynamicCast<nw::gfx::Model*>(node);
789 NW_NULL_ASSERT(s_ShadowDummyModel);
790
791 NW_ASSERT(s_ShadowDummyModel->GetMaterialCount() != 0);
792
793 // 影の強度(濃さ)を設定します。
794 nw::gfx::ResMaterialColor materialColor = s_ShadowDummyModel->GetMaterial(0)->GetOriginal().GetMaterialColor();
795 materialColor.SetDiffuse(s_ShadowIntensity, s_ShadowIntensity, s_ShadowIntensity);
796
797 nw::demo::CommandListSwapper* commandListSwapper = s_RenderSystem->GetCommandListSwapper();
798 NW_ASSERT(s_ShadowDummyModel->GetMaterialCount() != 0);
799 nw::gfx::Material* shadowMaterial = s_ShadowDummyModel->GetMaterial(0);
800
801 // レンダーコマンドを作成します。
802 void* startShadowCommandMemory = s_DeviceAllocator.Alloc(sizeof(StartShadowRenderCommand));
803 NW_NULL_ASSERT(startShadowCommandMemory);
804 s_StartShadowRenderCommand = new(startShadowCommandMemory) StartShadowRenderCommand(
805 commandListSwapper,
806 s_RenderTargets[1],
807 s_ShadowCameraIndex,
808 shadowMaterial);
809
810 void* endShadowCommandMemory = s_DeviceAllocator.Alloc(sizeof(EndShadowRenderCommand));
811 NW_NULL_ASSERT(endShadowCommandMemory);
812 s_EndShadowRenderCommand = new(endShadowCommandMemory) EndShadowRenderCommand(commandListSwapper, s_StartShadowRenderCommand);
813
814 void* startCommandMemory = s_DeviceAllocator.Alloc(sizeof(StartRenderCommand));
815 NW_NULL_ASSERT(startCommandMemory);
816 s_StartRenderCommand = new(startCommandMemory) StartRenderCommand(s_RenderSystem, s_RenderTargets[0], s_BaseCameraIndex);
817
818 void* endCommandMemory = s_DeviceAllocator.Alloc(sizeof(EndRenderCommand));
819 NW_NULL_ASSERT(endCommandMemory);
820 s_EndRenderCommand = new(endCommandMemory) EndRenderCommand(s_RenderSystem, s_LeftCamera, s_RightCamera, s_StartRenderCommand);
821
822 NW_GL_ASSERT();
823
824 s_FrameCount = 0;
825 }
826
827 /*!--------------------------------------------------------------------------*
828 @brief シーン関連の後始末をします。
829 *---------------------------------------------------------------------------*/
830 void
TerminateScenes()831 TerminateScenes()
832 {
833 s_DeviceAllocator.Free(s_EndRenderCommand);
834 s_DeviceAllocator.Free(s_StartRenderCommand);
835 s_DeviceAllocator.Free(s_EndShadowRenderCommand);
836 s_DeviceAllocator.Free(s_StartShadowRenderCommand);
837
838 nw::ut::SafeDestroy(s_ShadowDummyModel);
839 nw::gfx::SafeDestroyBranch(s_SceneRoot);
840 nw::demo::SafeCleanupResources(s_Resources);
841 nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
842 TerminateAnim();
843
844 NW_GL_ASSERT();
845
846 s_Resources.clear();
847 s_SceneEnvironmentSettings.clear();
848 s_ModelRoot = NULL;
849 s_LightRoot = NULL;
850 }
851
852 /*!--------------------------------------------------------------------------*
853 @brief シーンを更新します。
854 *---------------------------------------------------------------------------*/
855 void
UpdateScene()856 UpdateScene()
857 {
858 float radian = static_cast<float>((s_FrameCount) % (314 * 2)) * 0.01f;
859
860 // ライトルートがY軸中心に回転します。
861 nw::gfx::TransformNode* lightNode =
862 nw::ut::DynamicCast<nw::gfx::TransformNode*>(s_LightRoot);
863 NW_NULL_ASSERT(lightNode);
864
865 lightNode->Transform().SetRotateXYZ(0.0f, radian, 0.0f);
866
867 s_SceneSystem->GetCameraController()->Update();
868
869 s_SceneSystem->UpdateScene();
870
871 s_BaseCamera->UpdateCameraMatrix();
872
873 s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
874
875 // シャドウの描画をライト方向から行うために、カメラの位置と方向をライトに追従させます。
876 nw::math::VEC3 translate;
877 translate.x = s_SpotLight->WorldMatrix().m[0][3];
878 translate.y = s_SpotLight->WorldMatrix().m[1][3];
879 translate.z = s_SpotLight->WorldMatrix().m[2][3];
880
881 s_ShadowCamera->WorldMatrix().m[0][3] = translate.x;
882 s_ShadowCamera->WorldMatrix().m[1][3] = translate.y;
883 s_ShadowCamera->WorldMatrix().m[2][3] = translate.z;
884
885 const nw::math::VEC3& direction = s_SpotLight->Direction();
886 s_ShadowCamera->SetTargetPosition(translate + direction);
887
888 s_ShadowCamera->UpdateCameraMatrix();
889
890 ++s_FrameCount;
891 }
892
893 /*!--------------------------------------------------------------------------*
894 @brief レンダーキューにレンダーエレメントを追加します。
895 *---------------------------------------------------------------------------*/
896 void
SubmitView()897 SubmitView()
898 {
899 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
900 nw::gfx::SceneEnvironment& sceneEnvironment = renderContext->GetSceneEnvironment();
901 nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
902
903 nw::gfx::RenderQueue* renderQueue = s_RenderSystem->GetRenderQueue();
904
905 renderQueue->Reset();
906
907 // 描画対象とレンダーコマンドをレンダーキューに追加します。
908 // 分かりやすくするために処理される順に Submit or Enqueue を行います。
909
910 // シャドウ用の設定を行うコマンドをレイヤー0の後に実行するコールバックに追加します。
911 s_RenderSystem->EnqueueRenderCommand(
912 s_StartShadowRenderCommand, nw::gfx::ResMaterial::TRANSLUCENCY_KIND_OPAQUE, 0, 0);
913
914 // シャドウキャスターとして指定されたモデルのみを レイヤー1としてレンダーキューに追加します。
915 s_SceneSystem->GetSceneUpdater()->SubmitView(
916 renderQueue,
917 sceneContext,
918 *s_ShadowCamera,
919 1,
920 1,
921 &s_ShadowCasterModel,
922 s_RenderSystem->GetRenderSortMode());
923
924 // シャドウの後処理を行うコマンドをレイヤー1の後に実行するコールバックに追加します。
925 s_RenderSystem->EnqueueRenderCommand(
926 s_EndShadowRenderCommand, nw::gfx::ResMaterial::TRANSLUCENCY_KIND_OPAQUE, 0, 1);
927
928 // ステレオ描画の前処理の設定を行うコマンドをレイヤー1の後に実行するコールバックに追加します。
929 s_RenderSystem->EnqueueRenderCommand(
930 s_StartRenderCommand, nw::gfx::ResMaterial::TRANSLUCENCY_KIND_OPAQUE, 1, 1);
931
932 // シーンコンテキストの全てのモデルをレイヤー2でレンダーキューに追加します。
933 s_SceneSystem->GetSceneUpdater()->SubmitView(
934 renderQueue,
935 sceneContext,
936 *s_BaseCamera,
937 2,
938 s_RenderSystem->GetRenderSortMode());
939
940 // ステレオ描画の後処理の設定を行うコマンドをレイヤー2の後に実行するコールバックに追加します。
941 s_RenderSystem->EnqueueRenderCommand(
942 s_EndRenderCommand, nw::gfx::ResMaterial::TRANSLUCENCY_KIND_OPAQUE, 0, 2);
943
944 std::sort(
945 renderQueue->Begin(),
946 renderQueue->End(),
947 nw::gfx::RenderElementCompare());
948 }
949
950 //----------------------------------------
951 struct RenderSceneInternalFunctor
952 : public std::unary_function<nw::gfx::RenderElement&, void>
953 {
954 nw::gfx::RenderContext* m_RenderContext;
955 nw::gfx::MeshRenderer* m_MeshRenderer;
956
RenderSceneInternalFunctor__anoneac4b5990111::RenderSceneInternalFunctor957 RenderSceneInternalFunctor(nw::gfx::RenderContext* renderContext, nw::gfx::MeshRenderer* meshRenderer)
958 : m_RenderContext(renderContext), m_MeshRenderer(meshRenderer)
959 {
960 NW_NULL_ASSERT(renderContext);
961 NW_NULL_ASSERT(meshRenderer);
962 }
963
operator ()__anoneac4b5990111::RenderSceneInternalFunctor964 void operator()(nw::gfx::RenderElement& element)
965 {
966 if (element.IsCommand())
967 {
968 nw::gfx::RenderCommand* command = element.GetCommand();
969 NW_NULL_ASSERT(command);
970 command->Invoke(this->m_RenderContext);
971 }
972 else
973 {
974 nw::gfx::ResMesh mesh = element.GetMesh();
975 nw::gfx::Model* model = element.GetModel();
976 model->PreRenderSignal()(model, mesh, this->m_RenderContext);
977 this->m_MeshRenderer->RenderMesh(mesh, model);
978 model->PostRenderSignal()(model, mesh, this->m_RenderContext);
979 }
980 NW_GL_ASSERT();
981 }
982 };
983
984 /*!--------------------------------------------------------------------------*
985 @brief レンダーキューに基づいて描画を行います。
986 *---------------------------------------------------------------------------*/
987 void
RenderScene()988 RenderScene()
989 {
990 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
991 nw::gfx::RenderQueue* renderQueue = s_RenderSystem->GetRenderQueue();
992 nw::gfx::MeshRenderer* meshRenderer = s_RenderSystem->GetMeshRenderer();
993
994 std::for_each(
995 renderQueue->Begin(),
996 renderQueue->End(),
997 RenderSceneInternalFunctor(renderContext, meshRenderer));
998
999 NW_GL_ASSERT();
1000 }
1001
1002 /*!--------------------------------------------------------------------------*
1003 @brief 負荷表示やテスト機能の処理をおこないます。
1004 *---------------------------------------------------------------------------*/
1005 void
ReportDemo()1006 ReportDemo()
1007 {
1008 NW_PROFILE("ReportDemo");
1009
1010 // 負荷表示からはこれらの負荷は除きます。
1011 s_RenderSystem->SuspendLoadMeter();
1012
1013 s_RenderSystem->AddLoadMeterCommandSize(
1014 s_EndShadowRenderCommand->GetCommandSize() - s_StartShadowRenderCommand->GetCommandSize());
1015
1016 s_GraphicsDrawing.BeginDrawingString();
1017
1018 nw::demo::DebugUtility::DrawLoadMeter(
1019 s_RenderSystem,
1020 &s_GraphicsDrawing,
1021 (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
1022 );
1023
1024 s_GraphicsDrawing.FlushDrawing();
1025
1026 s_RenderSystem->ResumeLoadMeter();
1027 }
1028
1029 /*!--------------------------------------------------------------------------*
1030 @brief シーンをデモンストレーションします。
1031 *---------------------------------------------------------------------------*/
1032 void
DemoScene()1033 DemoScene()
1034 {
1035 NW_ASSERT(!s_RenderTargets.empty());
1036
1037 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
1038
1039 InitializeScenes();
1040
1041 bool isContinuing = true;
1042
1043 while ( isContinuing )
1044 {
1045 nw::demo::DebugUtility::AdvanceAutoTestFrame();
1046
1047 nw::demo::PadFactory::GetPad()->Update();
1048
1049 UpdateScene();
1050
1051 SubmitView();
1052
1053 RenderScene();
1054
1055 s_RenderSystem->ClearBySkyModel(s_BaseCamera);
1056 ReportDemo();
1057 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
1058
1059 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
1060
1061 renderContext->ResetState();
1062
1063 if (nw::demo::Utility::IsTerminating())
1064 {
1065 isContinuing = false;
1066 }
1067 }
1068
1069 TerminateScenes();
1070 }
1071
1072 } // namespace
1073
1074 /*!--------------------------------------------------------------------------*
1075 @brief メイン関数です。
1076 *---------------------------------------------------------------------------*/
1077 void
nnMain()1078 nnMain()
1079 {
1080 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
1081
1082 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
1083
1084 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
1085 {
1086
1087 InitializeGraphics();
1088
1089 DemoScene();
1090
1091 TerminateGraphics();
1092
1093 }
1094
1095 nw::demo::PadFactory::Finalize();
1096
1097 nw::demo::FinalizeGraphicsSystem();
1098 }
1099