/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_Model.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 28677 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_MODEL_H_ #define NW_GFX_MODEL_H_ #include #include #include #include #include #include #include namespace nw { namespace gfx { class IMaterialActivator; //--------------------------------------------------------------------------- //! @brief シーン上に表示されるオブジェクトを表すためのクラスです。 //--------------------------------------------------------------------------- class Model : public TransformNode { private: NW_DISALLOW_COPY_AND_ASSIGN(Model); public: NW_UT_RUNTIME_TYPEINFO; //! @brief 描画時に呼ばれるコールバック用スロットの定義です。 //! //! @sa PreRenderSignal //! @sa PostRenderSignal typedef ut::Signal3 RenderSignal; //! @brief 描画時に呼ばれるコールバック用スロットの定義です。 typedef RenderSignal::SlotType RenderSlot; //! バッファオプションのビットフラグの定義です。 enum BufferOption { //! @details :private FLAG_BUFFER_SHADER_PARAMETER_SHIFT, //! @details :private FLAG_BUFFER_SHADING_PARAMETER_SHIFT, //! @details :private FLAG_BUFFER_MATERIAL_COLOR_SHIFT, //! @details :private FLAG_BUFFER_RASTERIZATION_SHIFT, //! @details :private FLAG_BUFFER_TEXTURE_COORDINATOR_SHIFT, //! @details :private FLAG_BUFFER_TEXTURE_MAPPER_SHIFT, //! @details :private FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER_SHIFT, //! @details :private FLAG_BUFFER_FRAGMENT_LIGHTING_SHIFT, //! @details :private FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE_SHIFT, //! @details :private FLAG_BUFFER_TEXTURE_COMBINER_SHIFT, //! @details :private FLAG_BUFFER_ALPHA_TEST_SHIFT, //! @details :private FLAG_BUFFER_FRAGMENT_OPERATION_SHIFT, //! @details :private FLAG_BUFFER_SCENE_ENVIRONMENT_SHIFT, //! シェーダーパラメータを利用するならば、1になります。 FLAG_BUFFER_SHADER_PARAMETER = 0x1 << FLAG_BUFFER_SHADER_PARAMETER_SHIFT, //! シェーディングパラメータを利用するならば、1になります。 FLAG_BUFFER_SHADING_PARAMETER = 0x1 << FLAG_BUFFER_SHADING_PARAMETER_SHIFT, //! マテリアルカラーを利用するならば、1になります。 FLAG_BUFFER_MATERIAL_COLOR = 0x1 << FLAG_BUFFER_MATERIAL_COLOR_SHIFT, //! ラスタライゼーションを利用するならば、1になります。 FLAG_BUFFER_RASTERIZATION = 0x1 << FLAG_BUFFER_RASTERIZATION_SHIFT, //! テクスチャコーディネータを利用するならば、1になります。 FLAG_BUFFER_TEXTURE_COORDINATOR = 0x1 << FLAG_BUFFER_TEXTURE_COORDINATOR_SHIFT, //! テクスチャマッパーを利用するならば、1になります。 FLAG_BUFFER_TEXTURE_MAPPER = 0x1 << FLAG_BUFFER_TEXTURE_MAPPER_SHIFT, //! 未実装です。 FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER = 0x1 << FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER_SHIFT, //! フラグメントライティングを利用するならば、1になります。 FLAG_BUFFER_FRAGMENT_LIGHTING = 0x1 << FLAG_BUFFER_FRAGMENT_LIGHTING_SHIFT, //! @brief フラグメントライティングテーブルを利用するならば、1になります。 FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE = 0x1 << FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE_SHIFT, //! テクスチャコンバイナを利用するならば、1になります。 FLAG_BUFFER_TEXTURE_COMBINER = 0x1 << FLAG_BUFFER_TEXTURE_COMBINER_SHIFT, //! アルファテストを利用するならば、1になります。 FLAG_BUFFER_ALPHA_TEST = 0x1 << FLAG_BUFFER_ALPHA_TEST_SHIFT, //! フラグメントオペレーションを利用するならば、1になります。 FLAG_BUFFER_FRAGMENT_OPERATION = 0x1 << FLAG_BUFFER_FRAGMENT_OPERATION_SHIFT, //! シーン環境を利用するならば、1になります。 FLAG_BUFFER_SCENE_ENVIRONMENT = 0x1 << FLAG_BUFFER_SCENE_ENVIRONMENT_SHIFT, FLAG_BUFFER_NOT_USE = 0, //!< バッファオプションを使用しません。 //! フラグメントシェーダーを一括指定するためのフラグです。 MULTI_FLAG_BUFFER_FRAGMENT_SHADER = FLAG_BUFFER_FRAGMENT_LIGHTING | FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE | FLAG_BUFFER_TEXTURE_COMBINER | FLAG_BUFFER_ALPHA_TEST, //! マテリアルを一括指定するためのフラグです。 MULTI_FLAG_BUFFER_MATERIAL = FLAG_BUFFER_SHADER_PARAMETER | FLAG_BUFFER_SHADING_PARAMETER | FLAG_BUFFER_MATERIAL_COLOR | FLAG_BUFFER_RASTERIZATION | FLAG_BUFFER_TEXTURE_COORDINATOR | FLAG_BUFFER_TEXTURE_MAPPER | FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER | FLAG_BUFFER_FRAGMENT_LIGHTING | FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE | FLAG_BUFFER_TEXTURE_COMBINER | FLAG_BUFFER_ALPHA_TEST | FLAG_BUFFER_FRAGMENT_OPERATION | FLAG_BUFFER_SCENE_ENVIRONMENT, //! マテリアルのうち、アニメーションする要素を一括指定するためのフラグです。 MULTI_FLAG_ANIMATABLE_MATERIAL = FLAG_BUFFER_MATERIAL_COLOR | FLAG_BUFFER_TEXTURE_COORDINATOR | FLAG_BUFFER_TEXTURE_MAPPER | FLAG_BUFFER_FRAGMENT_OPERATION, //! マテリアルのうち、ライトに関連する要素を一括指定するためのフラグです。 MULTI_FLAG_LIGHTING_MATERIAL = FLAG_BUFFER_SHADING_PARAMETER | FLAG_BUFFER_MATERIAL_COLOR | FLAG_BUFFER_FRAGMENT_LIGHTING | FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE | FLAG_BUFFER_SCENE_ENVIRONMENT }; //! @brief 設定内容です。 struct Description : public TransformNode::Description { bit32 bufferOption; //!< バッファの生成オプションです。 Model* sharedMaterialModel; //!< 共有元のマテリアルを持つモデルです。 //! @brief コンストラクタです。 Description() : bufferOption(0), sharedMaterialModel(NULL) {} }; //--------------------------------------------------------------------------- //! @brief デフォルトのモデル表示フラグ判定関数オブジェクトです。 //--------------------------------------------------------------------------- struct IsVisibleModelDefaultFunctor { bool IsVisible(const nw::gfx::Model* model) { return model->IsVisible() && model->IsEnabledResults(SceneNode::FLAG_IS_VISIBLE); } }; //---------------------------------------- //! @name 作成/破棄 //@{ //! @brief モデルを生成します。 //! //! @param[in] parent 親のノードです。 //! @param[in] resource リソースです。 //! @param[in] description 設定内容です。 //! @param[in] allocator アロケータです。 //! //! @return 生成されたモデルです。 //! static Model* Create( SceneNode* parent, ResSceneObject resource, const Model::Description& description, os::IAllocator* allocator); //! @brief 生成時に必要なメモリサイズを取得します。 //! //! @param[in] resource リソースです。 //! @param[in] description 設定内容です。 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 static size_t GetMemorySize( ResModel resModel, Description description, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) { os::MemorySizeCalculator size(alignment); GetMemorySizeInternal(&size, resModel, description); return size.GetSizeWithPadding(alignment); } //! @details :private static void GetMemorySizeInternal( os::MemorySizeCalculator* pSize, ResModel resModel, Description description) { os::MemorySizeCalculator& size = *pSize; size += sizeof(Model); GetMemorySizeForInitialize(pSize, resModel, description); } //@} //---------------------------------------- //! @name シーンツリー //@{ //! @brief ビジターを受け付けます。 //! //! @param[in] visitor ビジターです。 //! virtual void Accept(ISceneVisitor* visitor); //@} //---------------------------------------- //! @name リソース //@{ //! @brief モデルのリソースを取得します。 ResModel GetResModel() { // return ResDynamicCast(this->GetResSceneObject()); return ResModel(this->GetResSceneObject().ptr()); } //! @brief モデルのリソースを取得します。 const ResModel GetResModel() const { // return ResDynamicCast(this->GetResSceneObject()); return ResModel(this->GetResSceneObject().ptr()); } //! @brief メッシュのリソースの配列を取得します。 //! //! メッシュのリソースはモデルリソースから取得するのではなく、 //! このメソッドを使って取得するようにしてください。 //! //! @return メッシュのリソースの配列を取得します。 //! ResMeshArray GetResMeshes() { if (this->m_MeshBuffers.empty()) { ResModel model = this->GetResModel(); NW_ASSERT(model.IsValid()); return model.GetMeshes(); } return this->m_MeshBuffers; } //! @brief インデックスを指定して MeshNodeVisibility のリソースを取得します。 //! //! MeshNodeVisibility のリソースはモデルリソースから取得するのではなく、 //! このメソッドを使って取得するようにしてください。 //! //! @param[in] idx インデックスです。 //! //! @return MeshNodeVisibility のリソースを取得します。 //! ResMeshNodeVisibility GetResMeshNodeVisibilities(int idx) { if (this->m_MeshNodeVisibilityBuffers.empty()) { ResModel model = this->GetResModel(); NW_ASSERT(model.IsValid()); return model.GetMeshNodeVisibilities(idx); } return ResMeshNodeVisibility( &this->m_MeshNodeVisibilityBuffers[idx] ); } //@} //---------------------------------------- //! @name アニメーション //@{ //! @brief マテリアルアニメーショングループを取得します。 AnimGroup* GetMaterialAnimGroup() { return m_MaterialAnimGroup; } //! @brief マテリアルアニメーショングループを取得します。 const AnimGroup* GetMaterialAnimGroup() const { return m_MaterialAnimGroup; } //! @brief マテリアルアニメーショングループのアニメーションバインディング中のインデックスを取得します。 int GetMaterialAnimBindingIndex() const { return m_MaterialAnimBindingIndex; } //! @brief マテリアルアニメーションオブジェクトを取得します。 const AnimObject* GetMaterialAnimObject(int objectIndex = 0) const { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_MaterialAnimBindingIndex, objectIndex); } //! @brief マテリアルアニメーションオブジェクトを取得します。 AnimObject* GetMaterialAnimObject(int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_MaterialAnimBindingIndex, objectIndex); } //! @brief マテリアルアニメーションオブジェクトを設定します。 //! //! @param[in] animObject 設定するアニメーションオブジェクトです。NULL を指定するとアニメーションを解除します。 void SetMaterialAnimObject(AnimObject* animObject, int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); m_AnimBinding->SetAnimObject(m_MaterialAnimBindingIndex, animObject, objectIndex); } //! @brief ビジビリティアニメーショングループを取得します。 AnimGroup* GetVisibilityAnimGroup() { return m_VisibilityAnimGroup; } //! @brief ビジビリティアニメーショングループを取得します。 const AnimGroup* GetVisibilityAnimGroup() const { return m_VisibilityAnimGroup; } //! @brief ビジビリティアニメーショングループのアニメーションバインディング中のインデックスを取得します。 int GetVisibilityAnimBindingIndex() const { return m_VisibilityAnimBindingIndex; } //! @brief ビジビリティアニメーションオブジェクトを取得します。 const AnimObject* GetVisibilityAnimObject(int objectIndex = 0) const { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_VisibilityAnimBindingIndex, objectIndex); } //! @brief ビジビリティアニメーションオブジェクトを取得します。 AnimObject* GetVisibilityAnimObject(int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_VisibilityAnimBindingIndex, objectIndex); } //! @brief ビジビリティアニメーションオブジェクトを設定します。 //! //! @param[in] animObject 設定するアニメーションオブジェクトです。NULL を指定するとアニメーションを解除します。 void SetVisibilityAnimObject(AnimObject* animObject, int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); m_AnimBinding->SetAnimObject(m_VisibilityAnimBindingIndex, animObject, objectIndex); } //@} //---------------------------------------- //! @name コールバック //@{ //! @brief モデルの描画前に呼び出されるシグナルを取得します。 //! //! このシグナルはライブラリからは呼び出されません。 //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。 //! //! @sa RenderSignal RenderSignal& PreRenderSignal() { return *m_PreRenderSignal; } //! @brief モデルの描画前に呼び出されるシグナルを取得します。 //! //! このシグナルはライブラリからは呼び出されません。 //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。 //! //! @sa RenderSignal const RenderSignal& PreRenderSignal() const { return *m_PreRenderSignal; } //! @brief モデルの描画後に呼び出されるシグナルを取得します。 //! //! このシグナルはライブラリからは呼び出されません。 //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。 //! //! @sa RenderSignal RenderSignal& PostRenderSignal() { return *m_PostRenderSignal; } //! @brief モデルの描画後に呼び出されるシグナルを取得します。 //! //! このシグナルはライブラリからは呼び出されません。 //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。 //! //! @sa RenderSignal const RenderSignal& PostRenderSignal() const { return *m_PostRenderSignal; } // [非推奨] 互換性のために残してありますが、こちらの定義は用いないでください。 //! @details :private typedef gfx::MaterialArray MaterialArray; //@} //---------------------------------------- //! @name マテリアル //@{ //! @brief マテリアルのリストの範囲を表す型の定義です。 typedef std::pair< gfx::MaterialArray::iterator, gfx::MaterialArray::iterator> MaterialRange; //! @brief マテリアルのリストの先頭と末尾を取得します。 MaterialRange GetMaterials() { return std::make_pair( m_Materials.begin(), m_Materials.end()); } //! @brief マテリアルの数を取得します。 int GetMaterialCount() const { return m_Materials.size(); } //! @brief 指定したインデックス番号のマテリアルを取得します。 Material* GetMaterial(int index) { return m_Materials[index]; } //! @brief 指定したインデックス番号のマテリアルを取得します。 const Material* GetMaterial(int index) const { return m_Materials[index]; } //! @brief マテリアルアクティベータを取得します。 const IMaterialActivator* GetMaterialActivator() const { return this->m_MaterialActivator.Get(); } //! @brief マテリアルアクティベータを取得します。 IMaterialActivator* GetMaterialActivator() { return this->m_MaterialActivator.Get(); } //! @brief 所有権の移動を行いマテリアルアクティベータを設定します。 //! モデルクラスが破棄された場合に一緒に破棄されます。 void SetMaterialActivator(IMaterialActivator* materialActivator) { return this->m_MaterialActivator.Reset(materialActivator); } //! @brief 所有権の移動を行わずにマテリアルアクティベータを設定します。 //! ユーザー側でマテリアルアクティベータを管理する場合はこちらで設定してください。 void SetSharedMaterialActivator(IMaterialActivator* materialActivator) { return this->m_MaterialActivator.Reset(materialActivator, false); } //@} //---------------------------------------- //! @name バッファオプション //@{ //! @brief バッファオプションを確認します。 bool CheckBufferOption(bit32 bufferOption) const { return ut::CheckFlag(this->m_BufferOption, bufferOption); } //! @brief バッファオプションを取得します。 bit32 GetBufferOption() const { return this->m_BufferOption; } //@} //---------------------------------------- //! @name マトリクス //@{ //! @brief モデルビューマトリクスを取得します。 math::MTX34& ModelViewMatrix() { return this->m_ModelViewMatrix; } //! @brief モデルビューマトリクスを取得します。 const math::MTX34& ModelViewMatrix() const { return this->m_ModelViewMatrix; } //! @brief 法線マトリクスを取得します。 math::MTX34& NormalMatrix() { return this->m_NormalMatrix; } //! @brief 法線マトリクスを取得します。 const math::MTX34& NormalMatrix() const { return this->m_NormalMatrix; } //! @brief モデルビュー行列と法線用行列を更新します。 NW_INLINE void UpdateModelViewMatrixAndNormalMatrix( const math::MTX34& viewMatrix, bool isModelCoordinate); //@} //---------------------------------------- //! @name レイヤー //@{ //! @brief レイヤーIDを取得します。 u8 GetLayerId() const { return m_LayerId; } //! @brief レイヤーIDを設定します。 void SetLayerId(u8 layerId) { m_LayerId = layerId; } //! @brief メッシュの描画レイヤー値を取得します。 ResMaterial::TranslucencyKind GetRenderLayerId(ResMesh mesh) { NW_ASSERT(mesh.IsValid()); Material* material = this->GetMaterial(mesh.GetMaterialIndex()); ResMaterial shadingParametersResMaterial = material->GetShaderParameterResMaterial(); NW_ASSERT(shadingParametersResMaterial.IsValid()); return shadingParametersResMaterial.GetTranslucencyKind(); } //@} //---------------------------------------- //! @name 描画 //@{ //! @brief モデルを描画するかどうかのフラグを取得します。 bool IsVisible() const { return m_Visible; } //! @brief モデルを描画するかどうかのフラグを設定します。 void SetVisible(bool visible) { m_Visible = visible; } //! @brief メッシュが描画されるかどうかのフラグを取得します。 //! //! メッシュのビジビリティとメッシュノードビジビリティの論理積を返します。 //! //! @param[in] mesh 対象のメッシュです。 //! //! @return メッシュが描画されるかどうかのフラグを返します。 bool IsMeshVisible(ResMesh mesh) { int index = mesh.GetMeshNodeVisibilityIndex(); if (index < 0) { return mesh.IsVisible(); } else { ResMeshNodeVisibility visibility = this->GetResMeshNodeVisibilities(index); NW_ASSERT(visibility.IsValid()); { return visibility.IsVisible() && mesh.IsVisible(); } } } //! @brief 描画ソート用キーのキャッシュを無効化します。 //! //! @sa RenderQueue::Reset void InvalidateRenderKeyCache(); //@} //---------------------------------------- //! @name ユーザーパラメータ //@{ //! @brief ユーザーパラメータを取得します。 template Type GetUserParameter() const { NW_STATIC_ASSERT(sizeof(Type) <= 4); return *reinterpret_cast(&m_UserParameter); } //! @brief ユーザーパラメータを設定します。 template void SetUserParameter(Type parameter) { NW_STATIC_ASSERT(sizeof(Type) <= 4); m_UserParameter = *reinterpret_cast(¶meter); } //@} protected: virtual Result Initialize(os::IAllocator* allocator); //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 Model( os::IAllocator* allocator, ResTransformNode resource, const Model::Description& description) : TransformNode( allocator, resource, description), m_MaterialAnimGroup(NULL), m_MaterialAnimBindingIndex(0), m_VisibilityAnimGroup(NULL), m_VisibilityAnimBindingIndex(0), m_PreRenderSignal(NULL), m_PostRenderSignal(NULL), m_MeshBuffers(NULL, NULL), m_BufferOption(description.bufferOption), m_ModelViewMatrix(math::MTX34::Identity()), m_NormalMatrix(math::MTX34::Identity()), m_LayerId(0), m_OriginalVisibility(true), m_Visible(true), m_SharingMaterial(description.sharedMaterialModel != NULL), m_Description(description), m_UserParameter(0) { SetVisible(ResStaticCast(resource).IsVisible()); } //! デストラクタです。 virtual ~Model() { DestroyResMeshes(&GetAllocator(), m_MeshBuffers); SafeDestroy(this->m_PreRenderSignal); SafeDestroy(this->m_PostRenderSignal); if (!m_SharingMaterial) { SafeDestroyAll(this->m_Materials); } SafeDestroy(this->m_MaterialAnimGroup); SafeDestroy(this->m_VisibilityAnimGroup); } //@} //! @brief Initialize() の実行に必要なメモリサイズを取得します。 //! //! @details :private static void GetMemorySizeForInitialize( os::MemorySizeCalculator* pSize, ResModel resModel, Description description) { NW_ASSERT(description.isFixedSizeMemory); os::MemorySizeCalculator& size = *pSize; TransformNode::GetMemorySizeForInitialize(pSize, resModel, description); // Model::CreateResMeshes const s32 meshesCount = resModel.GetMeshesCount(); const s32 visibilitiesConut = resModel.GetMeshNodeVisibilitiesCount(); size += sizeof(ut::Offset) * meshesCount; size += sizeof(ResMeshData) * meshesCount; size += sizeof(bool) * meshesCount; // Model::CreateResMeshNodeVisibilities size += sizeof(ResMeshNodeVisibilityData) * visibilitiesConut; size += sizeof(bool) * visibilitiesConut; // Model::CreateMaterials if (description.sharedMaterialModel != NULL) { const int materialCount = description.sharedMaterialModel->GetMaterialCount(); size += sizeof(Material*) * materialCount; } else { const s32 bufferCount = (description.bufferOption == 0x0) ? 0 : 1; const s32 materialCount = resModel.GetMaterialsCount(); size += sizeof(Material*) * materialCount; for (int i=0; i < materialCount ; i++) { Material::GetMemorySizeInternal( pSize, resModel.GetMaterials(i), bufferCount, description.bufferOption); } } // Model::CreateCallbacks if (description.maxCallbacks == 0) { RenderSignal::GetMemorySizeForInvalidateSignalInternal(pSize); RenderSignal::GetMemorySizeForInvalidateSignalInternal(pSize); } else { RenderSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks); RenderSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks); } // Model::CreateAnimGroups if (description.isAnimationEnabled) { const int animGroupCount = resModel.GetAnimGroupsCount(); for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx) { anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx); if ( resAnimGroup.GetTargetType() == anim::ResGraphicsAnimGroup::TARGET_TYPE_MATERIAL || resAnimGroup.GetTargetType() == anim::ResGraphicsAnimGroup::TARGET_TYPE_VISIBILITY) { AnimGroup::Builder() .ResAnimGroup(resAnimGroup) .UseOriginalValue(true) .GetMemorySizeInternal(pSize); } } } // Model::CreateMaterialActivator if (description.sharedMaterialModel == NULL) { if (description.bufferOption == 0 || description.bufferOption == FLAG_BUFFER_SCENE_ENVIRONMENT) { SimpleMaterialActivator::GetMemorySizeInternal(pSize); } else { MaterialActivator::GetMemorySizeInternal(pSize); } } } private: //! マテリアルのメンバへの参照を解決します。 void BindMaterialAnim(AnimGroup* animGroup); //! ビジビリティのメンバへの参照を解決します。 void BindVisibilityAnim(AnimGroup* animGroup); //! メッシュリソースを生成します。 Result CreateResMeshes(os::IAllocator* allocator); //! メッシュリソースを破棄します。 void DestroyResMeshes(os::IAllocator* allocator, ResMeshArray resMeshes); //! MeshNodeVisibility リソースを生成します。 Result CreateResMeshNodeVisibilities(os::IAllocator* allocator); //! リソースからマテリアルを生成します。 Result CreateMaterials(os::IAllocator* allocator); //! アニメーショングループを生成します。 Result CreateAnimGroups(os::IAllocator* allocator); //! コールバック関数を生成します。 Result CreateCallbacks(os::IAllocator* allocator); //! マテリアルのアクティベータを生成します。 Result CreateMaterialActivator(os::IAllocator* allocator); //! アニメーションに登録するモデルデータのポインタを取得します。 void* GetAnimTargetObject(const anim::ResAnimGroupMember& anim); //! マテリアルアニメーションで書き換えるメンバへのポインタを取得します。 void* GetMaterialAnimTargetPtr(Material* material, const anim::ResAnimGroupMember& anim, bool isOriginalValue); //! アニメーション対象のマテリアルのインデックスを取得します。 int GetMaterialIndex(const anim::ResAnimGroupMember& anim) const; AnimGroup* m_MaterialAnimGroup; s32 m_MaterialAnimBindingIndex; AnimGroup* m_VisibilityAnimGroup; s32 m_VisibilityAnimBindingIndex; RenderSignal* m_PreRenderSignal; RenderSignal* m_PostRenderSignal; nw::gfx::MaterialArray m_Materials; ResMeshArray m_MeshBuffers; ut::MoveArray m_MeshNodeVisibilityBuffers; bit32 m_BufferOption; math::MTX34 m_ModelViewMatrix; math::MTX34 m_NormalMatrix; GfxPtr m_MaterialActivator; // 以下 4 つのメンバはアライメントを揃えるために集めています。 u8 m_LayerId; bool m_OriginalVisibility; bool m_Visible; bool m_SharingMaterial; ut::MoveArray m_MeshOriginalVisibilities; ut::MoveArray m_MeshNodeOriginalVisibilities; const Model::Description& m_Description; u32 m_UserParameter; }; //---------------------------------------- NW_INLINE void Model::UpdateModelViewMatrixAndNormalMatrix( const math::MTX34& viewMatrix, bool isModelCoordinate) { #if 1 // フラグの判定を行うとより多くのCPU時間を消費する傾向にあるので、判定をせずに全て計算を行うほうを有効にしておきます。 // 累積スケールが1でない場合は法線マトリクスの向きを補正します。 if (isModelCoordinate) { // ViewMatrix * WorldInverseTranspose * ModelNormalVector math::MTX34 worldInvTranspose; math::MTX34InvTranspose(&worldInvTranspose, &this->WorldMatrix()); math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose); } else { if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE)) { // ViewMatrix * WorldNormalVector math::MTX34Copy(&this->NormalMatrix(), &viewMatrix); } else { // ViewMatrix * WorldInverseTranspose * WorldInverse * WorldNormalVector math::MTX34 worldInv; math::MTX34 worldTranspose; math::MTX34 worldInvTranspose; math::MTX34Inverse(&worldInv, this->WorldMatrix()); math::MTX34Transpose(&worldTranspose, &worldInv); math::MTX34Mult(&worldInvTranspose, &worldInv, &worldTranspose); math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose); } } #else // 累積スケールが1でない場合は法線マトリクスの向きを補正します。 if (isModelCoordinate) { if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE)) { // ViewMatrix * WorldMatrix * ModelNormalVector math::MTX34 modelView; math::MTX34Mult(&modelView, &viewMatrix, &this->WorldMatrix()); math::MTX34Copy(&this->NormalMatrix(), &modelView); } else if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_UNIFORM_SCALE)) { // ViewMatrix * InverseScale * WorldMatrix * ModelNormalVector math::MTX34 scaleMtx; math::MTX34 reScaleMtx; f32 scale = 1.0f / this->WorldTransform().Scale().x; scaleMtx.SetupScale(math::VEC3(scale, scale, scale)); math::MTX34Mult(&reScaleMtx, &scaleMtx, &this->WorldMatrix()); math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &reScaleMtx); } else { // ViewMatrix * WorldInverseTranspose * ModelNormalVector math::MTX34 worldInvTranspose; math::MTX34InvTranspose(&worldInvTranspose, &this->WorldMatrix()); math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose); } } else { if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE)) { // ViewMatrix * WorldNormalVector math::MTX34Copy(&this->NormalMatrix(), &viewMatrix); } else if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_UNIFORM_SCALE)) { // ViewMatrix * InverseScale * WorldNormalVector math::MTX34 scaleMtx; f32 scale = 1.0f / this->WorldTransform().Scale().x; scaleMtx.SetupScale(math::VEC3(scale, scale, scale)); math::MTX34Mult(&this->NormalMatrix(), &scaleMtx, &viewMatrix); } else { // ViewMatrix * WorldInverseTranspose * WorldInverse * WorldNormalVector math::MTX34 worldInv; math::MTX34 worldTranspose; math::MTX34 worldInvTranspose; math::MTX34Inverse(&worldInv, this->WorldMatrix()); math::MTX34Transpose(&worldTranspose, &worldInv); math::MTX34Mult(&worldInvTranspose, &worldInv, &worldTranspose); math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose); } #endif } } // namespace gfx } // namespace nw #endif // NW_GFX_MODEL_H_