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