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