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