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