/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_AnimEvaluator.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: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include namespace nw { namespace gfx { NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimEvaluator , BaseAnimEvaluator); //---------------------------------------------------------- int AnimEvaluator::GetCacheBufferSizeNeeded() const { return GetCacheBufferSizeNeeded(m_AnimData); } //---------------------------------------------------------- int AnimEvaluator::GetCacheBufferSizeNeeded(const anim::ResAnim& animData) { const int headBytes = anim::AnimResult().GetOffsetToValueBuffer(); int size = 0; const int memberAnimCount = animData.GetMemberAnimSetCount(); for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx) { const anim::ResMemberAnim memberAnim = animData.GetMemberAnimSet(animIdx); const int primBytes = memberAnim.GetPrimitiveSize(); size += ut::RoundUp(headBytes + primBytes, sizeof(bit32)); } return size; } //---------------------------------------------------------- void AnimEvaluator::SetCacheBufferPointers() { const int headBytes = anim::AnimResult().GetOffsetToValueBuffer(); u8* cachePtr = reinterpret_cast(m_CacheBuf); const int memberAnimCount = m_AnimData.GetMemberAnimSetCount(); for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx) { m_CachePtrs[animIdx] = reinterpret_cast(cachePtr); const anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx); const int primBytes = memberAnim.GetPrimitiveSize(); cachePtr += ut::RoundUp(headBytes + primBytes, sizeof(bit32)); } } //---------------------------------------------------------- AnimEvaluator::AnimEvaluator( os::IAllocator* allocator) : BaseAnimEvaluator(allocator, ANIMTYPE_SIMPLE), m_CacheBuf(NULL), m_SharedCache(NULL) { } //---------------------------------------------------------- void AnimEvaluator::GetMemorySizeForInitialize( os::MemorySizeCalculator* pSize, const nw::anim::ResAnim& animData, const int maxMembers, const int maxAnimMembers, bool allocCache) { os::MemorySizeCalculator& size = *pSize; BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, maxMembers, maxAnimMembers); size += sizeof(anim::AnimResult*) * maxAnimMembers; if (allocCache) { size += AnimEvaluator::GetCacheBufferSizeNeeded(animData); } } //---------------------------------------------------------- Result AnimEvaluator::Initialize( const nw::anim::ResAnim& animData, const int maxMembers, const int maxAnimMembers, bool allocCache) { // 親クラスの初期化を通す Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers); NW_ENSURE_AND_RETURN(result); void* memory = GetAllocator().Alloc(sizeof(anim::AnimResult*) * maxAnimMembers); if (memory == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); m_CachePtrs = ut::MoveArray(memory, maxAnimMembers, &GetAllocator()); m_CachePtrs.Resize(animData.GetMemberAnimSetCount()); if (allocCache) { // サイズ0でのAllocを回避する // CreateEmpty~Anim()などを使用した場合に起こりうる if (animData.GetMemberAnimSetCount() != 0) { m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded()); if (m_CacheBuf == NULL) { result |= Result::MASK_FAIL_BIT; } NW_ENSURE_AND_RETURN(result); SetCacheBufferPointers(); } } return result; } //---------------------------------------------------------- Result AnimEvaluator::ForceBindMaterialAnim(AnimGroup* animGroup, const char* materialName) { NW_NULL_ASSERT(materialName); NW_FAILSAFE_IF (std::strcmp(m_AnimData.GetTargetAnimGroupName(), "MaterialAnimation") != 0) { return Result(BIND_RESULT_IRRELEVANT_ANIM_TYPE | Result::MASK_FAIL_BIT); } return TryBindTemplate(animGroup, ReplaceMaterialNameIndexGetterFunctor(materialName)); } //---------------------------------------------------------- const anim::AnimResult* AnimEvaluator::GetResult( void* target, int memberIdx ) const { //----------------------------------------------------------------- // メンバに関連付けられたアニメーションが存在しない場合は // target を変更せずに NULL を返す if (!HasMemberAnim(memberIdx)) { return NULL; } //----------------------------------------------------------------- const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx); const int animIdx = m_BindIndexTable[memberIdx]; if (m_CacheBuf != NULL && !m_IsCacheDirty) { //----------------------------------------------------------------- // キャッシュがあればキャッシュの値を返す if (blendOp != NULL) { return m_CachePtrs[animIdx]; } else { anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx); memberAnim.ApplyCacheForType(target, m_CachePtrs[animIdx]); // ブレンドオペレーションがない場合、返り値は使用されないが // ブレンダに評価したことを伝えるために target を返す return reinterpret_cast(target); } } else { //----------------------------------------------------------------- // アニメーションカーブを評価して対象に書き込む anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx); const void* originalValue = m_AnimGroup->HasOriginalValue() ? m_AnimGroup->GetOriginalValue(memberIdx) : NULL; if (blendOp != NULL) { anim::AnimResult* result = reinterpret_cast(target); bit32 flags = memberAnim.EvaluateResultForType( result->GetValueBuffer(), result->GetFlags(), m_AnimFrameController.GetFrame(), originalValue); result->SetFlags(flags); return result; } else { memberAnim.EvaluateResultForType( target, 0, m_AnimFrameController.GetFrame(), originalValue); // ブレンドオペレーションがない場合、返り値は使用されないが // ブレンダに評価したことを伝えるために target を返す return reinterpret_cast(target); } } } //---------------------------------------------------------- void AnimEvaluator::UpdateCacheNonVirtual() { if (m_IsCacheDirty) { if (m_CacheBuf != NULL && m_IsCacheDirty) { UpdateCacheImpl(); } else if (m_UseSharedCache && m_SharedCache != NULL) { // 共有キャッシュのDirtyフラグは、 // 現在のところアニメを変更したときに手動でtrueを立てるときしか使用しない if (m_SharedCache->IsDirty() || GetFrame() != m_SharedCache->GetFrame() || GetStepFrame() != m_SharedCache->GetStepFrame()) { UpdateCacheImpl(); // 共有キャッシュの情報更新 m_SharedCache->SetFrame(GetFrame()); m_SharedCache->SetStepFrame(GetStepFrame()); m_SharedCache->SetDirtyFlag(false); } } } m_IsCacheDirty = false; } void AnimEvaluator::UpdateCacheImpl() { int animCount = m_AnimData.GetMemberAnimSetCount(); for (int animIdx = 0; animIdx < animCount; ++animIdx) { anim::AnimResult* result = m_CachePtrs[animIdx]; result->ResetFlags(); // バインドされたメンバーがモデルに存在しない場合もあるのでチェック const int memberIdx = m_ReverseBindIndexTable[animIdx]; if (memberIdx == BaseAnimEvaluator::NotFoundIndex) { continue; } this->GetResult(result, memberIdx); } } } // namespace gfx } // namespace nw