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