1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     UserRenderNodeDemo.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: $
16  *---------------------------------------------------------------------------*/
17 
18 #define NW_DEBUG_CHECK_MEMORY_LEAK
19 
20 #include <nn/os.h>
21 #include <nn/fs.h>
22 
23 #include <nn/gr.h>
24 
25 #include <nw/types.h>
26 #include <nw/demo.h>
27 #include <nw/dev.h>
28 #include <nw/gfx.h>
29 #include <nw/ut.h>
30 
31 #include "GrRenderer.h"
32 
33 namespace
34 {
35 
36 class GrUserRenderCommand;
37 
38 //----------------------------------------
39 // メモリ関係
40 
41 // デバイスメモリを確保するためのアロケータです。
42 nw::demo::DemoAllocator s_DeviceAllocator;
43 
44 //----------------------------------------
45 // ファイル名の定義です。
46 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
47 
48 const wchar_t* MODEL_RESOURCE_FILES[] =
49 {
50     NW_DEMO_FILE_PATH(L"Male.bcmdl"),
51     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
52     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv")
53 };
54 
55 const wchar_t* GR_SHADER_FILE = NW_DEMO_FILE_PATH(L"UserRenderCommandShader.shbin");
56 
57 //----------------------------------------
58 // 描画関係
59 const int RENDER_TARGET_COUNT = 1;
60 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
61 
62 RenderTargetArray s_RenderTargets;
63 nw::demo::SceneSystem*  s_SceneSystem = NULL;
64 nw::demo::RenderSystem* s_RenderSystem = NULL;
65 
66 static nw::demo::GraphicsDrawing  s_GraphicsDrawing;
67 
68 //----------------------------------------
69 // リソース関係
70 nw::demo::ResourceArray s_Resources;
71 
72 //----------------------------------------
73 // シーン関係
74 const int SCENE_NODE_COUNT = 8;
75 nw::gfx::SceneNode* s_SceneRoot = NULL;
76 s32 s_FrameCount = 0;
77 nw::gfx::Camera* s_BaseCamera = NULL;
78 nw::gfx::Camera* s_LeftCamera = NULL;
79 nw::gfx::Camera* s_RightCamera = NULL;
80 
81 const s32 s_BaseCameraIndex = 0;
82 
83 //----------------------------------------
84 // シーン環境関係
85 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
86 
87 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
88 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
89 
90 //----------------------------------------
91 // ユーザ定義の描画ノードによる描画関係
92 nw::gfx::UserRenderNode* s_UserRenderNode = NULL;
93 GrUserRenderCommand*     s_GrUserRenderCommand = NULL;
94 GrPrimitiveRenderer s_GrPrimitiveRenderer;
95 
96 /*!--------------------------------------------------------------------------*
97   @brief        GR で描画するためののレンダーコマンドです。
98  *---------------------------------------------------------------------------*/
99 class GrUserRenderCommand : public nw::gfx::UserRenderCommand
100 {
101 public:
102     //! @brief コマンドを呼び出します。
Invoke(nw::gfx::RenderContext * renderContext)103     virtual void Invoke(nw::gfx::RenderContext* renderContext)
104     {
105         // UserRenderCommand が設定されている UserRenderNode を取得
106         nw::gfx::UserRenderNode* userRenderNode = GetUserRenderNode();
107         NW_NULL_ASSERT( userRenderNode );
108 
109         nw::math::MTX34& worldMatrix = userRenderNode->WorldMatrix();
110 
111         // 描画コマンドバッファのポインタを取得
112         u32* command = NULL;
113         nngxGetCmdlistParameteri(
114             NN_GX_CMDLIST_CURRENT_BUFADDR,
115             reinterpret_cast<GLint*>(&command));
116 
117         // 最後にポインタを進めるため、現在のコマンドリストの先頭アドレスを保存
118         const u32* start_addr = command;
119 
120         command = s_GrPrimitiveRenderer.MakeSceneBeginCommand(command);
121 
122         command = s_GrPrimitiveRenderer.MakeDrawBoxCommand(command, worldMatrix);
123 
124         command = s_GrPrimitiveRenderer.MakeSceneEndCommand(command);
125 
126         // コマンドリストのポインタを進める
127         nngxMoveCommandbufferPointer((command - start_addr) * sizeof(u32));
128 
129         // GR で描画するためにシェーダーを切り替えているので、
130         // レンダーコンテキストをリセットする。
131         renderContext->ResetState(
132             nw::gfx::RenderContext::RESETSTATEMODE_SHADER_PROGRAM |
133             nw::gfx::RenderContext::RESETSTATEMODE_MATERIAL_CACHE
134             ,0);
135 
136     }
137 
138 public:
139     //! コンストラクタです。
GrUserRenderCommand()140     GrUserRenderCommand(){}
141 
142     //! デストラクタです。
~GrUserRenderCommand()143     virtual ~GrUserRenderCommand() {}
144 };
145 
146 /*!--------------------------------------------------------------------------*
147   @brief        グラフィックス関連の初期化を行います。
148  *---------------------------------------------------------------------------*/
149 void
InitializeGraphics()150 InitializeGraphics()
151 {
152     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
153 
154     // renderDescriptionへステレオの設定を行います。
155     nw::demo::RenderSystem::Description renderDescription;
156 
157     renderDescription.reusableCommandBufferSize = 0x100000;
158     renderDescription.reusableCommandRequestCount      = 512;
159     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
160 
161     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
162 
163     s_GraphicsDrawing.SetScreenSize(
164         renderDescription.lowerScreenDescription.width,
165         renderDescription.lowerScreenDescription.height
166     );
167 
168     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
169 
170     s_RenderTargets.push_back(
171         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
172     );
173     NW_ASSERT(!s_RenderTargets.empty());
174     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
175 
176     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
177     nw::demo::SceneSystem::Description sceneDescription;
178 
179     // maxUserRenderNodes はデフォルト値が 0 になっているので、ここで値を設定します。
180     sceneDescription.maxUserRenderNodes = 1;
181     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
182 
183     // デモ用の最遠景モデルをレンダリングシステムに設定します。
184     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
185     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
186 
187     s_GrPrimitiveRenderer.Initialize( &s_DeviceAllocator, GR_SHADER_FILE );
188 
189     NW_GL_ASSERT();
190 }
191 
192 
193 /*!--------------------------------------------------------------------------*
194   @brief        グラフィックス関連の後始末をします。
195  *---------------------------------------------------------------------------*/
196 void
TerminateGraphics()197 TerminateGraphics()
198 {
199     s_GrPrimitiveRenderer.Finalize();
200 
201     nw::gfx::SafeDestroy(s_LeftCamera);
202 
203     nw::gfx::SafeDestroy(s_RightCamera);
204 
205     nw::gfx::SafeDestroy(s_SceneSystem);
206 
207     nw::gfx::SafeDestroyAll(s_RenderTargets);
208 
209     s_GraphicsDrawing.Finalize();
210 
211     nw::gfx::SafeDestroy(s_RenderSystem);
212 
213 
214     NW_GL_ASSERT();
215 }
216 
217 /*!--------------------------------------------------------------------------*
218   @brief        ユーザ定義の描画ノード関連の構築をします。
219  *---------------------------------------------------------------------------*/
220 void
BuildUserRenderNode()221 BuildUserRenderNode()
222 {
223     // ユーザ定義の描画コマンドを生成します
224     void* userCommandMemory = s_DeviceAllocator.Alloc(sizeof(GrUserRenderCommand));
225     NW_NULL_ASSERT(userCommandMemory);
226     s_GrUserRenderCommand = new(userCommandMemory) GrUserRenderCommand();
227 
228     // ユーザ定義の描画ノードを生成します
229     NW_ASSERT(s_UserRenderNode == NULL);
230     s_UserRenderNode = nw::gfx::UserRenderNode::DynamicBuilder()
231         .IsFixedSizeMemory(false)
232         .Create(&s_DeviceAllocator);
233     NW_NULL_ASSERT(s_UserRenderNode);
234 
235     // UserRenderNode は Z ソートされないので
236     // 描画優先度とレイヤー ID のみによってのみ描画順が制御できます。
237     s_UserRenderNode->SetPriority( 0 );
238     s_UserRenderNode->SetLayerId( 0 );
239 
240     // ユーザ定義の描画ノードに描画コマンドを設定します
241     s_UserRenderNode->SetUserRenderCommand(s_GrUserRenderCommand);
242 
243     // ユーザ定義の描画ノードをアタッチします
244     s_SceneRoot->AttachChild(s_UserRenderNode);
245 
246     s_UserRenderNode->Transform().SetTranslate(nw::math::VEC3(-5.0f, 5.0f, 0.0f));
247 }
248 
249 /*!--------------------------------------------------------------------------*
250   @brief        ルートノード関連の構築をします。
251  *---------------------------------------------------------------------------*/
252 void
BuildRootNodes()253 BuildRootNodes()
254 {
255     NW_ASSERT(s_SceneRoot == NULL);
256     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
257         .IsFixedSizeMemory(false)
258         .Create(&s_DeviceAllocator);
259     NW_NULL_ASSERT(s_SceneRoot);
260 }
261 
262 /*!--------------------------------------------------------------------------*
263   @brief        カメラ関連の構築をします。
264  *---------------------------------------------------------------------------*/
265 void
BuildCameras()266 BuildCameras()
267 {
268     nw::demo::Utility::CreateStereoCameras(
269         &s_BaseCamera,
270         &s_LeftCamera,
271         &s_RightCamera,
272         &s_DeviceAllocator,
273         nw::math::VEC3(23.0f, 20.0f, 21.0f),
274         nw::math::VEC3(0.0f, 8.0f, 0.0f)
275     );
276 
277     s_SceneRoot->AttachChild(s_BaseCamera);
278     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
279 }
280 
281 /*!--------------------------------------------------------------------------*
282   @brief        リソース関連の構築をします。
283  *---------------------------------------------------------------------------*/
284 void
BuildResources(nw::demo::ResourceSet * resourceSet)285 BuildResources(nw::demo::ResourceSet* resourceSet)
286 {
287     resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
288     resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
289     resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
290 
291     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
292     if (result.IsFailure())
293     {
294         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
295     }
296 
297     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
298 
299     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
300     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
301     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
302          modelResource != modelsEnd; ++modelResource)
303     {
304         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
305             &s_DeviceAllocator,
306             (*modelResource),
307             false
308         );
309         NW_NULL_ASSERT(node);
310         sceneNodeArray.push_back(node);
311 
312         nw::gfx::Model* model = nw::ut::DynamicCast<nw::gfx::Model*>(node);
313         model->Transform().SetTranslate(nw::math::VEC3(5.0f, 0.0f, 0.0f));
314     }
315 
316     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
317     nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
318     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
319          lightResource != lightsEnd; ++lightResource)
320     {
321         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
322             &s_DeviceAllocator,
323             (*lightResource)
324         );
325         NW_NULL_ASSERT(node);
326         sceneNodeArray.push_back(node);
327     }
328 
329     // 親子付け参照関係を解決
330     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
331 
332     nw::gfx::SceneHelper::ForeachRootNodes(
333         sceneNodeArray.Begin(),
334         sceneNodeArray.End(),
335         nw::gfx::AttachNode(s_SceneRoot)
336     );
337 
338     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
339     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
340     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
341         settingResource != settingsEnd; ++settingResource)
342     {
343         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
344             .Resource(*settingResource)
345             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
346 
347         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
348             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
349 
350         NW_NULL_ASSERT(sceneEnvironmentSetting);
351         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
352     }
353 }
354 
355 /*!--------------------------------------------------------------------------*
356   @brief        シーンを初期化します。
357  *---------------------------------------------------------------------------*/
358 void
InitializeScenes()359 InitializeScenes()
360 {
361     BuildRootNodes();
362 
363     BuildUserRenderNode();
364 
365     BuildCameras();
366 
367     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
368     {
369         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
370     }
371 
372     // シーンツリーを巡回して初期化を行います。
373     s_SceneSystem->InitializeScene(s_SceneRoot);
374     s_SceneSystem->UpdateScene();
375 
376     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
377 
378     // カメラを設定します。
379     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
380     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
381     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
382 
383     NW_GL_ASSERT();
384 
385     s_FrameCount = 0;
386 }
387 
388 /*!--------------------------------------------------------------------------*
389   @brief        シーン関連の後始末をします。
390  *---------------------------------------------------------------------------*/
391 void
TerminateScenes()392 TerminateScenes()
393 {
394     s_DeviceAllocator.Free(s_GrUserRenderCommand);
395     nw::gfx::SafeDestroyBranch(s_UserRenderNode);
396 
397     nw::gfx::SafeDestroyBranch(s_SceneRoot);
398     nw::demo::SafeCleanupResources(s_Resources);
399     nw::gfx::SafeDestroyAll(s_SceneEnvironmentSettings);
400 
401     NW_GL_ASSERT();
402 
403     s_Resources.clear();
404 }
405 
406 /*!--------------------------------------------------------------------------*
407   @brief        シーンを更新します。
408  *---------------------------------------------------------------------------*/
409 void
UpdateScene()410 UpdateScene()
411 {
412     s_SceneSystem->GetCameraController()->Update();
413 
414     s_SceneSystem->UpdateScene();
415 
416     s_BaseCamera->UpdateCameraMatrix();
417 
418     nw::gfx::ResCameraProjectionUpdater resProjectionUpdater =
419         s_BaseCamera->GetProjectionUpdater()->GetResource();
420 
421     int near = resProjectionUpdater.GetNear();
422 
423     s_RenderSystem->CalcStereoCamera(
424         s_LeftCamera,
425         s_RightCamera,
426         s_BaseCamera,
427         near + 5.0f);
428 
429     ++s_FrameCount;
430 }
431 
432 /*!--------------------------------------------------------------------------*
433   @brief        負荷表示やテスト機能の処理をおこないます。
434  *---------------------------------------------------------------------------*/
435 void
ReportDemo()436 ReportDemo()
437 {
438     NW_PROFILE("ReportDemo");
439 
440     // 負荷表示からはこれらの負荷は除きます。
441     s_RenderSystem->SuspendLoadMeter();
442 
443     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
444 
445     s_GraphicsDrawing.BeginDrawingShape();
446 
447     nw::demo::DebugUtility::DrawLoadMeter(
448         s_RenderSystem,
449         &s_GraphicsDrawing
450     );
451 
452     s_GraphicsDrawing.EndDrawingShape();
453 
454     s_GraphicsDrawing.BeginDrawingString();
455 
456     nw::demo::DebugUtility::DrawLoadMeterText(
457         s_RenderSystem,
458         &s_GraphicsDrawing
459     );
460 
461     s_GraphicsDrawing.EndDrawingString();
462 
463     s_RenderSystem->ResumeLoadMeter();
464 }
465 
466 /*!--------------------------------------------------------------------------*
467   @brief        シーンをデモンストレーションします。
468  *---------------------------------------------------------------------------*/
469 void
DemoScene()470 DemoScene()
471 {
472     NW_ASSERT(!s_RenderTargets.empty());
473 
474     InitializeScenes();
475 
476     nw::demo::DebugUtility::PostInitializeScenes();
477 
478     bool isContinuing = true;
479 
480     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
481 
482     while ( isContinuing )
483     {
484         nw::demo::DebugUtility::AdvanceAutoTestFrame();
485 
486         nw::demo::PadFactory::GetPad()->Update();
487 
488         UpdateScene();
489 
490         renderContext->SetActiveCamera(s_BaseCameraIndex);
491 
492         s_RenderSystem->SubmitView(s_SceneSystem);
493 
494         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
495         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
496 
497         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
498         ReportDemo();
499         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
500 
501         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
502 
503         renderContext->ResetState();
504 
505         if (nw::demo::Utility::IsTerminating())
506         {
507             isContinuing = false;
508         }
509     }
510 
511     nw::demo::DebugUtility::PreTerminateScenes();
512 
513     TerminateScenes();
514 }
515 
516 } // namespace
517 
518 /*!--------------------------------------------------------------------------*
519   @brief        メイン関数です。
520  *---------------------------------------------------------------------------*/
521 void
nnMain()522 nnMain()
523 {
524     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
525 
526     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
527 
528     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
529     {
530         InitializeGraphics();
531 
532         DemoScene();
533 
534         TerminateGraphics();
535     }
536 
537     nw::demo::PadFactory::Finalize();
538 
539     nw::demo::FinalizeGraphicsSystem();
540 }
541