/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_SkeletalModel.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: 25986 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_SKELETALMODEL_H_ #define NW_GFX_SKELETALMODEL_H_ #include #include #include #include namespace nw { namespace anim { namespace res { class ResAnimGroupMember; } } } namespace nw { namespace gfx { //--------------------------------------------------------------------------- //! @brief 内部に軽量な階層構造を持てるモデルクラスです。 //--------------------------------------------------------------------------- class SkeletalModel : public Model { private: NW_DISALLOW_COPY_AND_ASSIGN(SkeletalModel); public: NW_UT_RUNTIME_TYPEINFO; //! @brief 設定内容です。 struct Description : public Model::Description { Skeleton* sharedSkeleton; //!< 共有するスケルトンです。 //! @brief コンストラクタです。 Description() : sharedSkeleton(NULL) {} }; //! @brief スケルタルモデルを構築するためのクラスです。 //! //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は一部を除いて無視されます。 class Builder { public: //! コンストラクタです。 Builder() {} //! デストラクタです。 ~Builder() {} //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。 //! //! true を指定すると、生成時のみ固定サイズのメモリ確保を行います。 //! //! false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。 Builder& IsFixedSizeMemory(bool isFixedSizeMemory) { m_Description.isFixedSizeMemory = isFixedSizeMemory; return *this; } //! 子の最大数を設定します。 Builder& MaxChildren(int maxChildren) { m_Description.maxChildren = maxChildren; return *this; } //! 管理できるコールバックの最大数を設定します。 Builder& MaxCallbacks(int maxCallbacks) { m_Description.maxCallbacks = maxCallbacks; return *this; } //! @brief マテリアルのバッファを生成する数を設定します。 //! //! 現在の実装では0か1を指定する必要があります。 //! NW_DEPRECATED_FUNCTION(Builder& MaterialBufferCount(int bufferCount)) { NW_UNUSED_VARIABLE(bufferCount); return *this; } //! @brief バッファの生成オプションを設定します。 //! //! //! @param bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 //! SharedMaterialModel が指定された場合、BufferOption は指定することができません。 //! BufferOption が指定された場合は動作を停止します。 //! //! @param[in] bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 //! Builder& BufferOption(bit32 bufferOption) { m_Description.bufferOption = bufferOption; return *this; } //! @brief マテリアルを共有する場合に共有元のモデルを設定します。 //! //! 所有権の移動を行いません。 //! マテリアルを最初に生成したモデルがマテリアルの所有権を持ちます。 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 //! //! @param[in] model 共有するマテリアルを持つモデルです。 //! Builder& SharedMaterialModel(Model* model) { m_Description.sharedMaterialModel = model; return *this; } //! @brief 共有するスケルトンを設定します。 //! //! 所有権の移動を行いません。 //! スケルトンを最初に生成したモデルがスケルトンの所有権を持ちます。 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 //! //! @param[in] sharedSkeleton 共有するスケルトンです。 Builder& SharedSkeleton(Skeleton* sharedSkeleton) { m_Description.sharedSkeleton = sharedSkeleton; return *this; } //! @brief AnimGroup ごとの AnimObject の最大数を指定します。 //! //! IsFixedSizeMemory に false を指定しても、この最大数は有効です。 Builder& MaxAnimObjectsPerGroup(s32 maxAnimObjectCount) { m_Description.maxAnimObjectsPerGroup = maxAnimObjectCount; return *this; } //! @brief アニメーション可能かを設定します。 //! //! false を指定すると AnimBinding の生成を行いません。 //! そのためアニメーションのバインドができなくなりますが、 //! アニメーション更新の処理が行われなくなるため、 //! シーンアップデートのパフォーマンスが向上します。 Builder& IsAnimationEnabled(bool isAnimationEnabled) { m_Description.isAnimationEnabled = isAnimationEnabled; return *this; } //! @brief スケルタルモデルを生成します。 //! //! parent に NULL を指定した場合は、親ノードへの取り付けを行いません。 //! //! @param[in] allocator アロケータです。 //! @param[in] parent 親ノードです。 //! @param[in] resource リソースです。 //! //! @return 生成したスケルタルモデルを返します。 //! SkeletalModel* Create( SceneNode* parent, ResSceneObject resource, os::IAllocator* allocator); //! @brief 生成時に必要なメモリサイズを取得します。 //! //! @param[in] resource リソースです。 size_t GetMemorySize( ResSkeletalModel resModel, size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const { os::MemorySizeCalculator size(alignment); GetMemorySizeInternal(&size, resModel); return size.GetSizeWithPadding(alignment); } //! @details :private void GetMemorySizeInternal( os::MemorySizeCalculator* pSize, ResSkeletalModel resModel) const { os::MemorySizeCalculator& size = *pSize; if (m_Description.sharedSkeleton == NULL) { ResSkeleton resSkeleton = resModel.GetSkeleton(); #ifdef NW_MOVE_ARRAY_CACHE_LINE_ALIGNMENT_ENABLED size.Add( sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(), Skeleton::TransformPose::TransformArray::MEMORY_ALIGNMENT); #else size += sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(); #endif StandardSkeleton::GetMemorySizeInternal( pSize, resSkeleton, m_Description.maxCallbacks); } // モデル作成 size += sizeof(SkeletalModel); SkeletalModel::GetMemorySizeForInitialize(pSize, resModel, m_Description); } private: SkeletalModel::Description m_Description; }; //---------------------------------------- //! @name シーンツリー //@{ //! @brief ビジターを受け付けます。 //! //! @param[in] visitor ビジターです。 //! virtual void Accept(ISceneVisitor* visitor); //@} //---------------------------------------- //! @name リソース //@{ //! スケルタルモデルのリソースを取得します。 ResSkeletalModel GetResSkeletalModel() { return ResDynamicCast(this->GetResSceneObject()); } //! スケルタルモデルのリソースを取得します。 const ResSkeletalModel GetResSkeletalModel() const { return ResDynamicCast(this->GetResSceneObject()); } //@} //---------------------------------------- //! @name スケルトン //@{ //! スケルトンを取得します。 Skeleton* GetSkeleton() { return m_Skeleton.Get(); } //! スケルトンを取得します。 const Skeleton* GetSkeleton() const { return m_Skeleton.Get(); } //! 他モデルのスケルトンを共有している場合は true を返します。 bool IsSharingSkeleton() const { return this->m_SharingSkeleton; } //@} //---------------------------------------- //! @name アニメーション //@{ //! スケルタルアニメーショングループを取得します。 AnimGroup* GetSkeletalAnimGroup() { return m_SkeletalAnimGroup; } //! スケルタルアニメーショングループを取得します。 const AnimGroup* GetSkeletalAnimGroup() const { return m_SkeletalAnimGroup; } //! スケルタルアニメーショングループのアニメーションバインディング中のインデックスを取得します。 int GetSkeletalAnimBindingIndex() const { return m_SkeletalAnimBindingIndex; } //! スケルタルアニメーションオブジェクトを取得します。 const AnimObject* GetSkeletalAnimObject(int objectIndex = 0) const { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); } //! スケルタルアニメーションオブジェクトを取得します。 AnimObject* GetSkeletalAnimObject(int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); } //! スケルタルアニメーションオブジェクトを設定します。 void SetSkeletalAnimObject(AnimObject* animObject, int objectIndex = 0) { NW_NULL_ASSERT(m_AnimBinding); m_AnimBinding->SetAnimObject(m_SkeletalAnimBindingIndex, animObject, objectIndex); } //@} protected: virtual Result Initialize(os::IAllocator* allocator); //! @brief Initialize() の実行に必要なメモリサイズを取得します。 //! //! @details :private static void GetMemorySizeForInitialize( os::MemorySizeCalculator* pSize, ResSkeletalModel resModel, Description description) { // SkeletalModel::Initialize os::MemorySizeCalculator& size = *pSize; Model::GetMemorySizeForInitialize(pSize, resModel, description); // SkeletalModel::CreateSkeletalAnimGroup if (description.isAnimationEnabled) { const int animGroupCount = resModel.GetAnimGroupsCount(); for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx) { anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx); const int targetType = resAnimGroup.GetTargetType(); const bool transformFlag = (resAnimGroup.GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) != 0; if (transformFlag && targetType == anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE) { AnimGroup::Builder() .ResAnimGroup(resAnimGroup) .UseOriginalValue(true) .GetMemorySizeInternal(pSize); break; // 他にスケルタルモデル専用のアニメーショングループがないので } } } } //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 SkeletalModel( os::IAllocator* allocator, ResSkeletalModel resource, GfxPtr& skeleton, bool isSharingSkeleton, const SkeletalModel::Description& description) : Model( allocator, resource, description), m_Skeleton(skeleton), m_SkeletalAnimGroup(NULL), m_SkeletalAnimBindingIndex(-1), m_SharingSkeleton(isSharingSkeleton) { if (!isSharingSkeleton) { m_Skeleton->SetOwnerSkeletalModel(this); } } //! デストラクタです。 virtual ~SkeletalModel() { SafeDestroy(m_SkeletalAnimGroup); } //@} //! スケルタルアニメーション用のアニメーショングループを生成します。 Result CreateSkeletalAnimGroup(os::IAllocator* allocator); //! スケルタルアニメーションに登録するモデルデータのポインタを取得します。 void* GetAnimTargetObject(const anim::ResAnimGroupMember& anim); private: GfxPtr m_Skeleton; AnimGroup* m_SkeletalAnimGroup; int m_SkeletalAnimBindingIndex; bool m_SharingSkeleton; }; } // namespace gfx } // namespace nw #endif // NW_GFX_SKELETALMODEL_H_