1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: SimpleDemo.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: 28152 $
14 *---------------------------------------------------------------------------*/
15
16 #define NW_DEBUG_CHECK_MEMORY_LEAK
17
18 #include <nn/os.h>
19 #include <nn/fs.h>
20
21 #include <nw/types.h>
22 #include <nw/demo.h>
23 #include <nw/dev.h>
24 #include <nw/gfx.h>
25 #include <nw/ut.h>
26
27 namespace
28 {
29
30 //----------------------------------------
31 // メモリ関係
32
33 // デバイスメモリを確保するためのアロケータです。
34 nw::demo::DemoAllocator s_DeviceAllocator;
35
36 //----------------------------------------
37 // ファイル名の定義です。
38 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
39
40 static const wchar_t* MODEL_RESOURCE_FILES[] =
41 {
42 NW_DEMO_FILE_PATH(L"Cube.bcmdl"),
43 NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
44 NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
45 };
46
47 //----------------------------------------
48 // 描画関係
49 const int RENDER_TARGET_COUNT = 1;
50 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
51
52 RenderTargetArray s_RenderTargets;
53 nw::demo::SceneSystem* s_SceneSystem = NULL;
54 nw::demo::RenderSystem* s_RenderSystem = NULL;
55
56 nw::demo::GraphicsDrawing s_GraphicsDrawing;
57
58 //----------------------------------------
59 // リソース関係
60 nw::demo::ResourceArray s_Resources;
61
62 //----------------------------------------
63 // シーン関係
64 const int SCENE_NODE_COUNT = 4;
65 nw::gfx::SceneNode* s_SceneRoot = NULL;
66 nw::gfx::Camera* s_Camera = NULL;
67 s32 s_FrameCount = 0;
68
69 //----------------------------------------
70 // シーン環境関係
71 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
72
73 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
74 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
75
76 const s32 s_BaseCameraIndex = 0;
77
78 /*!--------------------------------------------------------------------------*
79 @brief グラフィックス関連の初期化を行います。
80 *---------------------------------------------------------------------------*/
81 void
InitializeGraphics()82 InitializeGraphics()
83 {
84 // コマンドキャッシュを動的に確保するためにアロケータを渡します。
85 // gfx のライブラリを使う前に必ずアロケータを設定する必要があります。
86 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
87
88 // デモ用のレンダリングシステムのインスタンスを生成します。
89 // 生成の設定である構造体 renderDescription への標準的な値の設定は
90 // 構造体のコンストラクタで行われています。
91 nw::demo::RenderSystem::Description renderDescription;
92 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
93
94 // デバッグ表示用の GraphicsDrawing を初期化します。
95 s_GraphicsDrawing.SetScreenSize(
96 renderDescription.lowerScreenDescription.width,
97 renderDescription.lowerScreenDescription.height
98 );
99
100 nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
101
102 s_RenderTargets.push_back(
103 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
104 );
105 NW_ASSERT(!s_RenderTargets.empty());
106
107 // デモ用のシーンシステムのインスタンスを生成します。
108 // 生成の設定である構造体 sceneDescription への標準的な値の設定は
109 // 構造体のコンストラクタで行われています。
110 nw::demo::SceneSystem::Description sceneDescription;
111 sceneDescription.isFixedSizeMemory = true;
112 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
113
114 // デモ用の最遠景モデルをレンダリングシステムに設定します。
115 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
116 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
117
118 NW_GL_ASSERT();
119 }
120
121 /*!--------------------------------------------------------------------------*
122 @brief グラフィックス関連の後始末をします。
123 *---------------------------------------------------------------------------*/
124 void
TerminateGraphics()125 TerminateGraphics()
126 {
127 nw::gfx::SafeDestroy(s_SceneSystem);
128
129 nw::gfx::SafeDestroyAll(s_RenderTargets);
130
131 s_GraphicsDrawing.Finalize();
132
133 nw::gfx::SafeDestroy(s_RenderSystem);
134
135 NW_GL_ASSERT();
136 }
137
138 /*!--------------------------------------------------------------------------*
139 @brief ルートノード関連の構築をします。
140 *---------------------------------------------------------------------------*/
141 void
BuildRootNodes()142 BuildRootNodes()
143 {
144 NW_ASSERT(s_SceneRoot == NULL);
145 s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
146 .Create(&s_DeviceAllocator);
147 NW_NULL_ASSERT(s_SceneRoot);
148 }
149
150 /*!--------------------------------------------------------------------------*
151 @brief カメラ関連の構築をします。
152 *---------------------------------------------------------------------------*/
153 void
BuildCameras()154 BuildCameras()
155 {
156 s_Camera = nw::demo::Utility::CreateCamera(
157 &s_DeviceAllocator,
158 nw::math::VEC3(7.0f, 3.5f, -5.0f)
159 );
160 s_SceneRoot->AttachChild(s_Camera);
161 s_SceneSystem->GetCameraController()->Register(s_Camera);
162 }
163
164 /*!--------------------------------------------------------------------------*
165 @brief リソース関連の構築をします。
166 *---------------------------------------------------------------------------*/
167 void
BuildResources(nw::demo::ResourceSet * resourceSet)168 BuildResources(nw::demo::ResourceSet* resourceSet)
169 {
170 // ForeachTexture, ForeachIndexStream, ForeachVertexStream で
171 // ResGraphicsFile 内の ResTexture, ResIndexStream, ResVertexStream に関数オブジェクトを設定します。
172 // 関数オブジェクトは SetLocationFlag でメモリの配置場所を指定します。
173 // ここでは VRAMA と VRAMB にテクスチャと頂点データを配置します。
174 //
175 resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
176 resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
177 resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
178
179 // リソースのセットアップを行います。リソースのセットアップでは以下のような処理を行います。
180 // ・シェーダーやテクスチャの参照解決
181 // ・テクスチャや頂点のVRAM転送
182 // ・マテリアルのコマンド生成
183 //
184 // Setup の戻り値 Result は ResourceResult であり、参照解決エラーなどを返します。
185 // エラーコードが返ってきた場合は引数に必要な ResGraphicsFile を与えて再度 Setup することでエラーを解消できます。
186 // Setup を行ったリソースは Cleanup を呼び出して内部で確保したメモリなどを破棄する必要があります。
187 //
188 nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
189 if (result.IsFailure())
190 {
191 NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
192 }
193
194 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
195
196 // モデルのインスタンスを生成します。
197 nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
198 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
199 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
200 modelResource != modelsEnd; ++modelResource)
201 {
202 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
203 &s_DeviceAllocator,
204 (*modelResource),
205 false
206 );
207 NW_NULL_ASSERT(node);
208 sceneNodeArray.push_back(node);
209 }
210
211 // ライトのインスタンスを生成します。
212 nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
213 nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
214 for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
215 lightResource != lightsEnd; ++lightResource)
216 {
217 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
218 &s_DeviceAllocator,
219 (*lightResource)
220 );
221 NW_NULL_ASSERT(node);
222 sceneNodeArray.push_back(node);
223 }
224
225 // ファイル内に含まれる SceneNode 継承クラスをすべて渡すことで、
226 // ResSceneNode の親子階層を SceneNode で構築します。
227 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
228
229 // SceneNode 継承クラスをシーンルートに追加します。
230 nw::gfx::SceneHelper::ForeachRootNodes(
231 sceneNodeArray.Begin(),
232 sceneNodeArray.End(),
233 nw::gfx::AttachNode(s_SceneRoot)
234 );
235
236 // シーン環境設定のインスタンスを生成します。
237 // シーン環境はライトセット、カメラ、フォグをマテリアルごとに切り替えるために必要となります。
238 // SimpleDemo ではライトセットのみ利用しています。
239 nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
240 nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
241 for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
242 settingResource != settingsEnd; ++settingResource)
243 {
244 nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
245 .Resource(*settingResource)
246 .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
247
248 nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
249 nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
250
251 NW_NULL_ASSERT(sceneEnvironmentSetting);
252 s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
253 }
254 }
255
256 /*!--------------------------------------------------------------------------*
257 @brief シーンを初期化します。
258 *---------------------------------------------------------------------------*/
259 void
InitializeScenes()260 InitializeScenes()
261 {
262 BuildRootNodes();
263
264 BuildCameras();
265
266 // ファイルからモデル、ライト、シーン環境のインスタンスを作成して、シーンルートに追加します。
267 NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
268 {
269 BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
270 }
271
272 // SceneInitializer でマテリアルソートの順序を決定する MaterialId を設定します。
273 // SceneTraverser でシーンノードの収集と直列化をして SceneContext に追加を行います。
274 s_SceneSystem->InitializeScene(s_SceneRoot);
275
276 // カメラ位置を世界座標にするために一度更新しておきます。
277 s_SceneSystem->UpdateScene();
278
279 // シーン環境の参照解決を行い設定します。
280 s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
281
282 // カメラを設定します。
283 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
284 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_Camera);
285 nw::demo::Utility::SetCameraAspectRatio(s_Camera, s_RenderTargets[0]);
286
287 NW_GL_ASSERT();
288
289 s_FrameCount = 0;
290 }
291
292 /*!--------------------------------------------------------------------------*
293 @brief シーン関連の後始末をします。
294 *---------------------------------------------------------------------------*/
295 void
TerminateScenes()296 TerminateScenes()
297 {
298 nw::gfx::SafeDestroyBranch(s_SceneRoot);
299 nw::demo::SafeCleanupResources(s_Resources);
300 nw::gfx::SafeDestroyAll(s_SceneEnvironmentSettings);
301
302 NW_GL_ASSERT();
303
304 s_Resources.clear();
305 s_SceneEnvironmentSettings.clear();
306 }
307
308 /*!--------------------------------------------------------------------------*
309 @brief シーンを更新します。
310 *---------------------------------------------------------------------------*/
311 void
UpdateScene()312 UpdateScene()
313 {
314 s_SceneSystem->GetCameraController()->Update();
315
316 s_SceneSystem->UpdateScene();
317
318 s_Camera->UpdateCameraMatrix();
319
320 ++s_FrameCount;
321 }
322
323 /*!--------------------------------------------------------------------------*
324 @brief 負荷表示やテスト機能の処理をおこないます。
325 *---------------------------------------------------------------------------*/
326 void
ReportDemo()327 ReportDemo()
328 {
329 NW_PROFILE("ReportDemo");
330
331 // 負荷表示からはこれらの負荷は除きます。
332 s_RenderSystem->SuspendLoadMeter();
333
334 nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
335
336 s_GraphicsDrawing.BeginDrawingShape();
337
338 nw::demo::DebugUtility::DrawLoadMeter(
339 s_RenderSystem,
340 &s_GraphicsDrawing
341 );
342
343 s_GraphicsDrawing.EndDrawingShape();
344
345 s_GraphicsDrawing.BeginDrawingString();
346
347 nw::demo::DebugUtility::DrawLoadMeterText(
348 s_RenderSystem,
349 &s_GraphicsDrawing
350 );
351
352 s_GraphicsDrawing.EndDrawingString();
353
354 s_RenderSystem->ResumeLoadMeter();
355 }
356
357 /*!--------------------------------------------------------------------------*
358 @brief シーンをデモンストレーションします。
359 *---------------------------------------------------------------------------*/
360 void
DemoScene()361 DemoScene()
362 {
363 NW_ASSERT(!s_RenderTargets.empty());
364
365 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
366
367 InitializeScenes();
368
369 nw::demo::DebugUtility::PostInitializeScenes();
370
371 bool isContinuing = true;
372
373 while ( isContinuing )
374 {
375 // テスト用フレームワークの更新を行います。
376 nw::demo::DebugUtility::AdvanceAutoTestFrame();
377
378 // パッドの更新を行います。
379 nw::demo::PadFactory::GetPad()->Update();
380
381 // ここでの処理順序については
382 // ドキュメント『処理フロー』の『グラフィックス描画シーケンス』を参照してください。
383
384 // アニメーション、ノード、スケルトン、カメラの更新処理を行います。
385 UpdateScene();
386
387 // ライト、環境マップ、WScale 用のカメラを設定します。
388 // ActiveCamera は RenderContext::ResetState でリセットされますので、
389 // 毎フレーム描画前に設定を行う必要があります。
390 renderContext->SetActiveCamera(s_BaseCameraIndex);
391
392 // 視点に依存する更新処理と RenderQueue の構築を行います。
393 s_RenderSystem->SubmitView(s_SceneSystem);
394
395 // 上画面を描画します。
396 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
397 s_RenderSystem->RenderScene(s_Camera, nw::demo::UPPER_SCREEN);
398
399 // 下画面をクリアします。
400 s_RenderSystem->ClearBySkyModel(s_Camera);
401
402 // 下画面にフォントで描画します。
403 ReportDemo();
404 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
405
406 // 描画されたバッファを表示します。
407 // PresentBuffer 関数は内部でVSync待ちやコマンドリストの処理を行っています。
408 // 詳しくは PresentBuffer 関数を参照してください。
409 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN);
410
411 // gfx ライブラリでの描画後に ResetState を呼び出すことで描画に用いたステートをリセットします。
412 renderContext->ResetState();
413
414 if (nw::demo::Utility::IsTerminating())
415 {
416 isContinuing = false;
417 }
418 }
419
420 nw::demo::DebugUtility::PreTerminateScenes();
421
422 TerminateScenes();
423 }
424
425 } // namespace
426
427 /*!--------------------------------------------------------------------------*
428 @brief メイン関数です。
429 *---------------------------------------------------------------------------*/
430 void
nnMain()431 nnMain()
432 {
433 // SDKとデバイスメモリの初期化処理を行います。
434 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
435
436 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
437
438 // NW_DEMO_TEST_LOOP はプロファイラなどの初期化を行うマクロです。
439 // NW_DEBUG_CHECK_MEMORY_LEAK マクロが有効であれば、メモリリークチェックが有効になり、以下のブロックはループになります。
440 // このとき、パッドの START ボタンを押すと nw::demo::Utility::IsTerminating() が true になるため、
441 // DemoScene() 内のループから抜けます。
442 // そして以下のループが繰り返されるときにメモリリークのチェックを行います。
443 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
444 {
445 InitializeGraphics();
446
447 DemoScene();
448
449 TerminateGraphics();
450 }
451
452 nw::demo::PadFactory::Finalize();
453
454 // デバイスメモリの終了処理を行います。
455 nw::demo::FinalizeGraphicsSystem();
456 }
457