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