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