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