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