/*---------------------------------------------------------------------------* Project: NintendoWare File: GfxCtrl.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: $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include "../include/SmDef.h" #include "../include/GfxCtrl.h" namespace { /*---------------------------------------------------------------------------* @brief 指定ファイルのロードを行います。 *---------------------------------------------------------------------------*/ bool LoadResources( GfxCtrl::GfxResourceSet* resourceSet, const wchar_t* resourcePath, nw::os::IAllocator* allocator, nw::os::IAllocator* deviceAllocator, GfxCtrl::GfxVramType vramType = GfxCtrl::GFX_CTRL_VRAM_NONE ) { static const int RESOURCE_ALIGNMENT = 128; resourceSet->buffer = nw::demo::Utility::LoadFile( deviceAllocator , resourcePath, RESOURCE_ALIGNMENT ); if (!resourceSet->buffer) { NW_FATAL_ERROR("can not open gfx archive.\n"); } resourceSet->resource = nw::gfx::ResGraphicsFile(&(resourceSet->buffer.front())); if (vramType != GfxCtrl::GFX_CTRL_VRAM_NONE) { // 配置するVRAMを引数で切り替えます。 resourceSet->resource.ForeachTexture(nw::gfx::TextureLocationFlagSetter(vramType | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachIndexStream(nw::gfx::IndexStreamLocationFlagSetter(vramType | GL_NO_COPY_FCRAM_DMP)); resourceSet->resource.ForeachVertexStream(nw::gfx::VertexStreamLocationFlagSetter(vramType | GL_NO_COPY_FCRAM_DMP)); } // ロードしたリソースのセットアップを行い、エラーがあれば出力します。 nw::gfx::Result result = resourceSet->resource.Setup(allocator); if (result.IsFailure()) { NW_WARNING(false ,"Fail to set up model. A result code is 0x%x", result.GetCode()); } return true; } /*---------------------------------------------------------------------------* @brief コンストラクタです。 *---------------------------------------------------------------------------*/ GfxCtrl::GfxCtrl( SmSceneCtrl* sceneCtrl ) : m_GfxSceneCtrl(sceneCtrl), m_SceneRoot(NULL), m_Camera(NULL), m_ResCamera(NULL), m_SmCamera(NULL), m_SmParticle(NULL), m_ParticleContext(NULL), m_ParticleSceneUpdater(NULL), m_SceneEnvSetting(NULL), m_LightAnimation(NULL) { m_ResourcesArray.clear(); m_AnimationArray.clear(); m_SmModelInstArray.clear(); // ルートノードを生成します。 m_SceneRoot = nw::gfx::TransformNode::DynamicBuilder() .IsFixedSizeMemory(false) .Create(m_Allocator); NW_NULL_ASSERT(m_SceneRoot); // SmCamera 生成します。 m_SmCamera = new SmCamera( m_SceneRoot, NULL ); // パーティクルコンテキスト生成します。 m_ParticleContext = nw::gfx::ParticleContext::Builder() .MaxEmission(1000) .Create( m_Allocator ); // パーティクルシーンアップデータ生成します。 m_ParticleSceneUpdater = nw::gfx::ParticleSceneUpdater::Builder() .Create( m_Allocator ); } /*---------------------------------------------------------------------------* @brief デストラクタです。 *---------------------------------------------------------------------------*/ GfxCtrl::~GfxCtrl() { // アニメーションの破棄 for (int animIdx = 0; animIdx < m_AnimationArray.Size(); ++animIdx) { nw::gfx::SafeDestroy(m_AnimationArray[animIdx]); } m_AnimationArray.clear(); // SmModelインスタンスの破棄 for (int modelIdx = 0; modelIdx < m_SmModelInstArray.Size(); ++modelIdx) { SM_SAFE_DELETE(m_SmModelInstArray[modelIdx]); } m_SmModelInstArray.clear(); // パーティクル関連の破棄を行います。 nw::gfx::SafeDestroy(m_ParticleSceneUpdater); nw::gfx::SafeDestroy(m_ParticleContext); // シーンノードをトップノードから破棄を行います。 nw::gfx::SafeDestroyBranch(m_SceneRoot); // リソースを破棄を行います。 nw::demo::SafeCleanupResources(m_ResourcesArray); nw::ut::SafeDestroy(m_SceneEnvSetting); SM_SAFE_DELETE(m_SmCamera); SM_SAFE_DELETE(m_SmParticle); m_ResourcesArray.clear(); } /*---------------------------------------------------------------------------* @brief シーンの初期化を行います。 *---------------------------------------------------------------------------*/ void GfxCtrl::InitializeScene() { } /*---------------------------------------------------------------------------* @brief シーンのトラバースを行います。 *---------------------------------------------------------------------------*/ void GfxCtrl::TraverseScene() { m_GfxSceneCtrl->TraverseScene(m_SceneRoot); } /*---------------------------------------------------------------------------* @brief シーンの更新を行います。 *---------------------------------------------------------------------------*/ void GfxCtrl::Update() { uint i = 0; // パーティクルアップデートを行います。 m_ParticleSceneUpdater->UpdateNode( m_GfxSceneCtrl->GetSceneContext(), m_ParticleContext ); // SmModelのアップデートを行います。 // コンストレインの解決を行います。 for ( i = 0; i < m_SmModelInstArray.size(); i++ ) { m_SmModelInstArray[i]->Update(); } // カメラの更新を行います。 m_SmCamera->UpdateMatrix(); } /*---------------------------------------------------------------------------* @brief SmModelクラスのインスタンスを生成します。 *---------------------------------------------------------------------------*/ SmModel* GfxCtrl::CreateModel( SmModel* parentModel, const wchar_t* resourcePath, GfxVramType vramType ) { NW_NULL_ASSERT( resourcePath ); bool isPushed; NW_UNUSED_VARIABLE(isPushed); GfxCtrl::GfxResourceSet resSet; // リソースのロード、セットアップを行います。 LoadResources( &resSet, resourcePath, m_Allocator, m_DeviceAllocator, vramType ); // SmModel を生成して、必要なデータを設定していきます。 SmModel* pModel = new SmModel(); NW_NULL_ASSERT( pModel ); //------------------------------------------------------------------ // モデルのセットアップを行います。(モデルは1リソース1つのみ対応) nw::gfx::ResModelArray models = resSet.resource.GetModels(); if ( models.size() != 1 ) { NW_FATAL_ERROR("1 Resource is 1 Model"); } // ノード生成します。 nw::gfx::SceneNode* pAddNode = nw::demo::Utility::CreateSceneNode( m_DeviceAllocator, nw::gfx::ResSceneObject((*models.begin()))); // 親子付け参照関係を解決します。 nw::ut::MoveArray sceneNodeArray(m_Allocator); sceneNodeArray.push_back( pAddNode ); nw::gfx::SceneHelper::ResolveReference(sceneNodeArray); // モデルをシーンに追加します。 if ( parentModel ) { // 指定された親ノードに追加します。 parentModel->GetSceneNode()->AttachChild( pAddNode ); pModel->SetSceneNode( parentModel->GetSceneNode(), pAddNode ); } else { // ルートノードに追加します。 m_SceneRoot->AttachChild( pAddNode ); pModel->SetSceneNode( m_SceneRoot, pAddNode ); } // モデル/スケルタルモデルをセットします。 nw::gfx::Model* pGfxModel = nw::ut::DynamicCast(pAddNode); nw::gfx::SkeletalModel* pSkelModel = nw::ut::DynamicCast(pAddNode); pModel->SetModel( pGfxModel, pSkelModel ); if ( !pSkelModel ) goto _anim_end; //------------------------------------------------------------------ // アニメーションのセットアップを行います。 { nw::gfx::ResSkeletalModel resModel = pSkelModel->GetResSkeletalModel(); nw::gfx::ResSkeleton resSkeleton = resModel.GetSkeleton(); int maxBones = resSkeleton.GetBonesCount(); uint resAnimNum = resSet.resource.GetSkeletalAnimsCount(); for ( uint i = 0; i < resAnimNum; i++ ) { nw::anim::ResAnim resAnim = resSet.resource.GetSkeletalAnims(i); if (!resAnim.IsValid()){ NW_FATAL_ERROR("Animation is Valid"); } // トランスフォームアニメーション評価を生成します。 nw::gfx::TransformAnimEvaluator* evaluator = nw::gfx::TransformAnimEvaluator::Builder() .AnimData(resAnim) .MaxMembers(maxBones) .AllocCache(true) .Create(m_Allocator); if (!evaluator){ NW_FATAL_ERROR("Animation Evaluator is Valid"); } // SmModel にセットします。 pModel->AddAnimEvaluator( evaluator ); // アニメーションを保持 isPushed = m_AnimationArray.push_back( evaluator ); NW_ASSERT(isPushed); } } _anim_end: //------------------------------------------------------------------ // マテリアルアニメーション { int materialAnimCount = resSet.resource.GetMaterialAnimsCount(); if ( materialAnimCount == 1 ) { nw::anim::ResAnim resAnim = resSet.resource.GetMaterialAnims(0); nw::gfx::AnimGroup* animGroup = pGfxModel->GetMaterialAnimGroup(); if ( !animGroup ) goto _setup_end; int maxMembers = animGroup->GetMemberCount(); nw::gfx::AnimEvaluator* matAnimEvaluator = nw::gfx::AnimEvaluator::Builder() .AnimData(resAnim) .MaxMembers(maxMembers) .AllocCache(true) .Create(m_Allocator); // アニメーションをバインドします。 bool bindResult = matAnimEvaluator->Bind( animGroup ); // アニメーションをモデルに登録します。 if ( bindResult ) { pGfxModel->SetMaterialAnimObject( matAnimEvaluator ); } // アニメーションを保持します。 isPushed = m_AnimationArray.push_back( matAnimEvaluator ); NW_ASSERT(isPushed); } } _setup_end: // 読み込んだリソースを保持します。 isPushed = m_ResourcesArray.push_back( resSet ); NW_ASSERT(isPushed); // SmModel のインスタンスを保持します。 isPushed = m_SmModelInstArray.push_back( pModel ); NW_ASSERT(isPushed); return pModel; } /*---------------------------------------------------------------------------* @brief SmModelをシーンに追加します。 *---------------------------------------------------------------------------*/ bool GfxCtrl::AddModel( SmModel* model ) { // ルートノードに追加します。 m_SceneRoot->AttachChild( model->GetSceneNode() ); model->SetSceneNode( m_SceneRoot, model->GetSceneNode() ); return true; } /*---------------------------------------------------------------------------* @brief パーティクルを生成します。 *---------------------------------------------------------------------------*/ SmParticle* GfxCtrl::CreateParticle( const wchar_t* resourcePath, GfxVramType vramType ) { NW_ASSERT( !m_SmParticle ); NW_NULL_ASSERT( resourcePath ); bool isPushed; NW_UNUSED_VARIABLE(isPushed); GfxCtrl::GfxResourceSet resSet; nw::ut::MoveArray sceneNodeArray(m_Allocator); // リソースのロードを行います。 LoadResources( &resSet, resourcePath, m_Allocator, m_DeviceAllocator, vramType ); // SmParticle を生成して、必要なデータを設定していきます。 m_SmParticle = new SmParticle( m_SceneRoot ); NW_NULL_ASSERT( m_SmParticle ); // ノード生成します。 nw::gfx::ResModelArray models = resSet.resource.GetModels(); nw::gfx::ResModelArray::iterator modelsEnd = models.end(); for (nw::gfx::ResModelArray::iterator modelResource = models.begin(); modelResource != modelsEnd; ++modelResource) { nw::gfx::SceneNode* pAddNode = nw::demo::Utility::CreateSceneNode( m_DeviceAllocator, nw::gfx::ResSceneObject((*modelResource).ptr())); // todo:レイヤIDをここで更新します。 { nw::gfx::ParticleModel* pParticleModel = nw::ut::DynamicCast(pAddNode); pParticleModel->SetLayerId( 6 ); } sceneNodeArray.push_back( pAddNode ); // SmParticleにParticleModelを追加します。 nw::gfx::ParticleModel* pParticleModel = nw::ut::DynamicCast(pAddNode); NW_NULL_ASSERT( pParticleModel ); m_SmParticle->AddParticleModel( pParticleModel ); } // エミッタを生成します。 nw::gfx::ResEmitterArray emitters = resSet.resource.GetEmitters(); nw::gfx::ResEmitterArray::iterator emittersEnd = emitters.end(); for (nw::gfx::ResEmitterArray::iterator emitterResource = emitters.begin(); emitterResource != emittersEnd; ++emitterResource) { nw::gfx::SceneNode* pAddEmitNode = nw::demo::Utility::CreateSceneNode( m_DeviceAllocator, nw::gfx::ResSceneObject((*emitterResource).ptr())); sceneNodeArray.push_back( pAddEmitNode ); // SmParticleにParticleModelを追加します。 nw::gfx::ParticleEmitter* pParticleEmitter = nw::ut::DynamicCast(pAddEmitNode); NW_NULL_ASSERT( pParticleEmitter ); m_SmParticle->AddParticleEmitter( pParticleEmitter ); } /* // マテリアルアニメーション { int materialAnimCount = resSet.resource.GetMaterialAnimsCount(); nw::anim::ResAnim resAnim = resSet.resource.GetMaterialAnims(0); nw::gfx::AnimGroup* animGroup = pGfxModel->GetMaterialAnimGroup(); if ( !animGroup ) goto _setup_end; int maxMembers = animGroup->GetMemberCount(); nw::gfx::AnimEvaluator* matAnimEvaluator = nw::gfx::AnimEvaluator::Builder() .AnimData(resAnim) .MaxMembers(maxMembers) .AllocCache(true) .Create(m_Allocator); // アニメーションをバインドします。 bool bindResult = matAnimEvaluator->Bind( animGroup ); // アニメーションをモデルに登録します。 if ( bindResult ) { pGfxModel->SetMaterialAnimObject( matAnimEvaluator ); } // アニメーションを保持します。 isPushed = m_AnimationArray.push_back( matAnimEvaluator ); NW_ASSERT(isPushed); } */ // パーティクルのオブジェクトの参照解決と初期設定を行います。 nw::gfx::ParticleUtil::SetupParticleObject( &sceneNodeArray, m_ParticleContext ); // 親子付け参照関係を解決します。 nw::gfx::SceneHelper::ResolveReference(sceneNodeArray); // モデルとエミッタをシーンに追加します。 nw::gfx::SceneHelper::ForeachRootNodes( sceneNodeArray.Begin(), sceneNodeArray.End(), nw::gfx::AttachNode( m_SceneRoot ) ); // 読み込んだリソースを保持します。 isPushed = m_ResourcesArray.push_back( resSet ); NW_ASSERT(isPushed); return m_SmParticle; } /*---------------------------------------------------------------------------* @brief ライト/フォグ/シーン環境を設定します。 *---------------------------------------------------------------------------*/ void GfxCtrl::CreateSceneEnvironment( const wchar_t* resourcePath ) { bool isPushed = false; NW_UNUSED_VARIABLE(isPushed); GfxCtrl::GfxResourceSet resSet; nw::gfx::SceneNode* firstLightNode = NULL; // リソースのロードを行います。 LoadResources( &resSet, resourcePath, m_Allocator, m_DeviceAllocator ); // ライトオブジェクトを生成します。 nw::gfx::ResLightArray lights = resSet.resource.GetLights(); nw::gfx::ResLightArray::iterator lightsEnd = lights.end(); for (nw::gfx::ResLightArray::iterator lightResource = lights.begin(); lightResource != lightsEnd; ++lightResource) { nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder() .Resource( nw::gfx::ResSceneObject((*lightResource).ptr()) ) .CreateObject(m_Allocator, m_DeviceAllocator); nw::gfx::SceneNode* node = nw::ut::DynamicCast(sceneObject); // 1つ目のライトを保持して、アニメーションをバインドする。 if ( !firstLightNode ) { firstLightNode = node; } m_SceneRoot->AttachChild(node); } // ライトアニメーションのセットアップを行います。 int lightAnimCount = resSet.resource.GetLightAnimsCount(); if ( lightAnimCount == 1 && firstLightNode ) { nw::anim::ResAnim resAnim = resSet.resource.GetLightAnims(0); nw::gfx::Light* light = nw::ut::DynamicCast(firstLightNode); nw::gfx::AnimGroup* animGroup = light->GetAnimGroup(); if (animGroup) { int maxMembers = animGroup->GetMemberCount(); nw::gfx::AnimEvaluator* lightAnimEvaluator = nw::gfx::AnimEvaluator::Builder() .AnimData(resAnim) .MaxMembers(maxMembers) .AllocCache(true) .Create(m_Allocator); // アニメーションをバインドします。 bool bindResult = lightAnimEvaluator->Bind( animGroup ); // アニメーションをモデルに登録します。 if ( bindResult ) { light->SetAnimObject( lightAnimEvaluator ); } // アニメーションを保持します。 isPushed = m_AnimationArray.push_back( lightAnimEvaluator ); NW_ASSERT(isPushed); if( !m_LightAnimation ) { m_LightAnimation = lightAnimEvaluator; } } } // フォグのセットアップを行います。 { nw::gfx::ResFogArray fogs = resSet.resource.GetFogs(); nw::gfx::ResFogArray::iterator fogsEnd = fogs.end(); for (nw::gfx::ResFogArray::iterator fogResource = fogs.begin(); fogResource != fogsEnd; ++fogResource) { nw::gfx::SceneNode* node = nw::demo::Utility::CreateSceneNode( m_DeviceAllocator, nw::gfx::ResSceneObject(*fogResource) ); NW_NULL_ASSERT(node); m_SceneRoot->AttachChild(node); } } // シーン環境設定のインスタンスを生成します。 if (!m_SceneEnvSetting) { nw::gfx::ResSceneEnvironmentSettingArray settings = resSet.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(m_Allocator, m_DeviceAllocator); nw::gfx::SceneEnvironmentSetting* sceneEnvironmentSetting = nw::ut::DynamicCast(sceneObject); NW_NULL_ASSERT(sceneEnvironmentSetting); m_SceneEnvSetting = sceneEnvironmentSetting;; } } // 読み込んだリソースを保持します。 isPushed = m_ResourcesArray.push_back( resSet ); NW_ASSERT(isPushed); } /*---------------------------------------------------------------------------* @brief カメラを生成します。 *---------------------------------------------------------------------------*/ void GfxCtrl::CreateCamera( const wchar_t* resourcePath ) { NW_ASSERT( !m_ResCamera ); GfxCtrl::GfxResourceSet resSet; // リソースのロードを行います。 LoadResources( &resSet, resourcePath, m_Allocator, m_DeviceAllocator ); // カメラは1リソース1つのみ対応 nw::gfx::ResCameraArray cameras = resSet.resource.GetCameras(); if ( cameras.size() != 1 ) { NW_FATAL_ERROR("1 Resource is 1 Camera"); } { nw::gfx::SceneObject* sceneObject = nw::gfx::SceneBuilder() .Resource( nw::gfx::ResSceneObject( *cameras.begin() ) ) .CreateObject(m_Allocator, m_DeviceAllocator); nw::gfx::SceneNode* node = nw::ut::DynamicCast(sceneObject); // gfxCameraへキャスト m_ResCamera = nw::ut::DynamicCast(node); NW_ASSERT(m_ResCamera); // SmCameraのカメラへ設定 m_SmCamera->SetGxCamera( m_ResCamera ); } // 読み込んだリソースを保持します。 bool isPushed = m_ResourcesArray.push_back( resSet ); NW_UNUSED_VARIABLE(isPushed); NW_ASSERT(isPushed); // カメラアニメーションの生成 { nw::gfx::AnimGroup* animGroup = m_ResCamera->GetAnimGroup(); if (animGroup == NULL) // アニメーション用のアニメーショングループがありません。 { return; } int maxMembers = animGroup->GetMemberCount(); int cameraAnimCount = resSet.resource.GetCameraAnimsCount(); for (int i = 0; i < cameraAnimCount; ++i) { nw::anim::ResAnim resAnim = resSet.resource.GetCameraAnims(i); // トランスフォームアニメーション評価を生成します。 nw::gfx::AnimEvaluator* evaluator = nw::gfx::AnimEvaluator::Builder() .AnimData(resAnim) .MaxMembers(maxMembers) .AllocCache(true) .Create(m_Allocator); if (!evaluator){ NW_FATAL_ERROR("Animation Evaluator is Valid"); } // SmCamera に追加 m_SmCamera->AddAnimEvaluator( evaluator ); // アニメーションを保持 isPushed = m_AnimationArray.push_back( evaluator ); NW_ASSERT(isPushed); } } } } // namespace