1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ConstraintDemo.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: 19751 $
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 nw::demo::DemoAllocator s_ParticleAllocator;
38 
39 //----------------------------------------
40 // ファイル名の定義です。
41 const wchar_t* FONT_SHADER_FILE_NAME = NW_DEMO_FILE_PATH(L"nwfont_RectDrawerShader.shbin");
42 const wchar_t* FONT_FILE_NAME        = NW_DEMO_FILE_PATH(L"Font.bcfnt");
43 const wchar_t* SKY_SPHERE_FILE_NAME  = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl");
44 
45 const wchar_t* RESOURCE_FILES[] =
46 {
47     NW_DEMO_FILE_PATH(L"Mobile.bcres"),
48     NW_DEMO_FILE_PATH(L"Mobile.bcskla"),
49     NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"),
50     NW_DEMO_FILE_PATH(L"Light.bclgt"),
51 };
52 
53 //----------------------------------------
54 // プロファイル関係
55 const int NW_LOAD_METER_INTERVAL = 60;
56 
57 //----------------------------------------
58 // 描画関係
59 const int RENDER_TARGET_COUNT = 1;
60 typedef nw::ut::FixedSizeArray<nw::gfx::IRenderTarget*, RENDER_TARGET_COUNT> RenderTargetArray;
61 
62 RenderTargetArray s_RenderTargets;
63 nw::demo::SceneSystem*  s_SceneSystem = NULL;
64 nw::demo::RenderSystem* s_RenderSystem = NULL;
65 nw::gfx::ParticleContext* s_ParticleContext = NULL;
66 
67 nw::demo::GraphicsDrawing  s_GraphicsDrawing;
68 
69 //----------------------------------------
70 // リソース関係
71 nw::demo::ResourceArray s_Resources;
72 
73 //----------------------------------------
74 // シーン関係
75 const int SCENE_NODE_COUNT = 4;
76 nw::gfx::SceneNode* s_SceneRoot = NULL;
77 s32 s_FrameCount = 0;
78 nw::gfx::Camera* s_BaseCamera = NULL;
79 nw::gfx::Camera* s_LeftCamera = NULL;
80 nw::gfx::Camera* s_RightCamera = NULL;
81 
82 const s32 s_BaseCameraIndex = 0;
83 
84 bool s_SceneDone = false;
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 //----------------------------------------
94 // アニメーション関係
95 const int MAX_ANIM_OBJECTS = 2;
96 nw::ut::FixedSizeArray<nw::gfx::AnimObject*, MAX_ANIM_OBJECTS> s_AnimObjects;
97 
98 const int ANIMATION_RESOURCES_COUNT = 4;
99 const int ANIMATION_TARGETS_COUNT = 8;
100 
101 nw::ut::FixedSizeArray<nw::gfx::ResGraphicsFile, ANIMATION_RESOURCES_COUNT> s_ResAnims;
102 nw::ut::FixedSizeArray<nw::gfx::SceneObject*, ANIMATION_TARGETS_COUNT> s_AnimTargets;
103 
104 nw::gfx::BaseAnimEvaluator* s_MainEvaluator = NULL;
105 
106 struct AnimBindingTable
107 {
108     const char* targetName;
109     const char* animName;
110     nw::demo::Utility::AnimationType animType;
111 };
112 
113 const AnimBindingTable ANIM_BINDING_TABLE[] =
114 {
115     { "Toy_Mobile", "Toy_Mobile", nw::demo::Utility::SKELETAL_ANIMATION },
116     { "pointLight1", "pointLight1", nw::demo::Utility::LIGHT_ANIMATION }
117 };
118 
119 //----------------------------------------
120 // パーティクル関係
121 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL;
122 const int EMITTER_COUNT = 2;
123 const int MODEL_COUNT = 2;
124 nw::demo::FlushCache* s_FlushCache;
125 
126 
127 typedef nw::ut::FixedSizeArray<nw::gfx::ParticleModel*, MODEL_COUNT> ParticleMdlArray;
128 ParticleMdlArray s_ParticleModels;
129 
130 
131 //----------------------------------------
132 // コンストレイン関係
133 nw::gfx::SkeletalModel* s_SkeletalModel = NULL;
134 int s_BoneIdx = -1;
135 
136 typedef nw::ut::FixedSizeArray<nw::gfx::ParticleEmitter*, EMITTER_COUNT> EmitterArray;
137 EmitterArray s_Emitters;
138 
139 nw::gfx::Light* s_Light = NULL;
140 
141 /*!--------------------------------------------------------------------------*
142   @brief        コールバックコンストレインの関数オブジェクトです。
143 
144   他のコールバックについては、関数リファレンスの「高度な機能」をご覧ください。
145  *---------------------------------------------------------------------------*/
146 class CallbackConstraint : public nw::gfx::Skeleton::CalculateMatrixSlot
147 {
148 public:
149     //! @brief コンストラクタです。
150     //!
151     //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に
152     //! オブジェクトが削除されることはありません。
153     //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。
154     //!
155     //! @param[in] allocator 対象オブジェクトの配列を確保するためのアロケータです。
CallbackConstraint(nw::os::IAllocator * allocator)156     CallbackConstraint(nw::os::IAllocator* allocator)
157     : nw::gfx::Skeleton::CalculateMatrixSlot(allocator),
158       m_ConstrainedObjects(allocator),
159       m_Skeleton(NULL),
160       m_BoneIdx(0)
161     {}
162 
163     //! @brief コンストラクタです。
164     //!
165     //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に
166     //! オブジェクトが削除されることはありません。
167     //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。
168     //!
169     //! @param[in] maxConstrainedCount 拘束されるオブジェクトの最大数です。
170     //! @param[in] allocator      拘束されるオブジェクトの配列を確保するためのアロケータです。
CallbackConstraint(size_t maxConstrainedCount,nw::os::IAllocator * allocator)171     CallbackConstraint(size_t maxConstrainedCount, nw::os::IAllocator* allocator)
172     : nw::gfx::Skeleton::CalculateMatrixSlot(allocator),
173       m_ConstrainedObjects(maxConstrainedCount, allocator),
174       m_Skeleton(NULL),
175       m_BoneIdx(0)
176     {}
177 
178     //! @brief 拘束されるオブジェクトを追加します。
179     //!
180     //! @param[in] targetObject 追加するオブジェクトです。
181     //!
182     //! @return 追加に成功したら true を返します。
AddConstrainedObject(nw::gfx::TransformNode * constrainedObject)183     bool AddConstrainedObject(nw::gfx::TransformNode* constrainedObject)
184     {
185         constrainedObject->Transform().DisableFlags(
186             nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED);
187         return m_ConstrainedObjects.push_back(constrainedObject);
188     }
189 
190     //! @brief 拘束するオブジェクトとボーンを設定します。
191     //!
192     //! @param[in] skeletalModel 拘束するボーンを持ったスケルタルモデルです。
193     //! @param[in] boneName 拘束するボーンの名前です。
194     //!
195     //! @return 設定に成功したら true を返します。
SetTargetObject(nw::gfx::SkeletalModel * skeletalModel,const char * boneName)196     bool SetTargetObject(
197         nw::gfx::SkeletalModel* skeletalModel,
198         const char* boneName
199     )
200     {
201         nw::gfx::Skeleton* skeleton = skeletalModel->GetSkeleton();
202         int boneIdx = skeleton->GetResSkeleton().GetBonesIndex(boneName);
203         if (boneIdx < 0)
204         {
205             return false;
206         }
207 
208         m_Skeleton = skeleton;
209         m_BoneIdx = boneIdx;
210 
211         return true;
212     }
213 
214     //! @brief コールバック関数です。
Invoke(nw::gfx::Skeleton * skeleton,int boneIdx)215     virtual void Invoke(nw::gfx::Skeleton* skeleton, int boneIdx)
216     {
217         if (skeleton != m_Skeleton || boneIdx != m_BoneIdx)
218         {
219             return;
220         }
221 
222         nw::gfx::Skeleton::MatrixPose& pose = skeleton->WorldMatrixPose();
223 
224         TransformNodeArray::iterator end = m_ConstrainedObjects.end();
225         for (TransformNodeArray::iterator iter = m_ConstrainedObjects.begin() ; iter != end ; ++iter)
226         {
227             (*iter)->WorldMatrix() = *pose.GetMatrix(boneIdx);
228 
229             // ワールド行列を更新したので、逆行列のキャッシュを無効化します。
230             (*iter)->InvalidateInverseWorldMatrix();
231         }
232     }
233 
234 private:
235     typedef nw::ut::MoveArray<nw::gfx::TransformNode*> TransformNodeArray;
236     TransformNodeArray m_ConstrainedObjects;
237     nw::gfx::Skeleton* m_Skeleton;
238     int m_BoneIdx;
239 };
240 
241 CallbackConstraint* s_ConstraintEmitter;
242 
243 /*!--------------------------------------------------------------------------*
244   @brief        グラフィックス関連の初期化を行います。
245  *---------------------------------------------------------------------------*/
246 void
InitializeGraphics()247 InitializeGraphics()
248 {
249     nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator );
250 
251     // renderDescriptionへステレオの設定を行います。
252     nw::demo::RenderSystem::Description renderDescription;
253 
254     renderDescription.reusableCommandBufferSize = 0x100000;
255     renderDescription.reusableCommandRequestCount      = 512;
256     renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
257 
258     s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription);
259 
260     s_GraphicsDrawing.SetScreenSize(
261         renderDescription.lowerScreenDescription.width,
262         renderDescription.lowerScreenDescription.height
263     );
264 
265     bool result = s_GraphicsDrawing.InitializeFont(&s_DeviceAllocator, FONT_SHADER_FILE_NAME, FONT_FILE_NAME);
266 
267     NN_ASSERTMSG(result, "Fail to load Font.");
268 
269     s_RenderTargets.push_back(
270         nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription)
271     );
272     NW_ASSERT(!s_RenderTargets.empty());
273     s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front());
274 
275     // sceneDescriptionへの標準的な設定はコンストラクタで行われています。
276     nw::demo::SceneSystem::Description sceneDescription;
277     s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription);
278 
279     s_ParticleContext = nw::gfx::ParticleContext::Builder()
280         .Create(&s_DeviceAllocator);
281 
282     s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder()
283         .Create(&s_DeviceAllocator);
284     NW_NULL_ASSERT(s_ParticleSceneUpdater);
285 
286     // デモ用の最遠景モデルをレンダリングシステムに設定します。
287     // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。
288     s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME);
289 
290     NW_GL_ASSERT();
291 }
292 
293 /*!--------------------------------------------------------------------------*
294   @brief        グラフィックス関連の後始末をします。
295  *---------------------------------------------------------------------------*/
296 void
TerminateGraphics()297 TerminateGraphics()
298 {
299     nw::gfx::SafeDestroy(s_LeftCamera);
300 
301     nw::gfx::SafeDestroy(s_RightCamera);
302 
303     nw::gfx::SafeDestroy(s_SceneSystem);
304 
305     nw::gfx::SafeDestroy(s_ParticleSceneUpdater);
306 
307     nw::gfx::SafeDestroy(s_ParticleContext);
308 
309     nw::gfx::SafeDestroyAll(s_RenderTargets);
310 
311     s_GraphicsDrawing.Finalize();
312 
313     nw::gfx::SafeDestroy(s_RenderSystem);
314 
315     NW_GL_ASSERT();
316 }
317 
318 /*!--------------------------------------------------------------------------*
319   @brief        アニメーションの後始末をします。
320  *---------------------------------------------------------------------------*/
321 void
TerminateAnim(void)322 TerminateAnim(void)
323 {
324     for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx)
325     {
326         nw::gfx::SafeDestroy(s_AnimObjects[animIdx]);
327     }
328     s_AnimObjects.clear();
329 }
330 
331 
332 /*!--------------------------------------------------------------------------*
333   @brief        再生ステップを設定します。
334 
335   @param[in]    再生ステップです。
336  *---------------------------------------------------------------------------*/
337 void
SetStepFrame(f32 stepFrame)338 SetStepFrame(f32 stepFrame)
339 {
340     nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
341 
342     nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd();
343     for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i)
344     {
345         nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(*i);
346         if (emitter != NULL)
347         {
348             emitter->ParticleAnimFrameController().SetStepFrame(stepFrame);
349         }
350         else
351         {
352             nw::gfx::ParticleModel* model = nw::ut::DynamicCast<nw::gfx::ParticleModel*>(*i);
353             if (model != NULL)
354             {
355                 model->ParticleAnimFrameController().SetStepFrame(stepFrame);
356             }
357         }
358     }
359 }
360 
361 /*!--------------------------------------------------------------------------*
362   @brief        パーティクルのリセットを行います。
363  *---------------------------------------------------------------------------*/
364 void
ResetParticle()365 ResetParticle()
366 {
367     // パーティクルをリセットします。
368     if ( s_SceneDone )
369     {
370         nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
371 
372         // パーティクルモデルのリセット処理を行います。
373         // GPU処理中はParticleSetsClearをコールすることができません。
374         {
375             ParticleMdlArray::iterator end = s_ParticleModels.end();
376             for (ParticleMdlArray::iterator iter = s_ParticleModels.begin() ; iter != end ; ++iter)
377             {
378                 s_SceneRoot->AttachChild(*iter);
379 
380                 (*iter)->ForeachParticleSet(nw::gfx::ParticleSetsClear());
381                 (*iter)->ParticleAnimFrameController().SetFrame(0);
382             }
383 
384             s_ParticleModels.clear();
385         }
386 
387         // パーティクルエミッタのリセット処理を行います。
388         {
389             EmitterArray::iterator end = s_Emitters.end();
390             for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter)
391             {
392                 (*iter)->Reset();
393             }
394         }
395 
396         // アニメーションをリセットします。
397         for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx)
398         {
399             nw::gfx::BaseAnimEvaluator* evaluator = nw::ut::DynamicCast<nw::gfx::BaseAnimEvaluator*>(s_AnimObjects[animIdx]);
400             if (evaluator)
401             {
402                 evaluator->SetFrame(0);
403             }
404         }
405 
406         s_SceneSystem->InitializeScene(s_SceneRoot);
407         s_SceneDone = false;
408     }
409 }
410 
411 
412 /*!--------------------------------------------------------------------------*
413   @brief        アニメーションのループ再生を行います。
414  *---------------------------------------------------------------------------*/
415 void
LoopAnimation()416 LoopAnimation()
417 {
418     // アニメーションが終了フレームに到達していたらParticleModelのデタッチを行います。
419     if (s_MainEvaluator->GetFrame() >= s_MainEvaluator->GetEndFrame())
420     {
421         nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext();
422 
423         // ParticleModel のデタッチを行います。
424         // GPU処理中はParticleSetsClearをコールすることができないので、
425         // GPU処理終了後にParticleModelのアタッチ、ParticleSetsClearのコール処理を行います。
426         nw::gfx::ParticleModelArray::iterator end = sceneContext->GetParticleModelEnd();
427         for (nw::gfx::ParticleModelArray::iterator iter = sceneContext->GetParticleModelBegin();
428             iter != end; ++iter)
429         {
430             bool isPushed = s_ParticleModels.push_back(*iter);
431             NW_ASSERT(isPushed);
432             s_SceneRoot->DetachChild(*iter);
433         }
434 
435         s_SceneSystem->InitializeScene(s_SceneRoot);
436         s_SceneDone = true;
437     }
438 }
439 
440 /*!--------------------------------------------------------------------------*
441   @brief        ルートノード関連の構築をします。
442  *---------------------------------------------------------------------------*/
443 void
BuildRootNodes()444 BuildRootNodes()
445 {
446     NW_ASSERT(s_SceneRoot == NULL);
447     s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder()
448         .IsFixedSizeMemory(false)
449         .Create(&s_DeviceAllocator);
450     NW_NULL_ASSERT(s_SceneRoot);
451 
452 }
453 
454 /*!--------------------------------------------------------------------------*
455   @brief        カメラ関連の構築をします。
456  *---------------------------------------------------------------------------*/
457 void
BuildCameras()458 BuildCameras()
459 {
460     nw::demo::Utility::CreateStereoCameras(
461         &s_BaseCamera,
462         &s_LeftCamera,
463         &s_RightCamera,
464         &s_DeviceAllocator,
465         nw::math::VEC3(15.0f, 10.0f, 15.0f),
466         nw::math::VEC3(0.0f, 0.0f, 0.0f)
467     );
468 
469     s_SceneRoot->AttachChild(s_BaseCamera);
470     s_SceneSystem->GetCameraController()->Register(s_BaseCamera);
471 }
472 
473 /*!--------------------------------------------------------------------------*
474   @brief        リソース関連の構築をします。
475  *---------------------------------------------------------------------------*/
476 void
BuildResources(nw::demo::ResourceSet * resourceSet)477 BuildResources(nw::demo::ResourceSet* resourceSet)
478 {
479     resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP));
480     resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
481     resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP));
482 
483     nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator);
484     if (result.IsFailure())
485     {
486         NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode());
487     }
488 
489     nw::ut::MoveArray<nw::gfx::SceneNode*> sceneNodeArray(&s_DeviceAllocator);
490 
491     nw::gfx::ResModelArray models = resourceSet->resource.GetModels();
492     nw::gfx::ResModelArray::iterator modelsEnd = models.end();
493     for (nw::gfx::ResModelArray::iterator modelResource = models.begin();
494          modelResource != modelsEnd; ++modelResource)
495     {
496         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
497             &s_DeviceAllocator,
498             (*modelResource)
499         );
500         NW_NULL_ASSERT(node);
501         sceneNodeArray.push_back(node);
502 
503         s_AnimTargets.push_back(node);
504 
505         nw::gfx::SkeletalModel* skeletalModel = nw::ut::DynamicCast<nw::gfx::SkeletalModel*>(node);
506         if (skeletalModel)
507         {
508             s_SkeletalModel = skeletalModel;
509         }
510     }
511 
512     nw::gfx::ResLightArray lights = resourceSet->resource.GetLights();
513     nw::gfx::ResLightArray::iterator lightsEnd = lights.end();
514     for (nw::gfx::ResLightArray::iterator lightResource = lights.begin();
515          lightResource != lightsEnd; ++lightResource)
516     {
517         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
518             &s_DeviceAllocator,
519             (*lightResource)
520         );
521         NW_NULL_ASSERT(node);
522         sceneNodeArray.push_back(node);
523 
524         s_AnimTargets.push_back(node);
525 
526         s_Light = nw::ut::DynamicCast<nw::gfx::Light*>(node);
527     }
528 
529     nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters();
530     for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin();
531         emitterResource != emitters.end(); ++emitterResource)
532     {
533         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
534             &s_DeviceAllocator,
535             (*emitterResource)
536             );
537         NW_NULL_ASSERT(node);
538         sceneNodeArray.push_back(node);
539 
540         s_Emitters.push_back(nw::ut::DynamicCast<nw::gfx::ParticleEmitter*>(node));
541     }
542 
543     nw::gfx::ResCameraArray cameras = resourceSet->resource.GetCameras();
544     nw::gfx::ResCameraArray::iterator camerasEnd = cameras.end();
545     for (nw::gfx::ResCameraArray::iterator cameraResource = cameras.begin();
546          cameraResource != camerasEnd; ++cameraResource)
547     {
548         nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode(
549             &s_DeviceAllocator,
550             (*cameraResource)
551         );
552         NW_NULL_ASSERT(node);
553         sceneNodeArray.push_back(node);
554     }
555 
556     // 親子付け参照関係を解決
557     nw::gfx::SceneHelper::ResolveReference(sceneNodeArray);
558 
559     nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext);
560 
561     // モデルとエミッタをシーンに追加
562     nw::gfx::SceneHelper::ForeachRootNodes(
563         sceneNodeArray.Begin(),
564         sceneNodeArray.End(),
565         nw::gfx::AttachNode(s_SceneRoot)
566     );
567 
568     nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings();
569     nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end();
570     for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin();
571         settingResource != settingsEnd; ++settingResource)
572     {
573         nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder()
574             .Resource(*settingResource)
575             .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator);
576 
577         nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting =
578             nw::ut::DynamicCast<nw::gfx::SceneEnvironmentSetting*>(sceneObject);
579 
580         NW_NULL_ASSERT(sceneEnvironmentSetting);
581         s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting);
582     }
583 }
584 
585 /*!--------------------------------------------------------------------------*
586   @brief        アニメーション関連の構築をします。
587  *---------------------------------------------------------------------------*/
588 void
BuildAnimations()589 BuildAnimations()
590 {
591     NW_FOREACH(AnimBindingTable animBindingTable, ANIM_BINDING_TABLE)
592     {
593         s_AnimObjects.PushBack(
594             nw::demo::Utility::BindAnimationByName(
595                 &s_DeviceAllocator,
596                 s_AnimTargets,
597                 s_ResAnims,
598                 animBindingTable.targetName,
599                 animBindingTable.animName,
600                 animBindingTable.animType,
601                 false)
602             );
603     }
604 
605     // 最初に登録されたアニメーションをループ再生用の基準に設定します。
606     NW_ASSERT(!s_AnimObjects.empty());
607     s_MainEvaluator = nw::ut::DynamicCast<nw::gfx::BaseAnimEvaluator*>(s_AnimObjects[0]);
608     NW_NULL_ASSERT(s_MainEvaluator);
609 }
610 
611 /*!--------------------------------------------------------------------------*
612   @brief        コールバックコンストレインを設定します。
613                 パーティクルエミッタをスケルタルモデルのボーンに拘束します。
614  *---------------------------------------------------------------------------*/
615 void
SetupCallbackConstraint()616 SetupCallbackConstraint()
617 {
618     void* slotMemory = s_DeviceAllocator.Alloc(sizeof(CallbackConstraint));
619     s_ConstraintEmitter =
620         new(slotMemory) CallbackConstraint(s_Emitters.size(), &s_DeviceAllocator);
621 
622     EmitterArray::iterator end = s_Emitters.end();
623     for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter)
624     {
625         // 拘束されるエミッタを関数オブジェクトに追加します。
626         s_ConstraintEmitter->AddConstrainedObject(*iter);
627     }
628 
629     // RocketNozzle ボーンに拘束するよう設定します。
630     bool result = s_ConstraintEmitter->SetTargetObject(s_SkeletalModel, "RocketNozzle");
631     NW_ASSERT(result);
632 
633     // 関数オブジェクトをシグナルに接続します。
634     s_SkeletalModel->GetSkeleton()->PostCalculateMatrixSignal().Connect(s_ConstraintEmitter);
635 }
636 
637 /*!--------------------------------------------------------------------------*
638   @brief        コンストレインを設定します。
639                 ライトをスケルタルモデルのボーンに拘束するための情報を取得します。
640  *---------------------------------------------------------------------------*/
641 void
SetupConstraint()642 SetupConstraint()
643 {
644     // 拘束するボーンのインデックスを取得します。
645     s_BoneIdx = s_SkeletalModel->GetSkeleton()->GetResSkeleton().GetBonesIndex("RocketNozzle");
646 
647     // ライトのワールドマトリックスの計算を無効化します。
648     s_Light->Transform().DisableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED);
649 }
650 
651 /*!--------------------------------------------------------------------------*
652   @brief        シーンを初期化します。
653                 コンストレインのためにコールバックの設定を行います。
654  *---------------------------------------------------------------------------*/
655 void
InitializeScenes()656 InitializeScenes()
657 {
658     BuildRootNodes();
659 
660     BuildCameras();
661 
662     NW_FOREACH(const wchar_t* name, RESOURCE_FILES)
663     {
664         nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator);
665         BuildResources(resourceSet);
666         s_ResAnims.push_back(resourceSet->resource);
667     }
668 
669     NW_NULL_ASSERT(s_SkeletalModel);
670     NW_NULL_ASSERT(s_Light);
671 
672     BuildAnimations();
673 
674     // コンストレインを設定します。
675     SetupCallbackConstraint();
676     SetupConstraint();
677 
678     // 煙のエミッタの開始フレームを設定します。
679     EmitterArray::iterator end = s_Emitters.end();
680     for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter)
681     {
682         if (::std::strcmp((*iter)->GetName(), "MobileSmokeEmitter") == 0)
683         {
684             (*iter)->GetResParticleEmitter().SetEmissionStart(100);
685         }
686     }
687 
688     // シーンツリーを巡回して初期化を行います。
689     s_SceneSystem->InitializeScene(s_SceneRoot);
690     s_SceneSystem->UpdateScene();
691 
692     // シーン環境の参照解決を行い設定します。
693     s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings);
694     nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment();
695     sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera);
696     nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]);
697 
698     NW_GL_ASSERT();
699 
700     s_FrameCount = 0;
701 }
702 
703 /*!--------------------------------------------------------------------------*
704   @brief        シーン関連の後始末をします。
705  *---------------------------------------------------------------------------*/
706 void
TerminateScenes()707 TerminateScenes()
708 {
709     nw::gfx::SafeDestroyBranch(s_SceneRoot);
710     nw::demo::SafeCleanupResources(s_Resources);
711     nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings);
712 
713     TerminateAnim();
714 
715     NW_GL_ASSERT();
716 
717     s_Resources.clear();
718     s_Emitters.clear();
719     s_SceneEnvironmentSettings.clear();
720 
721     s_SceneRoot = NULL;
722     s_SkeletalModel = NULL;
723     s_Light = NULL;
724 }
725 
726 /*!--------------------------------------------------------------------------*
727   @brief        ライトをボーンに拘束します。
728  *---------------------------------------------------------------------------*/
729 void
ConstrainLight()730 ConstrainLight()
731 {
732     nw::gfx::Skeleton::MatrixPose& pose = s_SkeletalModel->GetSkeleton()->WorldMatrixPose();
733     s_Light->WorldMatrix() = *pose.GetMatrix(s_BoneIdx);
734 
735     // ワールド行列を更新したので、逆行列のキャッシュを無効化します。
736     s_Light->InvalidateInverseWorldMatrix();
737 }
738 
739 /*!--------------------------------------------------------------------------*
740   @brief        シーンを更新します。
741  *---------------------------------------------------------------------------*/
742 void
UpdateScene()743 UpdateScene()
744 {
745     s_SceneSystem->GetCameraController()->Update();
746 
747     s_SceneSystem->UpdateScene();
748 
749     s_BaseCamera->UpdateCameraMatrix();
750 
751     ConstrainLight();
752 
753     s_ParticleSceneUpdater->UpdateNode(
754         s_SceneSystem->GetSceneContext(),
755         s_ParticleContext);
756 
757     nw::gfx::ResCameraProjectionUpdater resProjectionUpdater =
758         s_BaseCamera->GetProjectionUpdater()->GetResource();
759 
760     int near = resProjectionUpdater.GetNear();
761 
762     s_RenderSystem->CalcStereoCamera(
763         s_LeftCamera,
764         s_RightCamera,
765         s_BaseCamera,
766         near + 5.0f);
767 
768     ++s_FrameCount;
769 }
770 
771 /*!--------------------------------------------------------------------------*
772   @brief        負荷表示やテスト機能の処理をおこないます。
773  *---------------------------------------------------------------------------*/
774 void
ReportDemo()775 ReportDemo()
776 {
777     NW_PROFILE("ReportDemo");
778 
779     // 負荷表示からはこれらの負荷は除きます。
780     s_RenderSystem->SuspendLoadMeter();
781 
782     s_GraphicsDrawing.BeginDrawingString();
783 
784     nw::demo::DebugUtility::DrawLoadMeter(
785         s_RenderSystem,
786         &s_GraphicsDrawing,
787         (s_FrameCount % NW_LOAD_METER_INTERVAL == 0)
788     );
789     s_GraphicsDrawing.FlushDrawing();
790 
791     s_RenderSystem->ResumeLoadMeter();
792 }
793 
794 /*!--------------------------------------------------------------------------*
795   @brief        シーンをデモンストレーションします。
796  *---------------------------------------------------------------------------*/
797 void
DemoScene()798 DemoScene()
799 {
800     NW_ASSERT(!s_RenderTargets.empty());
801 
802     nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext();
803 
804     InitializeScenes();
805 
806     bool isContinuing = true;
807 
808     while ( isContinuing )
809     {
810         nw::demo::DebugUtility::AdvanceAutoTestFrame();
811 
812         nw::demo::PadFactory::GetPad()->Update();
813 
814         LoopAnimation();
815 
816         UpdateScene();
817 
818         renderContext->SetActiveCamera(s_BaseCameraIndex);
819         s_RenderSystem->SubmitView(s_SceneSystem);
820 
821         s_RenderSystem->SetRenderTarget(s_RenderTargets[0]);
822         s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera);
823 
824         s_RenderSystem->ClearBySkyModel(s_BaseCamera);
825         ReportDemo();
826         s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
827 
828         s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN);
829 
830         renderContext->ResetState();
831 
832         // GPU処理が終了したのち、パーティクルのリセット処理を行います。
833         ResetParticle();
834 
835         if (nw::demo::Utility::IsTerminating())
836         {
837             isContinuing = false;
838         }
839     }
840 
841     TerminateScenes();
842 }
843 
844 } // namespace
845 
846 /*!--------------------------------------------------------------------------*
847   @brief        メイン関数です。
848  *---------------------------------------------------------------------------*/
849 void
nnMain()850 nnMain()
851 {
852     nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
853     nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE);
854 
855     nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
856 
857     NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem)
858     {
859         InitializeGraphics();
860 
861         s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator);
862 
863         DemoScene();
864 
865         nw::ut::SafeDestroy(s_FlushCache);
866 
867         TerminateGraphics();
868     }
869 
870     nw::demo::PadFactory::Finalize();
871 
872     nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator);
873 
874     nw::demo::FinalizeGraphicsSystem();
875 }
876