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