1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     PartialAnimationDemo.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: $
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 
25 #include <nw/demo.h>
26 #include <nw/dev.h>
27 #include <nw/gfx.h>
28 #include <nw/ut.h>
29 #include <nw/anim.h>
30 
31 namespace
32 {
33 
34 //----------------------------------------
35 // メモリ関係
36 
37 // デバイスメモリを確保するためのアロケータです。
38 nw::demo::DemoAllocator s_DeviceAllocator;
39 
40 //----------------------------------------
41 // ファイル名の定義です。
42 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
43 
44 const wchar_t* MODEL_RESOURCE_FILES[] =
45 {
46     NW_DEMO_FILE_PATH(L"Male.bcmdl"),
47     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
48     NW_DEMO_FILE_PATH(L"FragmentLight.bcenv"),
49 };
50 
51 const wchar_t* SKELETAL_ANIM_RESOURCE_FILES[] =
52 {
53     NW_DEMO_FILE_PATH(L"RunLower.bcskla"),
54     NW_DEMO_FILE_PATH(L"AimAtOnlyUpperBody.bcskla")
55 };
56 
57 //----------------------------------------
58 // 描画関係
59 const int RENDER_TARGET_COUNT = 1;
60 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
61 
62 RenderTargetArray s_RenderTargets;
63 nw::demo::SceneSystem*  s_SceneSystem = NULL;
64 nw::demo::RenderSystem* s_RenderSystem = NULL;
65 
66 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
67 
68 //----------------------------------------
69 // リソース関係
70 nw::demo::ResourceArray s_Resources;
71 
72 //----------------------------------------
73 // シーン関係
74 const int SCENE_NODE_COUNT = 4;
75 nw::gfx::SceneNode* s_SceneRoot = NULL;
76 nw::gfx::SceneNode* s_ModelRoot = NULL;
77 s32 s_FrameCount = 0;
78 nw::gfx::Camera* s_BaseCamera = NULL;
79 nw::gfx::Camera* s_LeftCamera = NULL;
80 nw::gfx::Camera* s_RightCamera = NULL;
81 const f32 s_fNearPlane = 0.1f;
82 
83 //----------------------------------------
84 // シーン環境関係
85 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
86 
87 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
88 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
89 
90 const s32 s_BaseCameraIndex = 0;
91 
92 //----------------------------------------
93 // アニメーション関係
94 nw::gfx::SkeletalModel* s_AnimModel = NULL;
95 const int MAX_ANIM_OBJECTS = 6;
96 nw::ut::FixedSizeArray<nw::gfx::AnimObject*, MAX_ANIM_OBJECTS> s_AnimObjects;
97 const int MAX_ANIM_OBJECTS_PER_MODEL = 2;
98 
99 /*!--------------------------------------------------------------------------*
100   @brief        グラフィックス関連の初期化を行います。
101  *---------------------------------------------------------------------------*/
102 void
InitializeGraphics()103 InitializeGraphics()
104 {
105     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
106 
107     // renderDescriptionへステレオの設定を行います。
108     nw::demo::RenderSystem::Description renderDescription;
109 
110     renderDescription.reusableCommandBufferSize = 0x100000;
111     renderDescription.reusableCommandRequestCount = 512;
112     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
113 
114     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
115 
116     s_GraphicsDrawing.SetScreenSize(
117         renderDescription.lowerScreenDescription.width,
118         renderDescription.lowerScreenDescription.height
119     );
120 
121     nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing);
122 
123     s_RenderTargets.push_back(
124         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
125     );
126     NW_ASSERT(!s_RenderTargets.empty());
127     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
128 
129     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
130     nw::demo::SceneSystem::Description sceneDescription;
131     sceneDescription.isFixedSizeMemory = true;
132     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
133 
134     // デモ用の最遠景モデルをレンダリングシステムに設定します。
135     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
136     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
137 
138     NW_GL_ASSERT();
139 }
140 
141 /*!--------------------------------------------------------------------------*
142   @brief        グラフィックス関連の後始末をします。
143  *---------------------------------------------------------------------------*/
144 void
TerminateGraphics()145 TerminateGraphics()
146 {
147     nw::gfx::SafeDestroy(s_LeftCamera);
148 
149     nw::gfx::SafeDestroy(s_RightCamera);
150 
151     nw::gfx::SafeDestroy(s_SceneSystem);
152 
153     nw::gfx::SafeDestroyAll(s_RenderTargets);
154 
155     s_GraphicsDrawing.Finalize();
156 
157     nw::gfx::SafeDestroy(s_RenderSystem);
158 
159     NW_GL_ASSERT();
160 }
161 
162 /*!--------------------------------------------------------------------------*
163   @brief ファイルからトランスフォームアニメーション評価を生成します。
164 
165   @param[in] maxBones 最大メンバ数です。
166   @param[in] translateAnimEnabled 移動アニメーションが有効かどうかです。
167   @param[in] filePath トランスフォームアニメーションファイルのフルパスです。
168 
169   @return トランスフォームアニメーション評価です。
170  *---------------------------------------------------------------------------*/
171 nw::gfx::TransformAnimEvaluator*
CreateTransformAnimEvaluator(const int maxMembers,const bool translateAnimEnabled,const wchar_t * filePath)172 CreateTransformAnimEvaluator(
173     const int maxMembers,
174     const bool translateAnimEnabled,
175     const wchar_t* filePath
176 )
177 {
178     //----------------------------------------
179     // アニメーションリソースを生成します。
180     nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, filePath, &s_DeviceAllocator);
181     if (resourceSet->resource.GetSkeletalAnimsCount() == 0)
182     {
183         return NULL;
184     }
185     nw::anim::ResAnim resAnim = resourceSet->resource.GetSkeletalAnims(0);
186 
187     if (!resAnim.IsValid())
188     {
189         return NULL;
190     }
191 
192     //----------------------------------------
193     // トランスフォームアニメーション評価を生成します。
194     //
195     // アニメーションを1つのモデルにのみ適用する場合や、
196     // コマ形式データの場合は、 AllocCache を false にすると処理負荷が下がります。
197     nw::gfx::TransformAnimEvaluator* evaluator = nw::gfx::TransformAnimEvaluator::Builder()
198         .AnimData(resAnim)
199         .MaxMembers(maxMembers)
200         .MaxAnimMembers(resAnim.GetMemberAnimSetCount())
201         .AllocCache(false)
202         .Create(&s_DeviceAllocator);
203 
204     // 移動アニメーションの無効化フラグを設定します。
205     evaluator->SetIsTranslateDisabled(!translateAnimEnabled);
206 
207     return evaluator;
208 }
209 
210 /*!--------------------------------------------------------------------------*
211   @brief        スケルタルアニメーションを初期化します。
212 
213   1 つのモデルに複数の部分アニメのアニメーション評価をバインドします。
214 
215   @param[in]    model スケルタルモデルです。
216  *---------------------------------------------------------------------------*/
217 void
InitializeSkeletalAnim(nw::gfx::SkeletalModel * model)218 InitializeSkeletalAnim(nw::gfx::SkeletalModel* model)
219 {
220     nw::gfx::AnimGroup* animGroup = model->GetSkeletalAnimGroup();
221     if (animGroup == NULL) // スケルタルアニメーション用のアニメーショングループがありません。
222     {
223         return;
224     }
225 
226     nw::gfx::ResSkeletalModel resModel = model->GetResSkeletalModel();
227     nw::gfx::ResSkeleton resSkeleton = resModel.GetSkeleton();
228     const int maxBones = resSkeleton.GetBonesCount();
229     const bool translateAnimEnabled =
230         nw::ut::CheckFlag(resSkeleton.GetFlags(), nw::gfx::ResSkeletonData::FLAG_TRANSLATE_ANIMATION_ENABLED);
231 
232     //----------------------------------------
233     // アニメーション評価を生成します。
234     nw::gfx::TransformAnimEvaluator* evaluator0 = CreateTransformAnimEvaluator(
235         maxBones, translateAnimEnabled, SKELETAL_ANIM_RESOURCE_FILES[0]);
236     if (evaluator0 == NULL)
237     {
238         return;
239     }
240 
241     // アニメーションをバインドします。
242     evaluator0->Bind(animGroup);
243     s_AnimObjects.PushBack(evaluator0);
244 
245     //----------------------------------------
246     // 2 つめのアニメーション評価を生成します。
247     nw::gfx::TransformAnimEvaluator* evaluator1 = CreateTransformAnimEvaluator(
248         maxBones, translateAnimEnabled, SKELETAL_ANIM_RESOURCE_FILES[1]);
249 
250     if (evaluator1 == NULL)
251     {
252         return;
253     }
254 
255     // アニメーションを 1 つ目と同じアニメーショングループにバインドします。
256     evaluator1->Bind(animGroup);
257     s_AnimObjects.PushBack(evaluator1);
258 
259     //----------------------------------------
260     // モデルに 2 つのアニメーション評価を設定します。
261     model->SetSkeletalAnimObject(evaluator0, 0);
262     model->SetSkeletalAnimObject(evaluator1, 1);
263 }
264 
265 /*!--------------------------------------------------------------------------*
266   @brief        アニメーションの後始末をします。
267  *---------------------------------------------------------------------------*/
268 void
TerminateAnim(void)269 TerminateAnim(void)
270 {
271     for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx)
272     {
273         nw::gfx::SafeDestroy(s_AnimObjects[animIdx]);
274     }
275     s_AnimObjects.clear();
276 }
277 
278 /*!--------------------------------------------------------------------------*
279   @brief        ルートノード関連の構築をします。
280  *---------------------------------------------------------------------------*/
281 void
BuildRootNodes()282 BuildRootNodes()
283 {
284     NW_ASSERT(s_SceneRoot == NULL);
285     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
286         .Create(&s_DeviceAllocator);
287     NW_NULL_ASSERT(s_SceneRoot);
288 
289     NW_ASSERT(s_ModelRoot == NULL);
290     s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
291         .Create(&s_DeviceAllocator);
292     s_SceneRoot->AttachChild(s_ModelRoot);
293     NW_NULL_ASSERT(s_ModelRoot);
294 }
295 
296 /*!--------------------------------------------------------------------------*
297   @brief        カメラ関連の構築をします。
298  *---------------------------------------------------------------------------*/
299 void
BuildCameras()300 BuildCameras()
301 {
302     nw::demo::Utility::CreateStereoCameras(
303         &s_BaseCamera,
304         &s_LeftCamera,
305         &s_RightCamera,
306         &s_DeviceAllocator,
307         nw::math::VEC3(20.0f, 15.0f, 20.0f),
308         nw::math::VEC3(0.0f, 10.0f, 0.0f),
309         s_fNearPlane
310     );
311 
312     s_SceneRoot->AttachChild(s_BaseCamera);
313     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
314 }
315 
316 /*!--------------------------------------------------------------------------*
317   @brief        リソース関連の構築をします。
318  *---------------------------------------------------------------------------*/
319 void
BuildResources(nw::demo::ResourceSet * resourceSet)320 BuildResources(nw::demo::ResourceSet* resourceSet)
321 {
322     resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
323     resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
324     resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
325 
326     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
327     if (result.IsFailure())
328     {
329         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
330     }
331 
332     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
333 
334     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
335     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
336     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
337          modelResource != modelsEnd; ++modelResource)
338     {
339         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
340             &s_DeviceAllocator,
341             (*modelResource),
342             true,
343             nw::gfx::Model::FLAG_BUFFER_NOT_USE,
344             MAX_ANIM_OBJECTS_PER_MODEL // 複数のアニメーションオブジェクトをバインドできるようにします。
345         );
346         NW_NULL_ASSERT(node);
347         sceneNodeArray.push_back(node);
348 
349         s_AnimModel = nw::ut::DynamicCast<nw::gfx::SkeletalModel*>(node);
350     }
351 
352     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
353     nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
354     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
355          lightResource != lightsEnd; ++lightResource)
356     {
357         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
358             &s_DeviceAllocator,
359             (*lightResource)
360         );
361         NW_NULL_ASSERT(node);
362         sceneNodeArray.push_back(node);
363     }
364 
365     // 親子付け参照関係を解決
366     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
367 
368     // モデルをシーンに追加
369     nw::gfx::SceneHelper::ForeachRootNodes(
370         sceneNodeArray.Begin(),
371         sceneNodeArray.End(),
372         nw::gfx::AttachNode(s_ModelRoot)
373     );
374 
375     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
376     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
377     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
378         settingResource != settingsEnd; ++settingResource)
379     {
380         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
381             .Resource(*settingResource)
382             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
383 
384         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
385             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
386 
387         NW_NULL_ASSERT(sceneEnvironmentSetting);
388         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
389     }
390 }
391 
392 /*!--------------------------------------------------------------------------*
393   @brief        シーンを初期化します。
394  *---------------------------------------------------------------------------*/
395 void
InitializeScenes()396 InitializeScenes()
397 {
398     BuildRootNodes();
399 
400     BuildCameras();
401 
402     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
403     {
404         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
405     }
406 
407     if (s_AnimModel != NULL)
408     {
409         InitializeSkeletalAnim(s_AnimModel);
410     }
411 
412     // シーンツリーを巡回して初期化を行います。
413     s_SceneSystem->InitializeScene(s_SceneRoot);
414     s_SceneSystem->UpdateScene();
415 
416     // シーン環境の参照解決を行い設定します。
417     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
418 
419     // カメラを設定します。
420     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
421     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
422     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
423 
424     NW_GL_ASSERT();
425 
426     s_FrameCount = 0;
427 }
428 
429 /*!--------------------------------------------------------------------------*
430   @brief        シーン関連の後始末をします。
431  *---------------------------------------------------------------------------*/
432 void
TerminateScenes()433 TerminateScenes()
434 {
435     nw::gfx::SafeDestroyBranch(s_SceneRoot);
436     nw::demo::SafeCleanupResources(s_Resources);
437     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
438     TerminateAnim();
439 
440     NW_GL_ASSERT();
441 
442     s_Resources.clear();
443     s_SceneEnvironmentSettings.clear();
444 
445     s_ModelRoot = NULL;
446 }
447 
448 /*!--------------------------------------------------------------------------*
449   @brief        シーンを更新します。
450  *---------------------------------------------------------------------------*/
451 void
UpdateScene()452 UpdateScene()
453 {
454     s_SceneSystem->GetCameraController()->Update();
455 
456     s_SceneSystem->UpdateScene();
457 
458     s_BaseCamera->UpdateCameraMatrix();
459 
460     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
461 
462     ++s_FrameCount;
463 }
464 
465 /*!--------------------------------------------------------------------------*
466   @brief        負荷表示やテスト機能の処理をおこないます。
467  *---------------------------------------------------------------------------*/
468 void
ReportDemo()469 ReportDemo()
470 {
471     NW_PROFILE("ReportDemo");
472 
473     // 負荷表示からはこれらの負荷は除きます。
474     s_RenderSystem->SuspendLoadMeter();
475 
476     nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem);
477 
478     s_GraphicsDrawing.BeginDrawingShape();
479 
480     nw::demo::DebugUtility::DrawLoadMeter(
481         s_RenderSystem,
482         &s_GraphicsDrawing
483     );
484 
485     s_GraphicsDrawing.EndDrawingShape();
486 
487     s_GraphicsDrawing.BeginDrawingString();
488 
489     nw::demo::DebugUtility::DrawLoadMeterText(
490         s_RenderSystem,
491         &s_GraphicsDrawing
492     );
493 
494     s_GraphicsDrawing.EndDrawingString();
495 
496     s_RenderSystem->ResumeLoadMeter();
497 }
498 
499 /*!--------------------------------------------------------------------------*
500   @brief        シーンをデモンストレーションします。
501  *---------------------------------------------------------------------------*/
502 void
DemoScene()503 DemoScene()
504 {
505     NW_ASSERT(!s_RenderTargets.empty());
506 
507     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
508 
509     InitializeScenes();
510 
511     nw::demo::DebugUtility::PostInitializeScenes();
512 
513     bool isContinuing = true;
514 
515     while ( isContinuing )
516     {
517         nw::demo::DebugUtility::AdvanceAutoTestFrame();
518 
519         nw::demo::PadFactory::GetPad()->Update();
520 
521         UpdateScene();
522 
523         renderContext->SetActiveCamera(s_BaseCameraIndex);
524         s_RenderSystem->SubmitView(s_SceneSystem);
525 
526         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
527         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
528 
529         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
530         ReportDemo();
531         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
532 
533         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
534 
535         renderContext->ResetState();
536 
537         if (nw::demo::Utility::IsTerminating())
538         {
539             isContinuing = false;
540         }
541     }
542 
543     nw::demo::DebugUtility::PreTerminateScenes();
544 
545     TerminateScenes();
546 }
547 
548 } // namespace
549 
550 /*!--------------------------------------------------------------------------*
551   @brief        メイン関数です。
552  *---------------------------------------------------------------------------*/
553 void
nnMain()554 nnMain()
555 {
556     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
557 
558     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
559 
560     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
561     {
562         InitializeGraphics();
563 
564         DemoScene();
565 
566         TerminateGraphics();
567     }
568 
569     nw::demo::PadFactory::Finalize();
570 
571     nw::demo::FinalizeGraphicsSystem();
572 }
573