/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_AnimInterpolator.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_ANIMINTERPOLATOR_H_ #define NW_GFX_ANIMINTERPOLATOR_H_ #include #include #include namespace nw { namespace gfx { //--------------------------------------------------------------------------- //! @brief 汎用アニメーション評価結果を補間ブレンドするクラスです。 //! //! 登録された全てのアニメーションオブジェクトの結果に重みをかけて、ブレンドした結果を採用します。 //! アニメーションが無いメンバの場合は、モデルのロード時の状態(OriginalValue)をブレンド計算に使用します。 //! //! デフォルトでは、ブレンドの重みは合計が 1.0 となるように正規化されてからブレンドされるので、重みの比率だけが意味を持ちます。 //! 正規化が不要な場合は、 SetNormalizationEnabled() で無効化できます。 //--------------------------------------------------------------------------- class AnimInterpolator : public AnimBlender { public: NW_UT_RUNTIME_TYPEINFO; //---------------------------------------- //! @name 作成 //@{ //! @brief 汎用アニメーション補間を構築するクラスです。 //! //! バージョン 1.0.1 以前の補間法に戻すためには、IsOldMethod か IgnoreNoAnimMember に true を指定してください。 //! //! 1.0.1 以前の補間方法と現在の補間方法の違いの詳細については、アニメーションのドキュメント(高度な機能)を参照ください。 class Builder { public: //! コンストラクタです。 Builder() : m_MaxAnimObjects(2), m_IgnoreNoAnimMember(false) {} //! 最大アニメーションオブジェクト数を設定します。 Builder& MaxAnimObjects(int maxAnimObjects) { NW_ASSERT(maxAnimObjects > 0); m_MaxAnimObjects = maxAnimObjects; return *this; } //! @brief アニメーションが存在しないメンバを無視するかどうかを設定します。 //! //! デフォルトでは、アニメーションが存在しないメンバはバインド時の値がブレンドされます。 //! IgnoreNoAnimMember に true を設定すると、 //! 重みの正規化がメンバ毎に行なわれ、アニメーションが存在しないメンバは重み 0 としてブレンドされます。 //! //! この挙動は バージョン 1.0.1 以前の補間法と同じです。 //! Builder& IgnoreNoAnimMember(bool ignoreNoAnimMember) { m_IgnoreNoAnimMember = ignoreNoAnimMember; 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(AnimInterpolator); AnimInterpolator::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects); } //! @brief 汎用アニメーション補間を生成します。 //! //! @param[in] allocator アロケータです。 //! //! @return 生成された汎用アニメーション補間です。 //! AnimInterpolator* Create(os::IAllocator* allocator) { void* buf = allocator->Alloc(sizeof(AnimInterpolator)); if (buf == NULL) { return NULL; } AnimInterpolator* animInterpolator = new(buf) AnimInterpolator(allocator); Result result = animInterpolator->Initialize(m_MaxAnimObjects, m_IgnoreNoAnimMember); NW_ASSERT(result.IsSuccess()); return animInterpolator; } private: int m_MaxAnimObjects; bool m_IgnoreNoAnimMember; }; //@} //---------------------------------------- //! @name 評価 //@{ //! @brief メンバ単位でアニメーション結果を取得します。 //! //! @param[out] target アニメーション結果を書き込む対象です。 //! @param[in] memberIdx メンバインデックスです。 //! //! @return アニメーション結果を返します。 //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。 //! virtual const anim::AnimResult* GetResult( void* target, int memberIdx) const; //@} //---------------------------------------- //! @name 取得/設定 //@{ //! @brief アニメーションのブレンド重みを取得します。 //! //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。 //! //! @return 重みです。 //! float GetWeight(int animObjIdx) const { NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size()); return m_Weights[animObjIdx]; } //! @brief アニメーションのブレンド重みを設定します。 //! //! ブレンド重みの解釈については、 SetNormalizationEnabled() を参照してください。 //! //! @param[in] animObjIdx アニメーションオブジェクトのインデックスです。 //! @param[in] weight 重みです。 //! @sa SetNormalizationEnabled //! void SetWeight(int animObjIdx, float weight) { NW_MINMAXLT_ASSERT(animObjIdx, 0, m_Weights.Size()); m_Weights[animObjIdx] = weight; m_NormalizedWeights[animObjIdx] = weight; m_IsWeightDirty = true; } //! @brief アニメーションのブレンド重みを正規化するかを設定します。 //! //! true を指定すると、ブレンド重みが合計で 1 になるよう正規化してからブレンドを行います。 //! false を指定すると、SetWeight() で指定された重みがそのままブレンドに使用されますので、 //! 重みの設定に注意してください。 //! //! 正規化処理は、 SetWeight() 実行後の最初のアニメーションブレンド時に 1 度だけ行われます。 //! //! Builder::IsOldMethod で true を指定していると、この設定は無視されます。 //! //! デフォルト値は true です。 void SetNormalizationEnabled(bool enabled){ m_IsWeightNormalizationEnabled = enabled; } //! @brief アニメーションのブレンド重みを正規化するかの設定を取得します。 bool GetNormalizationEnabled() const { return m_IsWeightNormalizationEnabled; } //@} protected: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 //! //! :private AnimInterpolator( os::IAllocator* allocator) : AnimBlender(allocator), m_IsOldMethod(false), m_IsWeightDirty(false), m_IsWeightNormalizationEnabled(true) { } //! デストラクタです。 //! //! :private virtual ~AnimInterpolator() {} //@} //! Initialize() の実行に必要なメモリサイズを取得します。 //! //! :private static void GetMemorySizeForInitialize(os::MemorySizeCalculator* pSize, int maxAnimObjects) { os::MemorySizeCalculator& size = *pSize; AnimBlender::GetMemorySizeForInitialize(pSize, maxAnimObjects); size += sizeof(float) * maxAnimObjects; size += sizeof(float) * maxAnimObjects; } //! @details :private Result Initialize(int maxAnimObjects, bool ignoreNoAnimMember) { Result result = AnimBlender::Initialize(maxAnimObjects); NW_ENSURE_AND_RETURN(result); { void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects); if (memory == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); m_Weights = ut::MoveArray(memory, maxAnimObjects, &GetAllocator()); for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx) { m_Weights.PushBackFast(animObjIdx == 0 ? 1.0f : 0.0f); } } { void* memory = GetAllocator().Alloc(sizeof(float) * maxAnimObjects); if (memory == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); m_NormalizedWeights = ut::MoveArray(memory, maxAnimObjects, &GetAllocator()); for (int animObjIdx = 0; animObjIdx < maxAnimObjects; ++animObjIdx) { m_NormalizedWeights.PushBackFast(animObjIdx == 0 ? 1.0f : 0.0f); } } // TODO: 変数名その他を変更。 m_IsOldMethod = ignoreNoAnimMember; return result; } //! @brief ブレンド重みを正規化します。 //! //! :private void NormalizeWeight() const { float weightSum = 0.0f; float normalizeScale; for (int i = 0; i < m_Weights.Size(); ++i) { weightSum += m_Weights[i]; } normalizeScale = GetAnimWeightNormalizeScale(weightSum); for (int i = 0; i < m_Weights.Size(); ++i) { m_NormalizedWeights[i] = m_Weights[i] * normalizeScale; } m_IsWeightDirty = false; } ut::MoveArray m_Weights; //!< @details :private mutable ut::MoveArray m_NormalizedWeights; //!< @details :private bool m_IsOldMethod; //!< @details :private mutable bool m_IsWeightDirty; //!< @details :private bool m_IsWeightNormalizationEnabled; //!< @details :private }; } // namespace gfx } // namespace nw #endif // NW_GFX_ANIMINTERPOLATOR_H_