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