/*---------------------------------------------------------------------------* Project: NintendoWare File: ConstraintDemo.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: $ *---------------------------------------------------------------------------*/ #define NW_DEBUG_CHECK_MEMORY_LEAK #include #include #include #include #include #include #include #include namespace { //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; nw::demo::DemoAllocator s_ParticleAllocator; //---------------------------------------- // ファイル名の定義です。 const wchar_t* SKY_SPHERE_FILE_NAME = NW_DEMO_FILE_PATH(L"SkySphere.bcmdl"); const wchar_t* RESOURCE_FILES[] = { NW_DEMO_FILE_PATH(L"Mobile.bcres"), NW_DEMO_FILE_PATH(L"Mobile.bcskla"), NW_DEMO_FILE_PATH(L"SceneEnvironmentSetting.bcenv"), NW_DEMO_FILE_PATH(L"Light.bclgt"), }; //---------------------------------------- // 描画関係 const int RENDER_TARGET_COUNT = 1; typedef nw::ut::FixedSizeArray RenderTargetArray; RenderTargetArray s_RenderTargets; nw::demo::SceneSystem* s_SceneSystem = NULL; nw::demo::RenderSystem* s_RenderSystem = NULL; nw::gfx::ParticleContext* s_ParticleContext = NULL; nw::demo::GraphicsDrawing s_GraphicsDrawing; //---------------------------------------- // リソース関係 nw::demo::ResourceArray s_Resources; //---------------------------------------- // シーン関係 const int SCENE_NODE_COUNT = 4; nw::gfx::SceneNode* s_SceneRoot = NULL; s32 s_FrameCount = 0; nw::gfx::Camera* s_BaseCamera = NULL; nw::gfx::Camera* s_LeftCamera = NULL; nw::gfx::Camera* s_RightCamera = NULL; const s32 s_BaseCameraIndex = 0; bool s_SceneDone = false; //---------------------------------------- // シーン環境関係 const s32 ENVIRONMENT_SETTINGS_COUNT = 1; typedef nw::ut::FixedSizeArray SceneEnvironmentSettingArray; SceneEnvironmentSettingArray s_SceneEnvironmentSettings; //---------------------------------------- // アニメーション関係 const int MAX_ANIM_OBJECTS = 2; nw::ut::FixedSizeArray s_AnimObjects; const int ANIMATION_RESOURCES_COUNT = 4; const int ANIMATION_TARGETS_COUNT = 8; nw::ut::FixedSizeArray s_ResAnims; nw::ut::FixedSizeArray s_AnimTargets; nw::gfx::BaseAnimEvaluator* s_MainEvaluator = NULL; struct AnimBindingTable { const char* targetName; const char* animName; nw::demo::Utility::AnimationType animType; }; const AnimBindingTable ANIM_BINDING_TABLE[] = { { "Toy_Mobile", "Toy_Mobile", nw::demo::Utility::SKELETAL_ANIMATION }, { "pointLight1", "pointLight1", nw::demo::Utility::LIGHT_ANIMATION } }; //---------------------------------------- // パーティクル関係 nw::gfx::ParticleSceneUpdater* s_ParticleSceneUpdater = NULL; const int EMITTER_COUNT = 3; nw::demo::FlushCache* s_FlushCache; typedef nw::ut::FixedSizeArray ParticleMdlArray; ParticleMdlArray s_ParticleModels; //---------------------------------------- // コンストレイン関係 nw::gfx::SkeletalModel* s_SkeletalModel = NULL; int s_BoneIdx = -1; typedef nw::ut::FixedSizeArray EmitterArray; EmitterArray s_Emitters; nw::gfx::Light* s_Light = NULL; /*!--------------------------------------------------------------------------* @brief コールバックコンストレインの関数オブジェクトです。 他のコールバックについては、関数リファレンスの「高度な機能」をご覧ください。 *---------------------------------------------------------------------------*/ class CallbackConstraint : public nw::gfx::Skeleton::CalculateMatrixSlot { public: //! @brief コンストラクタです。 //! //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に //! オブジェクトが削除されることはありません。 //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。 //! //! @param[in] allocator 対象オブジェクトの配列を確保するためのアロケータです。 CallbackConstraint(nw::os::IAllocator* allocator) : nw::gfx::Skeleton::CalculateMatrixSlot(allocator), m_ConstrainedObjects(allocator), m_Skeleton(NULL), m_BoneIdx(0) {} //! @brief コンストラクタです。 //! //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に //! オブジェクトが削除されることはありません。 //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。 //! //! @param[in] maxConstrainedCount 拘束されるオブジェクトの最大数です。 //! @param[in] allocator 拘束されるオブジェクトの配列を確保するためのアロケータです。 CallbackConstraint(size_t maxConstrainedCount, nw::os::IAllocator* allocator) : nw::gfx::Skeleton::CalculateMatrixSlot(allocator), m_ConstrainedObjects(maxConstrainedCount, allocator), m_Skeleton(NULL), m_BoneIdx(0) {} //! @brief 拘束されるオブジェクトを追加します。 //! //! @param[in] targetObject 追加するオブジェクトです。 //! //! @return 追加に成功したら true を返します。 bool AddConstrainedObject(nw::gfx::TransformNode* constrainedObject) { constrainedObject->Transform().DisableFlags( nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); return m_ConstrainedObjects.push_back(constrainedObject); } //! @brief 拘束するオブジェクトとボーンを設定します。 //! //! @param[in] skeletalModel 拘束するボーンを持ったスケルタルモデルです。 //! @param[in] boneName 拘束するボーンの名前です。 //! //! @return 設定に成功したら true を返します。 bool SetTargetObject( nw::gfx::SkeletalModel* skeletalModel, const char* boneName ) { nw::gfx::Skeleton* skeleton = skeletalModel->GetSkeleton(); int boneIdx = skeleton->GetResSkeleton().GetBonesIndex(boneName); if (boneIdx < 0) { return false; } m_Skeleton = skeleton; m_BoneIdx = boneIdx; return true; } //! @brief コールバック関数です。 virtual void Invoke(nw::gfx::Skeleton* skeleton, int boneIdx) { if (skeleton != m_Skeleton || boneIdx != m_BoneIdx) { return; } nw::gfx::Skeleton::MatrixPose& pose = skeleton->WorldMatrixPose(); TransformNodeArray::iterator end = m_ConstrainedObjects.end(); for (TransformNodeArray::iterator iter = m_ConstrainedObjects.begin() ; iter != end ; ++iter) { (*iter)->WorldMatrix() = *pose.GetMatrix(boneIdx); // ワールド行列を更新したので、逆行列のキャッシュを無効化します。 (*iter)->InvalidateInverseWorldMatrix(); } } protected: typedef nw::ut::MoveArray TransformNodeArray; TransformNodeArray m_ConstrainedObjects; nw::gfx::Skeleton* m_Skeleton; int m_BoneIdx; }; /*!--------------------------------------------------------------------------* @brief リソースのトランスフォームに基づいた コールバックコンストレインの関数オブジェクトです。 *---------------------------------------------------------------------------*/ class CallbackResourceBasedConstraint : public CallbackConstraint { public: //! @brief コンストラクタです。 //! //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に //! オブジェクトが削除されることはありません。 //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。 //! //! @param[in] allocator 対象オブジェクトの配列を確保するためのアロケータです。 CallbackResourceBasedConstraint(nw::os::IAllocator* allocator) : CallbackConstraint(allocator) {} //! @brief コンストラクタです。 //! //! 下記のコンストラクタで NULL を渡せば、ノードのデストラクト時に //! オブジェクトが削除されることはありません。 //! 自ら削除する場合は、Destroy(nw::os::IAllocator*) を呼び出してください。 //! //! @param[in] maxConstrainedCount 拘束されるオブジェクトの最大数です。 //! @param[in] allocator 拘束されるオブジェクトの配列を確保するためのアロケータです。 CallbackResourceBasedConstraint(size_t maxConstrainedCount, nw::os::IAllocator* allocator) : CallbackConstraint(maxConstrainedCount, allocator) {} //! @brief 拘束されるオブジェクトを追加します。 //! //! ワールド行列更新を無効化しない点が CallbackConstraint と異なります。 //! //! @param[in] targetObject 追加するオブジェクトです。 //! //! @return 追加に成功したら true を返します。 bool AddConstrainedObject(nw::gfx::TransformNode* constrainedObject) { return m_ConstrainedObjects.push_back(constrainedObject); } //! @brief コールバック関数です。 virtual void Invoke(nw::gfx::Skeleton* skeleton, int boneIdx) { if (skeleton != m_Skeleton || boneIdx != m_BoneIdx) { return; } nw::gfx::Skeleton::MatrixPose& pose = skeleton->WorldMatrixPose(); TransformNodeArray::iterator end = m_ConstrainedObjects.end(); for (TransformNodeArray::iterator iter = m_ConstrainedObjects.begin() ; iter != end ; ++iter) { (*iter)->SetResourceBasedTransform(*pose.GetMatrix(boneIdx)); } } }; CallbackConstraint* s_ConstraintEmitter; CallbackResourceBasedConstraint* s_ResourceBasedConstraintEmitter; /*!--------------------------------------------------------------------------* @brief グラフィックス関連の初期化を行います。 *---------------------------------------------------------------------------*/ void InitializeGraphics() { nw::gfx::CommandCacheManager::SetAllocator( &s_DeviceAllocator ); // renderDescriptionへステレオの設定を行います。 nw::demo::RenderSystem::Description renderDescription; renderDescription.reusableCommandBufferSize = 0x100000; renderDescription.reusableCommandRequestCount = 512; renderDescription.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO; s_RenderSystem = nw::demo::RenderSystem::Create(&s_DeviceAllocator, renderDescription); s_GraphicsDrawing.SetScreenSize( renderDescription.lowerScreenDescription.width, renderDescription.lowerScreenDescription.height ); nw::demo::Utility::InitializeGraphicsDrawing(&s_DeviceAllocator, s_GraphicsDrawing); s_RenderTargets.push_back( nw::demo::Utility::CreateUpperScreenBuffer(&s_DeviceAllocator, renderDescription) ); NW_ASSERT(!s_RenderTargets.empty()); s_RenderSystem->GetRenderContext()->SetRenderTarget(s_RenderTargets.front()); // sceneDescriptionへの標準的な設定はコンストラクタで行われています。 nw::demo::SceneSystem::Description sceneDescription; s_SceneSystem = nw::demo::SceneSystem::Create(&s_DeviceAllocator, sceneDescription); s_ParticleContext = nw::gfx::ParticleContext::Builder() .Create(&s_DeviceAllocator); s_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder() .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_ParticleSceneUpdater); // デモ用の最遠景モデルをレンダリングシステムに設定します。 // gfx のデモでは glClear などを用いずに背景で塗りつぶしを行います。 s_RenderSystem->LoadSkyModel(SKY_SPHERE_FILE_NAME); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief グラフィックス関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateGraphics() { nw::gfx::SafeDestroy(s_LeftCamera); nw::gfx::SafeDestroy(s_RightCamera); nw::gfx::SafeDestroy(s_SceneSystem); nw::gfx::SafeDestroy(s_ParticleSceneUpdater); nw::gfx::SafeDestroy(s_ParticleContext); nw::gfx::SafeDestroyAll(s_RenderTargets); s_GraphicsDrawing.Finalize(); nw::gfx::SafeDestroy(s_RenderSystem); NW_GL_ASSERT(); } /*!--------------------------------------------------------------------------* @brief アニメーションの後始末をします。 *---------------------------------------------------------------------------*/ void TerminateAnim(void) { for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx) { nw::gfx::SafeDestroy(s_AnimObjects[animIdx]); } s_AnimObjects.clear(); } /*!--------------------------------------------------------------------------* @brief 再生ステップを設定します。 @param[in] 再生ステップです。 *---------------------------------------------------------------------------*/ void SetStepFrame(f32 stepFrame) { nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext(); nw::gfx::SceneNodeArray::iterator end = sceneContext->GetSceneNodesEnd(); for (nw::gfx::SceneNodeArray::iterator i = sceneContext->GetSceneNodesBegin(); i != end; ++i) { nw::gfx::ParticleEmitter* emitter = nw::ut::DynamicCast(*i); if (emitter != NULL) { emitter->ParticleAnimFrameController().SetStepFrame(stepFrame); } else { nw::gfx::ParticleModel* model = nw::ut::DynamicCast(*i); if (model != NULL) { model->ParticleAnimFrameController().SetStepFrame(stepFrame); } } } } /*!--------------------------------------------------------------------------* @brief パーティクルのリセットを行います。 *---------------------------------------------------------------------------*/ void ResetParticle() { // パーティクルをリセットします。 if ( s_SceneDone ) { nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext(); // パーティクルモデルのリセット処理を行います。 // GPU処理中はParticleSetsClearをコールすることができません。 { ParticleMdlArray::iterator end = s_ParticleModels.end(); for (ParticleMdlArray::iterator iter = s_ParticleModels.begin() ; iter != end ; ++iter) { s_SceneRoot->AttachChild(*iter); (*iter)->ForeachParticleSet(nw::gfx::ParticleSetsClear()); (*iter)->ParticleAnimFrameController().SetFrame(0); } s_ParticleModels.clear(); } // パーティクルエミッタのリセット処理を行います。 { EmitterArray::iterator end = s_Emitters.end(); for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter) { (*iter)->Reset(); } } // アニメーションをリセットします。 for (int animIdx = 0; animIdx < s_AnimObjects.Size(); ++animIdx) { nw::gfx::BaseAnimEvaluator* evaluator = nw::ut::DynamicCast(s_AnimObjects[animIdx]); if (evaluator) { evaluator->SetFrame(0); } } s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneDone = false; } } /*!--------------------------------------------------------------------------* @brief アニメーションのループ再生を行います。 *---------------------------------------------------------------------------*/ void LoopAnimation() { // アニメーションが終了フレームに到達していたらParticleModelのデタッチを行います。 if (s_MainEvaluator->GetFrame() >= s_MainEvaluator->GetEndFrame()) { nw::gfx::SceneContext* sceneContext = s_SceneSystem->GetSceneContext(); // ParticleModel のデタッチを行います。 // GPU処理中はParticleSetsClearをコールすることができないので、 // GPU処理終了後にParticleModelのアタッチ、ParticleSetsClearのコール処理を行います。 nw::gfx::ParticleModelArray::iterator end = sceneContext->GetParticleModelEnd(); for (nw::gfx::ParticleModelArray::iterator iter = sceneContext->GetParticleModelBegin(); iter != end; ++iter) { bool isPushed = s_ParticleModels.push_back(*iter); NW_ASSERT(isPushed); s_SceneRoot->DetachChild(*iter); } s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneDone = true; } } /*!--------------------------------------------------------------------------* @brief ルートノード関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildRootNodes() { NW_ASSERT(s_SceneRoot == NULL); s_SceneRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(&s_DeviceAllocator); NW_NULL_ASSERT(s_SceneRoot); } /*!--------------------------------------------------------------------------* @brief カメラ関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildCameras() { nw::demo::Utility::CreateStereoCameras( &s_BaseCamera, &s_LeftCamera, &s_RightCamera, &s_DeviceAllocator, nw::math::VEC3(15.0f, 10.0f, 15.0f), nw::math::VEC3(0.0f, 0.0f, 0.0f) ); s_SceneRoot->AttachChild(s_BaseCamera); s_SceneSystem->GetCameraController()->Register(s_BaseCamera); } /*!--------------------------------------------------------------------------* @brief リソース関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildResources(nw::demo::ResourceSet* resourceSet) { resourceSet->resource.ForeachTexture(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMA | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachIndexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachVertexStream(nw::gfx::LocationFlagSetter(NN_GX_MEM_VRAMB | GL_NO_COPY_FCRAM_DMP)); nw::gfx::Result result = resourceSet->resource.Setup(&s_DeviceAllocator); if (result.IsFailure()) { NW_FATAL_ERROR("Fail to set up model. A result code is 0x%x", result.GetCode()); } nw::ut::MoveArray sceneNodeArray(&s_DeviceAllocator); nw::gfx::ResModelArray models = resourceSet->resource.GetModels(); nw::gfx::ResModelArray::iterator modelsEnd = models.end(); for (nw::gfx::ResModelArray::iterator modelResource = models.begin(); modelResource != modelsEnd; ++modelResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*modelResource) ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); s_AnimTargets.push_back(node); nw::gfx::SkeletalModel* skeletalModel = nw::ut::DynamicCast(node); if (skeletalModel) { s_SkeletalModel = skeletalModel; } } nw::gfx::ResLightArray lights = resourceSet->resource.GetLights(); nw::gfx::ResLightArray::iterator lightsEnd = lights.end(); for (nw::gfx::ResLightArray::iterator lightResource = lights.begin(); lightResource != lightsEnd; ++lightResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*lightResource) ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); s_AnimTargets.push_back(node); s_Light = nw::ut::DynamicCast(node); } nw::gfx::ResEmitterArray emitters = resourceSet->resource.GetEmitters(); for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin(); emitterResource != emitters.end(); ++emitterResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*emitterResource) ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); s_Emitters.push_back(nw::ut::DynamicCast(node)); } nw::gfx::ResCameraArray cameras = resourceSet->resource.GetCameras(); nw::gfx::ResCameraArray::iterator camerasEnd = cameras.end(); for (nw::gfx::ResCameraArray::iterator cameraResource = cameras.begin(); cameraResource != camerasEnd; ++cameraResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( &s_DeviceAllocator, (*cameraResource) ); NW_NULL_ASSERT(node); sceneNodeArray.push_back(node); } // 親子付け参照関係を解決 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray); nw::gfx::ParticleUtil::SetupParticleObject(&sceneNodeArray, s_ParticleContext); // モデルとエミッタをシーンに追加 nw::gfx::SceneHelper::ForeachRootNodes( sceneNodeArray.Begin(), sceneNodeArray.End(), nw::gfx::AttachNode(s_SceneRoot) ); nw::gfx::ResSceneEnvironmentSettingArray settings = resourceSet->resource.GetSceneEnvironmentSettings(); nw::gfx::ResSceneEnvironmentSettingArray::iterator settingsEnd = settings.end(); for (nw::gfx::ResSceneEnvironmentSettingArray::iterator settingResource = settings.begin(); settingResource != settingsEnd; ++settingResource) { nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder() .Resource(*settingResource) .CreateObject(&s_DeviceAllocator, &s_DeviceAllocator); nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting = nw::ut::DynamicCast(sceneObject); NW_NULL_ASSERT(sceneEnvironmentSetting); s_SceneEnvironmentSettings.push_back(sceneEnvironmentSetting); } } /*!--------------------------------------------------------------------------* @brief アニメーション関連の構築をします。 *---------------------------------------------------------------------------*/ void BuildAnimations() { NW_FOREACH(AnimBindingTable animBindingTable, ANIM_BINDING_TABLE) { s_AnimObjects.PushBack( nw::demo::Utility::BindAnimationByName( &s_DeviceAllocator, s_AnimTargets, s_ResAnims, animBindingTable.targetName, animBindingTable.animName, animBindingTable.animType, false) ); } // 最初に登録されたアニメーションをループ再生用の基準に設定します。 NW_ASSERT(!s_AnimObjects.empty()); s_MainEvaluator = nw::ut::DynamicCast(s_AnimObjects[0]); NW_NULL_ASSERT(s_MainEvaluator); } /*!--------------------------------------------------------------------------* @brief コールバックコンストレインを設定します。 パーティクルエミッタをスケルタルモデルのボーンに拘束します。 *---------------------------------------------------------------------------*/ void SetupCallbackConstraint() { void* slotMemory = s_DeviceAllocator.Alloc(sizeof(CallbackConstraint)); s_ConstraintEmitter = new(slotMemory) CallbackConstraint(s_Emitters.size(), &s_DeviceAllocator); EmitterArray::iterator end = s_Emitters.end(); for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter) { if ( ::std::strcmp( (*iter)->GetName(), "LineEffectEmitter") == 0 ) { // "LineEffectEmitter" は SetupCallbackResourceBasedConstraint() でコンストレインを設定するので // ここでは除外します。 continue; } // 拘束されるエミッタを関数オブジェクトに追加します。 s_ConstraintEmitter->AddConstrainedObject(*iter); } // RocketNozzle ボーンに拘束するよう設定します。 bool result = s_ConstraintEmitter->SetTargetObject(s_SkeletalModel, "RocketNozzle"); NW_ASSERT(result); // 関数オブジェクトをシグナルに接続します。 s_SkeletalModel->GetSkeleton()->PostCalculateMatrixSignal().Connect(s_ConstraintEmitter); } /*!--------------------------------------------------------------------------* @brief リソースのトランスフォームに基づいたコールバックコンストレインを設定します。 "LineEffectEmitter" をスケルタルモデルのボーンに拘束します。 エミッターのリソースにオフセットなどが設定されている場合に有効です。 *---------------------------------------------------------------------------*/ void SetupCallbackResourceBasedConstraint() { void* slotMemory = s_DeviceAllocator.Alloc(sizeof(CallbackResourceBasedConstraint)); s_ResourceBasedConstraintEmitter = new(slotMemory) CallbackResourceBasedConstraint(1, &s_DeviceAllocator); EmitterArray::iterator end = s_Emitters.end(); for (EmitterArray::iterator iter = s_Emitters.begin() ; iter != end ; ++iter) { if ( ::std::strcmp( (*iter)->GetName(), "LineEffectEmitter") == 0 ) { // 拘束されるエミッタを関数オブジェクトに追加します。 s_ResourceBasedConstraintEmitter->AddConstrainedObject(*iter); } } // Rocket ボーンに拘束するよう設定します。 bool result = s_ResourceBasedConstraintEmitter->SetTargetObject(s_SkeletalModel, "Rocket"); NW_ASSERT(result); // 関数オブジェクトをシグナルに接続します。 s_SkeletalModel->GetSkeleton()->PostCalculateMatrixSignal().Connect(s_ResourceBasedConstraintEmitter); } /*!--------------------------------------------------------------------------* @brief コンストレインを設定します。 ライトをスケルタルモデルのボーンに拘束するための情報を取得します。 *---------------------------------------------------------------------------*/ void SetupConstraint() { // 拘束するボーンのインデックスを取得します。 s_BoneIdx = s_SkeletalModel->GetSkeleton()->GetResSkeleton().GetBonesIndex("RocketNozzle"); // ライトのワールドマトリックスの計算を無効化します。 s_Light->Transform().DisableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); } /*!--------------------------------------------------------------------------* @brief シーンを初期化します。 コンストレインのためにコールバックの設定を行います。 *---------------------------------------------------------------------------*/ void InitializeScenes() { BuildRootNodes(); BuildCameras(); NW_FOREACH(const wchar_t* name, RESOURCE_FILES) { nw::demo::ResourceSet* resourceSet = nw::demo::Utility::LoadResources(s_Resources, name, &s_DeviceAllocator); BuildResources(resourceSet); s_ResAnims.push_back(resourceSet->resource); } NW_NULL_ASSERT(s_SkeletalModel); NW_NULL_ASSERT(s_Light); BuildAnimations(); // コールバックを使用したコンストレインを設定します。 SetupCallbackConstraint(); // コールバックを使用し、リソースのトランスフォームを考慮したコンストレインを設定します。 SetupCallbackResourceBasedConstraint(); // コールバックを使用せずに行なうコンストレインの準備をします。 SetupConstraint(); // シーンツリーを巡回して初期化を行います。 s_SceneSystem->InitializeScene(s_SceneRoot); s_SceneSystem->UpdateScene(); // シーン環境の参照解決を行い設定します。 s_RenderSystem->SetSceneEnvironmentSettings(s_SceneSystem, &s_SceneEnvironmentSettings); nw::gfx::SceneEnvironment& sceneEnvironment = s_RenderSystem->GetSceneEnvironment(); sceneEnvironment.SetCamera(s_BaseCameraIndex, s_BaseCamera); nw::demo::Utility::SetCameraAspectRatio(s_BaseCamera, s_RenderTargets[0]); NW_GL_ASSERT(); s_FrameCount = 0; } /*!--------------------------------------------------------------------------* @brief シーン関連の後始末をします。 *---------------------------------------------------------------------------*/ void TerminateScenes() { nw::gfx::SafeDestroyBranch(s_SceneRoot); nw::demo::SafeCleanupResources(s_Resources); nw::ut::SafeDestroyAll(s_SceneEnvironmentSettings); TerminateAnim(); NW_GL_ASSERT(); s_ResAnims.clear(); s_AnimTargets.clear(); s_Resources.clear(); s_Emitters.clear(); s_SceneEnvironmentSettings.clear(); s_SceneRoot = NULL; s_SkeletalModel = NULL; s_Light = NULL; } /*!--------------------------------------------------------------------------* @brief ライトをボーンに拘束します。 *---------------------------------------------------------------------------*/ void ConstrainLight() { nw::gfx::Skeleton::MatrixPose& pose = s_SkeletalModel->GetSkeleton()->WorldMatrixPose(); s_Light->WorldMatrix() = *pose.GetMatrix(s_BoneIdx); // ワールド行列を更新したので、逆行列のキャッシュを無効化します。 s_Light->InvalidateInverseWorldMatrix(); } /*!--------------------------------------------------------------------------* @brief シーンを更新します。 *---------------------------------------------------------------------------*/ void UpdateScene() { s_SceneSystem->GetCameraController()->Update(); s_SceneSystem->UpdateScene(); s_BaseCamera->UpdateCameraMatrix(); ConstrainLight(); s_ParticleSceneUpdater->UpdateNode( s_SceneSystem->GetSceneContext(), s_ParticleContext); nw::gfx::ResCameraProjectionUpdater resProjectionUpdater = s_BaseCamera->GetProjectionUpdater()->GetResource(); int near = resProjectionUpdater.GetNear(); s_RenderSystem->CalcStereoCamera( s_LeftCamera, s_RightCamera, s_BaseCamera, near + 5.0f); ++s_FrameCount; } /*!--------------------------------------------------------------------------* @brief 負荷表示やテスト機能の処理をおこないます。 *---------------------------------------------------------------------------*/ void ReportDemo() { NW_PROFILE("ReportDemo"); // 負荷表示からはこれらの負荷は除きます。 s_RenderSystem->SuspendLoadMeter(); nw::demo::DebugUtility::CalcLoadMeter(s_RenderSystem); s_GraphicsDrawing.BeginDrawingShape(); nw::demo::DebugUtility::DrawLoadMeter( s_RenderSystem, &s_GraphicsDrawing ); s_GraphicsDrawing.EndDrawingShape(); s_GraphicsDrawing.BeginDrawingString(); nw::demo::DebugUtility::DrawLoadMeterText( s_RenderSystem, &s_GraphicsDrawing ); s_GraphicsDrawing.EndDrawingString(); s_RenderSystem->ResumeLoadMeter(); } /*!--------------------------------------------------------------------------* @brief シーンをデモンストレーションします。 *---------------------------------------------------------------------------*/ void DemoScene() { NW_ASSERT(!s_RenderTargets.empty()); nw::gfx::RenderContext* renderContext = s_RenderSystem->GetRenderContext(); InitializeScenes(); nw::demo::DebugUtility::PostInitializeScenes(); bool isContinuing = true; while ( isContinuing ) { nw::demo::DebugUtility::AdvanceAutoTestFrame(); nw::demo::PadFactory::GetPad()->Update(); LoopAnimation(); UpdateScene(); renderContext->SetActiveCamera(s_BaseCameraIndex); s_RenderSystem->SubmitView(s_SceneSystem); s_RenderSystem->SetRenderTarget(s_RenderTargets[0]); s_RenderSystem->RenderStereoScene(s_LeftCamera, s_RightCamera); s_RenderSystem->ClearBySkyModel(s_BaseCamera); ReportDemo(); s_RenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN); s_RenderSystem->PresentBuffer(nw::demo::UPPER_SCREEN | nw::demo::LOWER_SCREEN | nw::demo::EXTENSION_SCREEN); renderContext->ResetState(); // GPU処理が終了したのち、パーティクルのリセット処理を行います。 ResetParticle(); if (nw::demo::Utility::IsTerminating()) { isContinuing = false; } } nw::demo::DebugUtility::PreTerminateScenes(); TerminateScenes(); } } // namespace /*!--------------------------------------------------------------------------* @brief メイン関数です。 *---------------------------------------------------------------------------*/ void nnMain() { nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator); nw::demo::InitializeDemoAllocator(&s_ParticleAllocator, nw::demo::DEMO_PARTICLE_MEMORY_SIZE); nw::demo::PadFactory::Initialize(&s_DeviceAllocator); NW_DEMO_TEST_LOOP(&s_DeviceAllocator, &s_ParticleAllocator, &s_RenderSystem) { InitializeGraphics(); s_FlushCache = nw::demo::FlushCache::Create(&s_DeviceAllocator); DemoScene(); nw::ut::SafeDestroy(s_FlushCache); TerminateGraphics(); } nw::demo::PadFactory::Finalize(); nw::demo::FinalizeDemoAllocator(&s_ParticleAllocator); nw::demo::FinalizeGraphicsSystem(); }