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