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