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