/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_AnimBinding.h 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: 31311 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_ANIMBINDING_H_ #define NW_GFX_ANIMBINDING_H_ #include #include #include #include #include namespace nw { namespace gfx { class AnimEvaluator; class TransformAnimEvaluator; //--------------------------------------------------------------------------- //! @brief アニメーションの関連付け情報のクラスです。 //! //! AnimObject と AnimGroup を関連付けて、アニメーションの再生を行います。 //--------------------------------------------------------------------------- class AnimBinding : public GfxObject { public: //! アニメーショングループの MoveArray の定義です。 //! //! :private typedef ut::MoveArray AnimGroupArray; //! アニメーションオブジェクトの MoveArray の定義です。 //! //! :private typedef ut::MoveArray AnimObjectArray; //---------------------------------------- //! @name 作成 //@{ //! アニメーションバインディングを構築するクラスです。 class Builder { public: //! コンストラクタです。 Builder() : m_MaxAnimGroups(1), m_MaxAnimObjectsPerGroup(1) {} //! 最大アニメーショングループ数を設定します。 Builder& MaxAnimGroups(int maxAnimGroups) { NW_ASSERT(maxAnimGroups > 0); m_MaxAnimGroups = maxAnimGroups; return *this; } //! @brief アニメーショングループ内での最大アニメーションオブジェクト数を設定します。 //! //! @details 複数のアニメーショングループを持つ場合は、そのうち最大のものを指定してください。 Builder& MaxAnimObjectsPerGroup(int maxAnimObjects) { NW_ASSERT(maxAnimObjects > 0); m_MaxAnimObjectsPerGroup = maxAnimObjects; return *this; } //! @brief 生成時に必要なメモリサイズを取得します。 //! //! メモリサイズは Builder の設定によって変化します。 //! すべての設定が終わった後にこの関数を呼び出してください。 //! //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const { os::MemorySizeCalculator size(alignment); GetMemorySizeInternal(&size); return size.GetSizeWithPadding(alignment); } //! @details :private void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const { os::MemorySizeCalculator& size = *pSize; size += sizeof(AnimBinding); AnimBinding::GetMemorySizeForInitialize(pSize, m_MaxAnimGroups, m_MaxAnimObjectsPerGroup); } //! @brief アニメーションバインディングを生成します。 //! //! @param[in] allocator アロケータです。 //! //! @return 生成されたアニメーションバインディングです。 //! AnimBinding* Create(os::IAllocator* allocator) { void* buf = allocator->Alloc(sizeof(AnimBinding)); if (buf == NULL) { return NULL; } AnimBinding* animBinding = new(buf) AnimBinding(allocator, m_MaxAnimObjectsPerGroup); Result result = animBinding->Initialize(m_MaxAnimGroups, m_MaxAnimObjectsPerGroup); if (result.IsSuccess()) { return animBinding; } else { SafeDestroy(animBinding); return NULL; } } private: int m_MaxAnimGroups; int m_MaxAnimObjectsPerGroup; }; //@} //---------------------------------------- //! @name 基本操作 //@{ //! @brief アニメーションを評価して対象に書き込みます。 //! //! SceneUpdater::UpdateAll から自動的に呼び出されます。 //! 通常は、ユーザーが呼び出す必要はありません。 //! //! @param[in] timing 評価タイミングです。 //! void Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing); //! @brief 設定されたすべてのアニメーションオブジェクトのフレームを更新します。 //! //! SceneUpdater::UpdateAll から自動的に呼び出されます。 //! 通常は、ユーザーが呼び出す必要はありません。 void UpdateFrame() { for (int animObjIdx = 0; animObjIdx < m_AnimObjects.Size(); ++animObjIdx) { if (m_AnimObjects[animObjIdx] != NULL) { m_AnimObjects[animObjIdx]->UpdateFrame(); } } } //@} //---------------------------------------- //! @name 取得/設定 //@{ //! アニメーショングループ数を取得します。 int GetAnimGroupCount() const { return m_AnimGroups.Size(); } //! アニメーショングループを取得します。 const AnimGroup* GetAnimGroup(int groupIdx) const { NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size()); return m_AnimGroups[groupIdx]; } //! アニメーショングループを取得します。 AnimGroup* GetAnimGroup(int groupIdx) { NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size()); return m_AnimGroups[groupIdx]; } //! @brief アニメーショングループ名から、登録されているグループのインデックスを取得します。 //! //! @param[in] animGroupName アニメーショングループ名です。 //! //! @return アニメーショングループのインデックスです。 //! animGroupName に対応するアニメーショングループがない場合は -1 を返します。 //! int GetAnimGroupIndex(const char* animGroupName) const { for (int groupIdx = 0; groupIdx < m_AnimGroups.Size(); ++groupIdx) { if (m_AnimGroups[groupIdx] != NULL && ::std::strcmp(m_AnimGroups[groupIdx]->GetName(), animGroupName) == 0) { return groupIdx; } } return -1; } //! アニメーショングループを設定します。 void SetAnimGroup(int groupIdx, AnimGroup* animGroup) { NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size()); m_AnimGroups[groupIdx] = animGroup; } //! アニメーションオブジェクトを取得します。 const AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0) const { NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimObjects.Size()); NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup); const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx; return m_AnimObjects[index]; } //! アニメーションオブジェクトを取得します。 AnimObject* GetAnimObject(int groupIdx, int objectIdx = 0) { NW_MINMAXLT_ASSERT(groupIdx, 0, m_AnimGroups.Size()); NW_MINMAXLT_ASSERT(objectIdx, 0, m_AnimObjectCountPerGroup); const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx; return m_AnimObjects[index]; } //! @brief アニメーションオブジェクトを設定します。 //! アニメーションオブジェクトにバインドされたアニメーショングループの名前から、 //! アニメーションバインディング中の設定先グループを決定します。 //! //! @param[in] animObject アニメーションオブジェクトです。 //! アニメーショングループにバインドされている必要があります。 //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。 //! 複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。 //! //! @return 成功すれば true を返します。 //! bool SetAnimObject(AnimObject* animObject, int objectIdx = 0) { const AnimGroup* animGroup = animObject->GetAnimGroup(); NW_NULL_ASSERT(animGroup); return SetAnimObject(animGroup->GetName(), animObject, objectIdx); } //! @brief アニメーションオブジェクトを設定します。 //! //! @param[in] groupIdx アニメーションバインディング中の、バインド対象のグループのインデックスです。 //! @param[in] animObject アニメーションオブジェクトです。 //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。 //! 複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。 //! //! @return 成功すれば true を返します。 //! bool SetAnimObject(int groupIdx, AnimObject* animObject, int objectIdx = 0) { // ここでgroupIdxに入っているのは、対象のグループのインデックス if ((0 <= groupIdx && groupIdx < m_AnimGroups.Size()) && (0 <= objectIdx && objectIdx < m_AnimObjectCountPerGroup)) { const int index = groupIdx * m_AnimObjectCountPerGroup + objectIdx; m_AnimObjects[index] = animObject; return true; } return false; } //! @brief アニメーションオブジェクトを設定します。 //! //! @param[in] animGroupName アニメーショングループ名です。 //! @param[in] animObject アニメーションオブジェクトです。 //! @param[in] objectIdx アニメーショングループについてのアニメーションオブジェクトのindexです。 //! 複数個のアニメーションオブジェクトを一つのグループにバインドする際に指定します。 //! //! @return 成功すれば true を返します。 //! bool SetAnimObject(const char* animGroupName, AnimObject* animObject, int objectIdx = 0) { return SetAnimObject(GetAnimGroupIndex(animGroupName), animObject, objectIdx); } //@} protected: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 //! //! :private AnimBinding( os::IAllocator* allocator, int maxAnimObjects) : GfxObject(allocator) , m_AnimObjectCountPerGroup(maxAnimObjects) { } //! デストラクタです。 //! //! :private virtual ~AnimBinding() { // AnimGroups, AnimObjects共に、中身は生成元で削除します。 // AnimBindingでは参照しているだけなので、何も行いません。 } //@} //! Initialize() の実行に必要なメモリサイズを取得します。 //! //! :private static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimGroups, int maxAnimObjects) { os::MemorySizeCalculator& size = *pSize; const int animObjectCount = maxAnimGroups * maxAnimObjects; size += sizeof(AnimGroup*) * maxAnimGroups; size += sizeof(AnimObject*) * animObjectCount; } //! メンバを初期化します。 //! //! :private Result Initialize(int maxAnimGroups, int maxAnimObjects) { // AnimObjectの個数は、Builderで設定されたAnimObjectsの数 * Groupの数です。 const int animObjectCount = maxAnimGroups * maxAnimObjects; Result result = INITIALIZE_RESULT_OK; { void* memory = GetAllocator().Alloc(sizeof(AnimGroup*) * maxAnimGroups); if (memory == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); m_AnimGroups = AnimGroupArray(memory, maxAnimGroups, &GetAllocator()); } { void* memory = GetAllocator().Alloc(sizeof(AnimObject*) * animObjectCount); if (memory == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); m_AnimObjects = AnimObjectArray(memory, animObjectCount, &GetAllocator()); } for (int animGroupIdx = 0; animGroupIdx < maxAnimGroups; ++animGroupIdx) { m_AnimGroups.PushBackFast(NULL); } for (int animObjectIdx = 0; animObjectIdx < animObjectCount; ++animObjectIdx) { m_AnimObjects.PushBackFast(NULL); } return result; } private: //---------------------------------------- // 評価 // ブレンダを使用しない場合の評価処理です。 // 不要なループを省略し、高速に処理します。 NW_FORCE_INLINE void EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator); NW_FORCE_INLINE void EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator); // ブレンダを使用する場合の評価処理です。 NW_FORCE_INLINE void EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj); NW_FORCE_INLINE void EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj); //!< @details :private NW_FORCE_INLINE void EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator); //!< @details :private NW_FORCE_INLINE void EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag); //!< @details :private AnimGroupArray m_AnimGroups; //!< @details :private AnimObjectArray m_AnimObjects; //!< @details :private const int m_AnimObjectCountPerGroup; //!< @details :private }; } // namespace gfx } // namespace nw #endif // NW_GFX_ANIMBINDING_H_