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