1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: SceneTreeDemo.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 const wchar_t* MODEL_RESOURCE_FILES[] =
43 {
44 NW_DEMO_FILE_PATH(L"SceneTree.bcmdl"),
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 static nw::demo::GraphicsDrawing s_GraphicsDrawing;
57 //----------------------------------------
58 // リソース関係
59 nw::demo::ResourceArray s_Resources;
60
61 //----------------------------------------
62 // シーン関係
63 nw::gfx::TransformNode* s_SceneRoot = NULL;
64 nw::gfx::TransformNode* s_ModelRoot = NULL;
65 nw::gfx::TransformNode* s_CameraRoot = NULL;
66 nw::gfx::TransformNode* s_LightRoot = NULL;
67 nw::gfx::TransformNode* s_FogRoot = NULL;
68 s32 s_FrameCount = 0;
69 nw::gfx::Camera* s_BaseCamera = NULL;
70 nw::gfx::Camera* s_LeftCamera = NULL;
71 nw::gfx::Camera* s_RightCamera = NULL;
72 const f32 s_fNearPlane = 0.1f;
73
74 const s32 s_BaseCameraIndex = 0;
75
76 /*!--------------------------------------------------------------------------*
77 @brief グラフィックス関連の初期化を行います。
78 *---------------------------------------------------------------------------*/
79 void
InitializeGraphics()80 InitializeGraphics()
81 {
82 nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
83
84 // renderDescriptionへステレオの設定を行います。
85 nw::demo::RenderSystem::Description renderDescription;
86
87 renderDescription.reusableCommandBufferSize = 0x100000;
88 renderDescription.reusableCommandRequestCount = 512;
89 renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
90
91 s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
92
93 s_GraphicsDrawing.SetScreenSize(
94 renderDescription.lowerScreenDescription.width,
95 renderDescription.lowerScreenDescription.height
96 );
97
98 nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
99
100 s_RenderTargets.push_back(
101 nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
102 );
103 NW_ASSERT(!s_RenderTargets.empty());
104 s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
105
106 // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
107 nw::demo::SceneSystem::Description sceneDescription;
108 s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
109
110 // デモ用の最遠景モデルをレンダリングシステムに設定します。
111 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
112 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
113
114 NW_GL_ASSERT();
115 }
116
117 /*!--------------------------------------------------------------------------*
118 @brief グラフィックス関連の後始末をします。
119 *---------------------------------------------------------------------------*/
120 void
TerminateGraphics()121 TerminateGraphics()
122 {
123 nw::gfx::SafeDestroy(s_LeftCamera);
124
125 nw::gfx::SafeDestroy(s_RightCamera);
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 .IsFixedSizeMemory(false)
147 .Create(&s_DeviceAllocator);
148 NW_NULL_ASSERT(s_SceneRoot);
149
150 NW_ASSERT(s_ModelRoot == NULL);
151 s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
152 .IsFixedSizeMemory(false)
153 .Create(&s_DeviceAllocator);
154 s_SceneRoot->AttachChild(s_ModelRoot);
155 NW_NULL_ASSERT(s_ModelRoot);
156
157 NW_ASSERT(s_CameraRoot == NULL);
158 s_CameraRoot = nw::gfx::TransformNode::DynamicBuilder()
159 .IsFixedSizeMemory(false)
160 .Create(&s_DeviceAllocator);
161 s_SceneRoot->AttachChild(s_CameraRoot);
162 NW_NULL_ASSERT(s_CameraRoot);
163
164 NW_ASSERT(s_LightRoot == NULL);
165 s_LightRoot = nw::gfx::TransformNode::DynamicBuilder()
166 .IsFixedSizeMemory(false)
167 .Create(&s_DeviceAllocator);
168 s_SceneRoot->AttachChild(s_LightRoot);
169 NW_NULL_ASSERT(s_LightRoot);
170
171 NW_ASSERT(s_FogRoot == NULL);
172 s_FogRoot = nw::gfx::TransformNode::DynamicBuilder()
173 .IsFixedSizeMemory(false)
174 .Create(&s_DeviceAllocator);
175 s_SceneRoot->AttachChild(s_FogRoot);
176 NW_NULL_ASSERT(s_FogRoot);
177
178 // テスト用にノードを生成して追加します。
179 s_SceneRoot->AttachChild(nw::gfx::SceneNode::DynamicBuilder()
180 .MaxChildren(4)
181 .Create(&s_DeviceAllocator));
182 }
183
184 /*!--------------------------------------------------------------------------*
185 @brief カメラ関連の構築をします。
186 *---------------------------------------------------------------------------*/
187 void
BuildCameras()188 BuildCameras()
189 {
190 // シーンツリーを構築します。
191 // カメラを生成します。
192 // カメラルートはシーンルートの子ノードになり親のトランスフォームの影響を受けます。
193
194 nw::demo::Utility::CreateStereoCameras(
195 &s_BaseCamera,
196 &s_LeftCamera,
197 &s_RightCamera,
198 &s_DeviceAllocator,
199 nw::math::VEC3(45.0f, 30.0f, 45.0f),
200 nw::math::VEC3(-45.0f, -15.0f, -45.0f),
201 s_fNearPlane
202 );
203
204 // ビューアップデータがカメラのトランスフォームの影響を受けるようにします。
205 nw::gfx::ResCameraViewUpdater resViewUpdater = s_BaseCamera->GetViewUpdater()->GetResource();
206 nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater =
207 nw::gfx::ResDynamicCast<nw::gfx::ResLookAtTargetViewUpdater>(resViewUpdater);
208 resLookAtTargetViewUpdater.SetFlags(
209 nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_ROTATE |
210 nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_TARGET_TRANSLATE |
211 nw::gfx::ResLookAtTargetViewUpdaterData::FLAG_INHERITING_UP_ROTATE);
212
213 s_CameraRoot->AttachChild(s_BaseCamera);
214 s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
215 }
216
217 /*!--------------------------------------------------------------------------*
218 @brief ライト関連の構築をします。
219 *---------------------------------------------------------------------------*/
220 void
BuildLights()221 BuildLights()
222 {
223 // ライトを生成します。
224 nw::gfx::AmbientLight* ambientLight = nw::gfx::AmbientLight::DynamicBuilder()
225 .MaxCallbacks(0)
226 .MaxChildren(0)
227 .Create(&s_DeviceAllocator);
228 s_LightRoot->AttachChild(ambientLight);
229
230 nw::gfx::ResAmbientLight resAmbientLight(ambientLight->GetResAmbientLight());
231 resAmbientLight.SetAmbient(0.2f, 0.2f, 0.2f);
232
233 nw::gfx::HemiSphereLight* hemiSphereLight = nw::gfx::HemiSphereLight::DynamicBuilder()
234 .MaxCallbacks(0)
235 .MaxChildren(0)
236 .Create(&s_DeviceAllocator);
237 s_LightRoot->AttachChild(hemiSphereLight);
238
239 nw::gfx::ResHemiSphereLight resHemiSphereLight(hemiSphereLight->GetResHemiSphereLight());
240 resHemiSphereLight.SetSkyColor(0.9f, 0.9f, 1.0f);
241 resHemiSphereLight.SetGroundColor(0.1f, 0.0f, 0.0f);
242 resHemiSphereLight.SetDirection(0.0f, 1.0f, 0.0f);
243 resHemiSphereLight.SetLerpFactor(0.5f);
244
245 nw::gfx::VertexLight* vertexLight = nw::gfx::VertexLight::DynamicBuilder()
246 .MaxCallbacks(0)
247 .MaxChildren(0)
248 .Create(&s_DeviceAllocator);
249 s_LightRoot->AttachChild(vertexLight);
250
251 nw::gfx::ResVertexLight resVertexLight(vertexLight->GetResVertexLight());
252 resVertexLight.SetLightKind(nw::gfx::ResVertexLight::KIND_SPOT);
253 resVertexLight.GetTransform().translate.Set(0.0f, 15.0f, 5.0f);
254 resVertexLight.SetAmbient(0.2f, 0.2f, 0.2f);
255 resVertexLight.SetDiffuse(1.0f, 1.0f, 1.0f);
256 resVertexLight.SetDistanceAttenuation(0.01f, 0.001f, 0.0001f);
257 resVertexLight.SetDistanceAttenuationEnabled(true);
258 resVertexLight.SetSpotFactor(1.0f, NW_MATH_DEG_TO_RAD(90.0f));
259 nw::math::VEC3 vertexLightDirection(0.0f, 0.0f, -1.0f);
260 vertexLightDirection.Normalize();
261 resVertexLight.SetDirection(vertexLightDirection);
262
263 nw::gfx::FragmentLight* fragmentLight = nw::gfx::FragmentLight::DynamicBuilder()
264 .MaxCallbacks(0)
265 .MaxChildren(0)
266 .Create(&s_DeviceAllocator);
267 s_LightRoot->AttachChild(fragmentLight);
268
269 nw::gfx::ResFragmentLight resFragmentLight(fragmentLight->GetResFragmentLight());
270 resFragmentLight.SetLightKind(nw::gfx::ResFragmentLight::KIND_DIRECTIONAL);
271 nw::math::VEC3 fragmentLightDirection(-0.5f, -1.0f, -0.5f);
272 fragmentLightDirection.Normalize();
273 resFragmentLight.SetDirection(fragmentLightDirection);
274 resFragmentLight.SetAmbient(0.2f, 0.2f, 0.2f);
275 resFragmentLight.SetDiffuse(1.0f, 1.0f, 1.0f);
276 resFragmentLight.SetSpecular0(0.8f, 0.8f, 0.8f);
277 resFragmentLight.SetSpecular1(0.8f, 0.8f, 0.8f);
278 }
279
280 /*!--------------------------------------------------------------------------*
281 @brief フォグ関連の構築をします。
282 *---------------------------------------------------------------------------*/
283 void
BuildFogs()284 BuildFogs()
285 {
286 // フォグを生成します。
287 nw::gfx::Fog* fog = nw::gfx::Fog::DynamicBuilder()
288 .MaxCallbacks(0)
289 .MaxChildren(0)
290 .Create(&s_DeviceAllocator);
291 s_FogRoot->AttachChild(fog);
292
293 nw::gfx::ResFog resFog(fog->GetResFog());
294
295 resFog.SetColor(0.3f, 0.3f, 0.5f);
296
297 nw::gfx::ResFogUpdater resFogUpdater = resFog.GetFogUpdater();
298 resFogUpdater.SetFogUpdaterType(nw::gfx::ResFogUpdater::FOG_UPDATER_TYPE_EXPONENT_SQUARE);
299 resFogUpdater.SetDensity(10.0f);
300 resFogUpdater.SetMinFogDepth(10.0f);
301 resFogUpdater.SetMaxFogDepth(500.0f);
302 }
303
304 /*!--------------------------------------------------------------------------*
305 @brief リソース関連の構築をします。
306 *---------------------------------------------------------------------------*/
307 void
BuildResources(nw::demo::ResourceSet * resourceSet)308 BuildResources(nw::demo::ResourceSet* resourceSet)
309 {
310 resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
311 resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
312 resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
313
314 nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
315
316 if (result.IsFailure())
317 {
318 NW_FATAL_ERROR("Fail to set up model. A result code is %x", result.GetCode());
319 }
320
321 nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
322
323 nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
324 nw::gfx::ResModelArray::iterator modelsEnd = models.end();
325 for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
326 modelResource != modelsEnd; ++modelResource)
327 {
328 // マテリアルバッファを利用します。
329 nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
330 &s_DeviceAllocator,
331 (*modelResource),
332 false,
333 nw::gfx::Model::MULTI_FLAG_BUFFER_MATERIAL
334 );
335 NW_NULL_ASSERT(node);
336 sceneNodeArray.push_back(node);
337
338 if (nw::ut::IsTypeOf<nw::gfx::SkeletalModel>(node))
339 {
340 nw::gfx::SkeletalModel* skeletalModel = static_cast<nw::gfx::SkeletalModel*>(node);
341 nw::gfx::Skeleton* skeleton = skeletalModel->GetSkeleton();
342 NW_NULL_ASSERT(skeleton);
343
344 nw::gfx::ResSkeleton resSkeleton = skeleton->GetResSkeleton();
345 NW_ASSERT(resSkeleton.IsValid());
346 }
347
348 }
349
350 // モデルをシーンに追加
351 nw::gfx::SceneHelper::ForeachRootNodes(
352 sceneNodeArray.Begin(),
353 sceneNodeArray.End(),
354 nw::gfx::AttachNode(s_ModelRoot)
355 );
356 }
357
358 /*!--------------------------------------------------------------------------*
359 @brief シーンを初期化します。
360 *---------------------------------------------------------------------------*/
361 void
InitializeScenes()362 InitializeScenes()
363 {
364 BuildRootNodes();
365
366 BuildCameras();
367
368 BuildLights();
369
370 BuildFogs();
371
372 NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
373 {
374 BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
375 }
376
377 // シーンツリーを巡回して初期化を行います。
378 s_SceneSystem->InitializeScene(s_SceneRoot);
379 s_SceneSystem->UpdateScene();
380
381 // カメラを設定します。
382 nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
383 sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
384 nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
385
386 NW_GL_ASSERT();
387
388 s_FrameCount = 0;
389 }
390
391 /*!--------------------------------------------------------------------------*
392 @brief シーン関連の後始末をします。
393 *---------------------------------------------------------------------------*/
394 void
TerminateScenes()395 TerminateScenes()
396 {
397 nw::gfx::SafeDestroyBranch(s_SceneRoot);
398 nw::demo::SafeCleanupResources(s_Resources);
399
400 NW_GL_ASSERT();
401
402 s_Resources.clear();
403 s_ModelRoot = NULL;
404 s_CameraRoot = NULL;
405 s_LightRoot = NULL;
406 s_FogRoot = NULL;
407 }
408
409 /*!--------------------------------------------------------------------------*
410 @brief シーンを更新します。
411 *---------------------------------------------------------------------------*/
412 void
UpdateScene()413 UpdateScene()
414 {
415 float radian = static_cast<float>((s_FrameCount * 5) % (314 * 2)) * 0.01f;
416
417 // カメラルートがY軸中心に回転します。
418 nw::gfx::TransformNode* cameraNode =
419 nw::ut::DynamicCast<nw::gfx::TransformNode*>(s_CameraRoot);
420 NW_NULL_ASSERT(cameraNode);
421
422 cameraNode->Transform().SetRotateXYZ(0.0f, radian, 0.0f);
423
424 // モデルルートがY軸に沿って上下します。
425 nw::gfx::TransformNode* modelNode =
426 nw::ut::DynamicCast<nw::gfx::TransformNode*>(s_ModelRoot);
427 NW_NULL_ASSERT(modelNode);
428
429 modelNode->Transform().SetTranslate(0.0f, nw::math::SinRad(radian) * 10.0f, 0.0f);
430
431 nw::gfx::SceneNodeArray::iterator end = modelNode->GetChildEnd();
432 for (nw::gfx::SceneNodeArray::iterator node = modelNode->GetChildBegin(); node != end; ++node)
433 {
434 // Model クラスの Transform を変更します。
435 if (nw::ut::IsTypeOf<nw::gfx::Model>(*node))
436 {
437 nw::gfx::Model* model = static_cast<nw::gfx::Model*>(*node);
438 model->Transform().SetScale(radian, radian, radian);
439 model->Transform().SetRotateXYZ(radian, 0.0f, 0.0f);
440 }
441 }
442
443 s_SceneSystem->GetCameraController()->Update();
444
445 s_SceneSystem->UpdateScene();
446
447 s_BaseCamera->UpdateCameraMatrix();
448
449 s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
450
451 ++s_FrameCount;
452 }
453
454 /*!--------------------------------------------------------------------------*
455 @brief 負荷表示やテスト機能の処理をおこないます。
456 *---------------------------------------------------------------------------*/
457 void
ReportDemo()458 ReportDemo()
459 {
460 NW_PROFILE("ReportDemo");
461
462 // 負荷表示からはこれらの負荷は除きます。
463 s_RenderSystem->SuspendLoadMeter();
464
465 nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
466
467 s_GraphicsDrawing.BeginDrawingShape();
468
469 nw::demo::DebugUtility::DrawLoadMeter(
470 s_RenderSystem,
471 &s_GraphicsDrawing
472 );
473
474 s_GraphicsDrawing.EndDrawingShape();
475
476 s_GraphicsDrawing.BeginDrawingString();
477
478 nw::demo::DebugUtility::DrawLoadMeterText(
479 s_RenderSystem,
480 &s_GraphicsDrawing
481 );
482
483 s_GraphicsDrawing.EndDrawingString();
484
485 s_RenderSystem->ResumeLoadMeter();
486 }
487
488 /*!--------------------------------------------------------------------------*
489 @brief シーンをデモンストレーションします。
490 *---------------------------------------------------------------------------*/
491 void
DemoScene()492 DemoScene()
493 {
494 NW_ASSERT(!s_RenderTargets.empty());
495
496 nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
497
498 InitializeScenes();
499
500 nw::demo::DebugUtility::PostInitializeScenes();
501
502 bool isContinuing = true;
503
504 while ( isContinuing )
505 {
506 nw::demo::DebugUtility::AdvanceAutoTestFrame();
507
508 nw::demo::PadFactory::GetPad()->Update();
509
510 UpdateScene();
511
512 // SceneTreeDemo は SceneEnvironmentSetting を読み込まず
513 // SceneEnvironment に直接ライト、フォグを設定しています。
514 s_RenderSystem->SetEnvironment(s_SceneSystem);
515
516 renderContext->SetActiveCamera(s_BaseCameraIndex);
517 s_RenderSystem->SubmitView(s_SceneSystem);
518
519 s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
520 s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
521
522 s_RenderSystem->ClearBySkyModel(s_BaseCamera);
523 ReportDemo();
524 s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
525
526 s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
527
528 renderContext->ResetState();
529
530 if (nw::demo::Utility::IsTerminating())
531 {
532 isContinuing = false;
533 }
534 }
535
536 nw::demo::DebugUtility::PreTerminateScenes();
537
538 TerminateScenes();
539 }
540
541 } // namespace
542
543 /*!--------------------------------------------------------------------------*
544 @brief メイン関数です。
545 *---------------------------------------------------------------------------*/
546 void
nnMain()547 nnMain()
548 {
549 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
550
551 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
552
553 NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
554 {
555 InitializeGraphics();
556
557 DemoScene();
558
559 TerminateGraphics();
560 }
561
562 nw::demo::PadFactory::Finalize();
563
564 nw::demo::FinalizeGraphicsSystem();
565 }
566