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