1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     AnimationBlendDemo.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"Walk.bcskla"),
54     NW_DEMO_FILE_PATH(L"Run.bcskla")
55 };
56 
57 const wchar_t* MATERIAL_ANIM_RESOURCE_FILES[] =
58 {
59     NW_DEMO_FILE_PATH(L"RedFading.bcmata"),
60     NW_DEMO_FILE_PATH(L"GreenFading.bcmata")
61 };
62 
63 //----------------------------------------
64 // プロファイル関係
65 const int NW_LOAD_METER_INTERVAL = 60;
66 
67 //----------------------------------------
68 // 描画関係
69 const int RENDER_TARGET_COUNT = 1;
70 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
71 
72 RenderTargetArray s_RenderTargets;
73 nw::demo::SceneSystem*  s_SceneSystem = NULL;
74 nw::demo::RenderSystem* s_RenderSystem = NULL;
75 
76 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
77 
78 //----------------------------------------
79 // リソース関係
80 nw::demo::ResourceArray s_Resources;
81 
82 //----------------------------------------
83 // シーン関係
84 const int SCENE_NODE_COUNT = 4;
85 nw::gfx::SceneNode* s_SceneRoot = NULL;
86 nw::gfx::SceneNode* s_ModelRoot = NULL;
87 s32 s_FrameCount = 0;
88 nw::gfx::Camera* s_BaseCamera = NULL;
89 nw::gfx::Camera* s_LeftCamera = NULL;
90 nw::gfx::Camera* s_RightCamera = NULL;
91 const f32 s_fNearPlane = 0.1f;
92 
93 //----------------------------------------
94 // シーン環境関係
95 const s32 ENVIRONMENT_SETTINGS_COUNT = 1;
96 
97 typedef nw::ut::FixedSizeArray<nw::gfx::SceneEnvironmentSetting*, ENVIRONMENT_SETTINGS_COUNT> SceneEnvironmentSettingArray;
98 SceneEnvironmentSettingArray s_SceneEnvironmentSettings;
99 
100 const s32 s_BaseCameraIndex = 0;
101 
102 //----------------------------------------
103 // アニメーション関係
104 nw::gfx::SkeletalModel* s_AnimModel = NULL;
105 const int MAX_ANIM_OBJECTS = 6;
106 nw::ut::FixedSizeArray<nw::gfx::AnimObject*, MAX_ANIM_OBJECTS> s_AnimObjects;
107 float s_SkeletalAnimWeight0 = 0.5f;
108 float s_SkeletalAnimWeight1 = 0.5f;
109 float s_MaterialAnimWeight0 = 0.5f;
110 float s_MaterialAnimWeight1 = 0.5f;
111 
112 /*!--------------------------------------------------------------------------*
113   @brief        グラフィックス関連の初期化を行います。
114  *---------------------------------------------------------------------------*/
115 void
InitializeGraphics()116 InitializeGraphics()
117 {
118     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
119 
120     // renderDescriptionへステレオの設定を行います。
121     nw::demo::RenderSystem::Description renderDescription;
122 
123     renderDescription.reusableCommandBufferSize = 0x100000;
124     renderDescription.reusableCommandRequestCount      = 512;
125     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
126 
127     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
128 
129     s_GraphicsDrawing.SetScreenSize(
130         renderDescription.lowerScreenDescription.width,
131         renderDescription.lowerScreenDescription.height
132     );
133 
134     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
135 
136     NN_ASSERTMSG(result, "Fail to load Font.");
137 
138     s_RenderTargets.push_back(
139         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
140     );
141     NW_ASSERT(!s_RenderTargets.empty());
142     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
143 
144     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
145     nw::demo::SceneSystem::Description sceneDescription;
146     sceneDescription.isFixedSizeMemory = true;
147     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
148 
149     // デモ用の最遠景モデルをレンダリングシステムに設定します。
150     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
151     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
152 
153     NW_GL_ASSERT();
154 }
155 
156 /*!--------------------------------------------------------------------------*
157   @brief        グラフィックス関連の後始末をします。
158  *---------------------------------------------------------------------------*/
159 void
TerminateGraphics()160 TerminateGraphics()
161 {
162     nw::gfx::SafeDestroy(s_LeftCamera);
163 
164     nw::gfx::SafeDestroy(s_RightCamera);
165 
166     nw::gfx::SafeDestroy(s_SceneSystem);
167 
168     nw::gfx::SafeDestroyAll(s_RenderTargets);
169 
170     s_GraphicsDrawing.Finalize();
171 
172     nw::gfx::SafeDestroy(s_RenderSystem);
173 
174     NW_GL_ASSERT();
175 }
176 
177 /*!--------------------------------------------------------------------------*
178   @brief ファイルから TransformAnimEvaluator を生成します。
179 
180   リソースからアニメーションを計算するための AnimEvaluator(アニメーション評価)を生成します。
181 
182   @param[in] maxBones 最大メンバ数です。
183   @param[in] translateAnimEnabled 移動アニメーションが有効かどうかです。
184   @param[in] filePath トランスフォームアニメーションファイルのフルパスです。
185 
186   @return トランスフォームアニメーション評価です。
187  *---------------------------------------------------------------------------*/
188 nw::gfx::TransformAnimEvaluator*
CreateTransformAnimEvaluator(const int maxMembers,const bool translateAnimEnabled,const wchar_t * filePath)189 CreateTransformAnimEvaluator(
190     const int maxMembers,
191     const bool translateAnimEnabled,
192     const wchar_t* filePath
193 )
194 {
195     // ファイルからアニメーションデータのインスタンスを生成します。
196     nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, filePath, &s_DeviceAllocator);
197     if (resourceSet->resource.GetSkeletalAnimsCount() == 0)
198     {
199         // スケルタルアニメーション用のアニメーションデータがありません。
200         return NULL;
201     }
202     nw::anim::ResAnim resAnim = resourceSet->resource.GetSkeletalAnims(0);
203 
204     if (!resAnim.IsValid())
205     {
206         return NULL;
207     }
208 
209     // resAnim から、AnimEvaluator::Builder を用いて AnimEvaluator を生成します。
210     // スケルタルアニメーションの場合は、TransformAnimEvaluator::Builder を使用します。
211     //
212     // アニメーションを1つのモデルにのみ適用する場合や、
213     // コマ形式データの場合は、 AllocCache を false にすると処理負荷が下がります。
214     nw::gfx::TransformAnimEvaluator* evaluator = nw::gfx::TransformAnimEvaluator::Builder()
215         .AnimData(resAnim)
216         .MaxMembers(maxMembers)
217         .MaxAnimMembers(resAnim.GetMemberAnimSetCount())
218         .AllocCache(false)
219         .Create(&s_DeviceAllocator);
220 
221     // 移動アニメーションの無効化フラグを設定します。
222     evaluator->SetIsTranslateDisabled(!translateAnimEnabled);
223 
224     return evaluator;
225 }
226 
227 /*!--------------------------------------------------------------------------*
228   @brief ファイルからマテリアルアニメーション評価を生成します。
229 
230   @param[in] maxBones 最大メンバ数です。
231   @param[in] filePath マテリアルアニメーションファイルのフルパスです。
232 
233   @return マテリアルアニメーション評価です。
234  *---------------------------------------------------------------------------*/
235 nw::gfx::AnimEvaluator*
CreateMaterialAnimEvaluator(const int maxMembers,const wchar_t * filePath)236 CreateMaterialAnimEvaluator(
237     const int maxMembers,
238     const wchar_t* filePath
239 )
240 {
241     //----------------------------------------
242     // アニメーションリソースを生成します。
243     nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, filePath, &s_DeviceAllocator);
244     if (resourceSet->resource.GetMaterialAnimsCount() == 0)
245     {
246         return NULL;
247     }
248 
249     nw::anim::ResAnim resAnim = resourceSet->resource.GetMaterialAnims(0);
250     if (!resAnim.IsValid())
251     {
252         return NULL;
253     }
254 
255     //----------------------------------------
256     // マテリアルアニメーション評価を生成します。
257     nw::gfx::AnimEvaluator* evaluator = nw::gfx::AnimEvaluator::Builder()
258         .AnimData(resAnim)
259         .MaxMembers(maxMembers)
260         .MaxAnimMembers(resAnim.GetMemberAnimSetCount())
261         .AllocCache(true)
262         .Create(&s_DeviceAllocator);
263 
264     return evaluator;
265 }
266 
267 /*!--------------------------------------------------------------------------*
268   @brief        スケルタルアニメーションを初期化します。
269 
270   アニメーション補間を生成し、2 つのアニメーション評価の結果をブレンドします。
271 
272   @param[in]    model スケルタルモデルです。
273  *---------------------------------------------------------------------------*/
274 void
InitializeSkeletalAnim(nw::gfx::SkeletalModel * model)275 InitializeSkeletalAnim(nw::gfx::SkeletalModel* model)
276 {
277     nw::gfx::AnimGroup* animGroup = model->GetSkeletalAnimGroup();
278     if (animGroup == NULL) // スケルタルアニメーション用のアニメーショングループがありません。
279     {
280         return;
281     }
282 
283     nw::gfx::ResSkeletalModel resModel = model->GetResSkeletalModel();
284     nw::gfx::ResSkeleton resSkeleton = resModel.GetSkeleton();
285     const int maxBones = resSkeleton.GetBonesCount();
286     const bool translateAnimEnabled =
287         nw::ut::CheckFlag(resSkeleton.GetFlags(), nw::gfx::ResSkeletonData::FLAG_TRANSLATE_ANIMATION_ENABLED);
288 
289     //----------------------------------------
290     // アニメーション評価を生成します。
291     nw::gfx::TransformAnimEvaluator* evaluator0 = CreateTransformAnimEvaluator(
292         maxBones, translateAnimEnabled, SKELETAL_ANIM_RESOURCE_FILES[0]);
293     if (evaluator0 == NULL)
294     {
295         return;
296     }
297 
298     // アニメーションをバインドします。
299     evaluator0->Bind(animGroup);
300     s_AnimObjects.PushBack(evaluator0);
301 
302     //----------------------------------------
303     // 2 つめのアニメーション評価を生成します。
304     nw::gfx::TransformAnimEvaluator* evaluator1 = CreateTransformAnimEvaluator(
305         maxBones, translateAnimEnabled, SKELETAL_ANIM_RESOURCE_FILES[1]);
306 
307     if (evaluator1 == NULL)
308     {
309         return;
310     }
311 
312     evaluator1->Bind(animGroup);
313     s_AnimObjects.PushBack(evaluator1);
314 
315     // 自然な絵になるように、2つのアニメーションの再生時間を合わせます。
316     float frameSize0 = evaluator0->AnimFrameController().GetEndFrame();
317     float frameSize1 = evaluator1->AnimFrameController().GetEndFrame();
318     evaluator1->SetStepFrame(frameSize1 / frameSize0);
319 
320     //----------------------------------------
321     // スケルタルアニメーション補間を生成します。
322     nw::gfx::TransformAnimInterpolator* blender = nw::gfx::TransformAnimInterpolator::Builder()
323         .MaxAnimObjects(2)
324         .Create(&s_DeviceAllocator);
325 
326     blender->Bind(animGroup);
327     blender->AddAnimObject(evaluator0);
328     blender->AddAnimObject(evaluator1);
329     blender->SetWeight(0, s_SkeletalAnimWeight0);
330     blender->SetWeight(1, s_SkeletalAnimWeight1);
331 
332     // 設定する重みは常に合計が 1 になり正規化は不要なので、正規化を無効にします。
333     // 合計が 1 にならないような重みを設定する場合は true を指定します。
334     blender->SetNormalizationEnabled(false);
335 
336     model->SetSkeletalAnimObject(blender);
337     s_AnimObjects.PushBack(blender);
338 }
339 
340 /*!--------------------------------------------------------------------------*
341   @brief        マテリアルアニメーションを初期化します。
342 
343   アニメーション補間を生成し、2 つのアニメーション評価の結果をブレンドします。
344 
345   @param[in]    model モデルです。
346  *---------------------------------------------------------------------------*/
347 void
InitializeMaterialAnim(nw::gfx::Model * model)348 InitializeMaterialAnim(nw::gfx::Model* model)
349 {
350     nw::gfx::AnimGroup* animGroup = model->GetMaterialAnimGroup();
351 
352     if (animGroup == NULL) // アニメーション用のアニメーショングループがありません。
353     {
354         return;
355     }
356 
357     int maxMembers = animGroup->GetMemberCount();
358 
359     //----------------------------------------
360     // アニメーション評価を生成します。
361     nw::gfx::AnimEvaluator* evaluator0 = CreateMaterialAnimEvaluator(
362         maxMembers, MATERIAL_ANIM_RESOURCE_FILES[0]);
363     if (evaluator0 == NULL)
364     {
365         return;
366     }
367 
368     // アニメーションをバインドします。
369     evaluator0->Bind(animGroup);
370     s_AnimObjects.PushBack(evaluator0);
371 
372     //----------------------------------------
373     // 2 つめのアニメーション評価を生成します。
374     nw::gfx::AnimEvaluator* evaluator1 = CreateMaterialAnimEvaluator(
375         maxMembers, MATERIAL_ANIM_RESOURCE_FILES[1]);
376 
377     if (evaluator1 == NULL)
378     {
379         return;
380     }
381 
382     evaluator1->Bind(animGroup);
383     s_AnimObjects.PushBack(evaluator1);
384 
385     //----------------------------------------
386     // アニメーション補間を生成します。
387     nw::gfx::AnimInterpolator* blender = nw::gfx::AnimInterpolator::Builder()
388         .MaxAnimObjects(2)
389         .Create(&s_DeviceAllocator);
390 
391     blender->Bind(animGroup);
392     blender->AddAnimObject(evaluator0);
393     blender->AddAnimObject(evaluator1);
394     blender->SetWeight(0, s_MaterialAnimWeight0);
395     blender->SetWeight(1, s_MaterialAnimWeight0);
396 
397     // 設定する重みは常に合計が 1 になり正規化は不要なので、正規化を無効にします。
398     // 合計が 1 にならないような重みを設定する場合は true を指定します。
399     blender->SetNormalizationEnabled(false);
400 
401     model->SetMaterialAnimObject(blender);
402     s_AnimObjects.PushBack(blender);
403 }
404 
405 /*!--------------------------------------------------------------------------*
406   @brief        ブレンダーを更新します。
407 
408   @param[in]    model モデルです。
409  *---------------------------------------------------------------------------*/
410 void
UpdateBlender(nw::gfx::SkeletalModel * model)411 UpdateBlender(nw::gfx::SkeletalModel* model)
412 {
413     NW_PROFILE("UpdateBlender");
414 
415     if (model == NULL)
416     {
417         return;
418     }
419 
420     // ブレンドのウェイト値を設定します。
421     nw::gfx::AnimObject* skeletalAnimObject = model->GetSkeletalAnimObject();
422     nw::gfx::TransformAnimInterpolator* skeletalInterpolator =
423         nw::ut::DynamicCast<nw::gfx::TransformAnimInterpolator*>(skeletalAnimObject);
424     if (skeletalInterpolator != NULL)
425     {
426         bool weightChanged = false;
427         nw::demo::Pad* pad = nw::demo::PadFactory::GetPad();
428         if (pad->IsButtonPress(nw::demo::Pad::BUTTON_LEFT))
429         {
430             s_SkeletalAnimWeight1 -= 0.02f;
431             weightChanged = true;
432         }
433         if (pad->IsButtonPress(nw::demo::Pad::BUTTON_RIGHT))
434         {
435             s_SkeletalAnimWeight1 += 0.02f;
436             weightChanged = true;
437         }
438         if (weightChanged)
439         {
440             s_SkeletalAnimWeight1 = nw::ut::Clamp(s_SkeletalAnimWeight1, 0.0f, 1.0f);
441             s_SkeletalAnimWeight0 = 1.0f - s_SkeletalAnimWeight1;
442 
443             skeletalInterpolator->SetWeight(0, s_SkeletalAnimWeight0);
444             skeletalInterpolator->SetWeight(1, s_SkeletalAnimWeight1);
445         }
446     }
447 
448     nw::gfx::AnimObject* materialAnimObject = model->GetMaterialAnimObject();
449     nw::gfx::AnimInterpolator* materialInterpolator =
450         nw::ut::DynamicCast<nw::gfx::AnimInterpolator*>(materialAnimObject);
451     if (materialInterpolator != NULL)
452     {
453         bool weightChanged = false;
454         nw::demo::Pad* pad = nw::demo::PadFactory::GetPad();
455         if (pad->IsButtonPress(nw::demo::Pad::BUTTON_UP))
456         {
457             s_MaterialAnimWeight1 -= 0.02f;
458             weightChanged = true;
459         }
460         if (pad->IsButtonPress(nw::demo::Pad::BUTTON_DOWN))
461         {
462             s_MaterialAnimWeight1 += 0.02f;
463             weightChanged = true;
464         }
465         if (weightChanged)
466         {
467             s_MaterialAnimWeight1 = nw::ut::Clamp(s_MaterialAnimWeight1, 0.0f, 1.0f);
468             s_MaterialAnimWeight0 = 1.0f - s_MaterialAnimWeight1;
469 
470             materialInterpolator->SetWeight(0, s_MaterialAnimWeight1);
471             materialInterpolator->SetWeight(1, s_MaterialAnimWeight0);
472         }
473     }
474 }
475 
476 /*!--------------------------------------------------------------------------*
477   @brief        アニメーションの後始末をします。
478  *---------------------------------------------------------------------------*/
479 void
TerminateAnim(void)480 TerminateAnim(void)
481 {
482     for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx)
483     {
484         nw::gfx::SafeDestroy(s_AnimObjects[animIdx]);
485     }
486     s_AnimObjects.clear();
487 }
488 
489 /*!--------------------------------------------------------------------------*
490   @brief        ルートノード関連の構築をします。
491  *---------------------------------------------------------------------------*/
492 void
BuildRootNodes()493 BuildRootNodes()
494 {
495     NW_ASSERT(s_SceneRoot == NULL);
496     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
497         .Create(&s_DeviceAllocator);
498     NW_NULL_ASSERT(s_SceneRoot);
499 
500     NW_ASSERT(s_ModelRoot == NULL);
501     s_ModelRoot = nw::gfx::TransformNode::DynamicBuilder()
502         .Create(&s_DeviceAllocator);
503     s_SceneRoot->AttachChild(s_ModelRoot);
504     NW_NULL_ASSERT(s_ModelRoot);
505 }
506 
507 /*!--------------------------------------------------------------------------*
508   @brief        カメラ関連の構築をします。
509  *---------------------------------------------------------------------------*/
510 void
BuildCameras()511 BuildCameras()
512 {
513     nw::demo::Utility::CreateStereoCameras(
514         &s_BaseCamera,
515         &s_LeftCamera,
516         &s_RightCamera,
517         &s_DeviceAllocator,
518         nw::math::VEC3(20.0f, 15.0f, 20.0f),
519         nw::math::VEC3(0.0f, 10.0f, 0.0f),
520         s_fNearPlane
521     );
522 
523     s_SceneRoot->AttachChild(s_BaseCamera);
524     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
525 }
526 
527 /*!--------------------------------------------------------------------------*
528   @brief        リソース関連の構築をします。
529  *---------------------------------------------------------------------------*/
530 void
BuildResources(nw::demo::ResourceSet * resourceSet)531 BuildResources(nw::demo::ResourceSet* resourceSet)
532 {
533     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
534     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
535     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
536 
537     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
538     if (result.IsFailure())
539     {
540         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
541     }
542 
543     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(SCENE_NODE_COUNT, &s_DeviceAllocator);
544 
545     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
546     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
547     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
548          modelResource != modelsEnd; ++modelResource)
549     {
550         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
551             &s_DeviceAllocator,
552             (*modelResource)
553         );
554         NW_NULL_ASSERT(node);
555         sceneNodeArray.push_back(node);
556         s_AnimModel = nw::ut::DynamicCast<nw::gfx::SkeletalModel*>(node);
557     }
558 
559     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
560     nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
561     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
562          lightResource != lightsEnd; ++lightResource)
563     {
564         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
565             &s_DeviceAllocator,
566             (*lightResource)
567         );
568         NW_NULL_ASSERT(node);
569         sceneNodeArray.push_back(node);
570     }
571 
572     // 親子付け参照関係を解決
573     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
574 
575     // モデルをシーンに追加
576     nw::gfx::SceneHelper::ForeachRootNodes(
577         sceneNodeArray.Begin(),
578         sceneNodeArray.End(),
579         nw::gfx::AttachNode(s_ModelRoot)
580     );
581 
582     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
583     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
584     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
585         settingResource != settingsEnd; ++settingResource)
586     {
587         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
588             .Resource(*settingResource)
589             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
590 
591         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
592             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
593 
594         NW_NULL_ASSERT(sceneEnvironmentSetting);
595         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
596     }
597 }
598 
599 /*!--------------------------------------------------------------------------*
600   @brief        シーンを初期化します。
601  *---------------------------------------------------------------------------*/
602 void
InitializeScenes()603 InitializeScenes()
604 {
605     s_SkeletalAnimWeight0 = 0.5f;
606     s_SkeletalAnimWeight1 = 0.5f;
607     s_MaterialAnimWeight0 = 0.5f;
608     s_MaterialAnimWeight1 = 0.5f;
609 
610     BuildRootNodes();
611 
612     BuildCameras();
613 
614     NW_FOREACH(const wchar_t* name, MODEL_RESOURCE_FILES)
615     {
616         BuildResources(nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator));
617     }
618 
619     if (s_AnimModel != NULL)
620     {
621         InitializeSkeletalAnim(s_AnimModel);
622         InitializeMaterialAnim(s_AnimModel);
623     }
624 
625     // シーンツリーを巡回して初期化を行います。
626     s_SceneSystem->InitializeScene(s_SceneRoot);
627     s_SceneSystem->UpdateScene();
628 
629     // シーン環境の参照解決を行い設定します。
630     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
631 
632     // カメラを設定します。
633     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
634     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
635     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
636 
637     NW_GL_ASSERT();
638 
639     s_FrameCount = 0;
640 }
641 
642 /*!--------------------------------------------------------------------------*
643   @brief        シーン関連の後始末をします。
644  *---------------------------------------------------------------------------*/
645 void
TerminateScenes()646 TerminateScenes()
647 {
648     nw::gfx::SafeDestroyBranch(s_SceneRoot);
649     nw::demo::SafeCleanupResources(s_Resources);
650     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
651     TerminateAnim();
652 
653     NW_GL_ASSERT();
654 
655     s_Resources.clear();
656     s_SceneEnvironmentSettings.clear();
657     s_ModelRoot = NULL;
658 }
659 
660 /*!--------------------------------------------------------------------------*
661   @brief        シーンを更新します。
662  *---------------------------------------------------------------------------*/
663 void
UpdateScene()664 UpdateScene()
665 {
666     UpdateBlender(s_AnimModel);
667 
668     s_SceneSystem->GetCameraController()->Update();
669 
670     s_SceneSystem->UpdateScene();
671 
672     s_BaseCamera->UpdateCameraMatrix();
673 
674     s_RenderSystem->CalcStereoCamera(s_LeftCamera, s_RightCamera, s_BaseCamera, s_fNearPlane + 5.0f);
675 
676     ++s_FrameCount;
677 }
678 
679 /*!--------------------------------------------------------------------------*
680   @brief        負荷表示やテスト機能の処理をおこないます。
681  *---------------------------------------------------------------------------*/
682 void
ReportDemo()683 ReportDemo()
684 {
685     NW_PROFILE("ReportDemo");
686 
687     // 負荷表示からはこれらの負荷は除きます。
688     s_RenderSystem->SuspendLoadMeter();
689 
690     s_GraphicsDrawing.BeginDrawingString();
691 
692     nw::demo::DebugUtility::DrawLoadMeter(
693         s_RenderSystem,
694         &s_GraphicsDrawing,
695         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
696     );
697 
698     const int dumpPositionX = 10;
699     const int dumpPositionY = 10;
700     s_GraphicsDrawing.DrawString(
701         dumpPositionX,
702         dumpPositionY,
703         "weight: %0.2f %0.2f",
704         s_SkeletalAnimWeight1,
705         s_MaterialAnimWeight1
706     );
707 
708     s_GraphicsDrawing.FlushDrawing();
709 
710     s_RenderSystem->ResumeLoadMeter();
711 }
712 
713 /*!--------------------------------------------------------------------------*
714   @brief        シーンをデモンストレーションします。
715  *---------------------------------------------------------------------------*/
716 void
DemoScene()717 DemoScene()
718 {
719     NW_ASSERT(!s_RenderTargets.empty());
720 
721     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
722 
723     InitializeScenes();
724 
725     NW_LOG("[Animation Blend Demo usage]\n");
726     NW_LOG("up/down   : change material animation blender weight\n");
727     NW_LOG("left/right: change skeletal animation blender weight\n");
728 
729     bool isContinuing = true;
730 
731     while ( isContinuing )
732     {
733         nw::demo::DebugUtility::AdvanceAutoTestFrame();
734 
735         nw::demo::PadFactory::GetPad()->Update();
736 
737         UpdateScene();
738 
739         renderContext->SetActiveCamera(s_BaseCameraIndex);
740         s_RenderSystem->SubmitView(s_SceneSystem);
741 
742         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
743         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
744 
745         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
746         ReportDemo();
747         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
748 
749         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
750 
751         renderContext->ResetState();
752 
753         if (nw::demo::Utility::IsTerminating())
754         {
755             isContinuing = false;
756         }
757     }
758 
759     TerminateScenes();
760 }
761 
762 } // namespace
763 
764 /*!--------------------------------------------------------------------------*
765   @brief        メイン関数です。
766  *---------------------------------------------------------------------------*/
767 void
nnMain()768 nnMain()
769 {
770     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
771 
772     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
773 
774     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, NULL, &s_RenderSystem)
775     {
776         InitializeGraphics();
777 
778         DemoScene();
779 
780         TerminateGraphics();
781     }
782 
783     nw::demo::PadFactory::Finalize();
784 
785     nw::demo::FinalizeGraphicsSystem();
786 }
787