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