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