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