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