/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_AnimBinding.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 #include #include namespace nw { namespace gfx { //---------------------------------------------------------- void AnimBinding::Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing) { for (int animGroupIdx = 0; animGroupIdx < m_AnimGroups.Size(); ++animGroupIdx) { AnimGroup* animGroup = m_AnimGroups[animGroupIdx]; // アニメーションの有無と評価タイミングをチェック if (animGroup == NULL || animGroup->GetResGraphicsAnimGroup().GetEvaluationTiming() != timing) { continue; } for (int animObjectIdx = 0; animObjectIdx < m_AnimObjectCountPerGroup; ++animObjectIdx) { const int index = animGroupIdx * m_AnimObjectCountPerGroup + animObjectIdx; AnimObject* animObj = m_AnimObjects[index]; if (animObj == NULL) { continue; } // 高速化のため、ブレンダの有無・Transformかどうかで分岐 switch (animObj->GetAnimType()) { case AnimObject::ANIMTYPE_SIMPLE: static_cast(animObj)->UpdateCacheNonVirtual(); EvaluateSimple(animGroup, static_cast(animObj)); break; case AnimObject::ANIMTYPE_TRANSFORM_SIMPLE: static_cast(animObj)->UpdateCacheNonVirtual(); EvaluateTransformSimple(animGroup, static_cast(animObj)); break; default: // アニメーション評価結果の内部キャッシュが古ければ更新 animObj->UpdateCache(); EvaluateBlender(animGroup, animObj); } } } } //---------------------------------------------------------- void AnimBinding::EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator) { NW_ASSERT(!(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM)); // 汎用アニメーションを評価 int lastTargetObjIdx = -1; bool targetObjSkipFlag = false; int animCount = evaluator->GetAnimData().GetMemberAnimSetCount(); for (int animIdx = 0; animIdx < animCount; ++animIdx) { int memberIdx = evaluator->ReverseBindIndexTable()[animIdx]; if (memberIdx == BaseAnimEvaluator::NotFoundIndex) { continue; } EvaluateMember(animGroup, memberIdx, evaluator, lastTargetObjIdx, targetObjSkipFlag); } } //---------------------------------------------------------- void AnimBinding::EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator) { NW_ASSERT(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM); // トランスフォームアニメーションを評価 int animCount = evaluator->GetAnimData().GetMemberAnimSetCount(); for (int animIdx = 0; animIdx < animCount; ++animIdx) { int memberIdx = evaluator->ReverseBindIndexTable()[animIdx]; if (memberIdx == BaseAnimEvaluator::NotFoundIndex) { continue; } EvaluateTransformMemberFast(animGroup, memberIdx, evaluator); } } //---------------------------------------------------------- void AnimBinding::EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj) { if (animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) { // トランスフォームアニメーションを評価 int memberCount = animGroup->GetMemberCount(); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) { EvaluateTransformMember(animGroup, memberIdx, animObj); } } else { // 汎用アニメーションを評価 int lastTargetObjIdx = -1; bool targetObjSkipFlag = false; int memberCount = animGroup->GetMemberCount(); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) { EvaluateMember(animGroup, memberIdx, animObj, lastTargetObjIdx, targetObjSkipFlag); } } } //---------------------------------------------------------- void AnimBinding::EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj) { AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback(); // 評価前コールバックの呼び出し if (preEvaluateCallback != NULL) { const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx); if (!preEvaluateCallback(animGroup, targetObjIdx)) { return; } } // 評価 CalculatedTransform* target = static_cast(animGroup->GetTargetPtr(memberIdx)); animObj->GetResult(target, memberIdx); // Setter経由で設定する必要はないので、Setterは呼び出さない // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する } //---------------------------------------------------------- void AnimBinding::EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator) { AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback(); // 評価前コールバックの呼び出し if (preEvaluateCallback != NULL) { const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx); if (!preEvaluateCallback(animGroup, targetObjIdx)) { return; } } // 評価 CalculatedTransform* target = static_cast(animGroup->GetTargetPtr(memberIdx)); evaluator->GetResultFast(target, memberIdx); // Setter経由で設定する必要はないので、Setterは呼び出さない // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する } //---------------------------------------------------------- void AnimBinding::EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag) { AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback(); // 評価前コールバックの呼び出し if (preEvaluateCallback != NULL) { const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx); if (targetObjIdx != lastTargetObjIdx) { // 高速化のため前回と対象オブジェクトが異なる場合だけ評価前コールバックを呼ぶ targetObjSkipFlag = !preEvaluateCallback(animGroup, targetObjIdx); lastTargetObjIdx = targetObjIdx; } if (targetObjSkipFlag) { return; } } // 評価 anim::ResAnimGroupMember member = animGroup->GetResAnimGroupMember(memberIdx); void* target = NULL; ut::Offset texturePatternTarget; if (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER && member.GetMemberType() == anim::ResTextureMapperMember::MEMBER_TYPE_TEXTURE) { // テクスチャパターンアニメーションは、targetを上書きせずにSetterのみ呼び出す // // マテリアルのバッファが有効な場合は、targetは動的に確保されたReferenceTextureを指す // それを上書きすると、解放時にアロケータで確保されていないポインタを解放しようとしてクラッシュする target = &texturePatternTarget; } else { target = animGroup->GetTargetPtr(memberIdx); } const anim::AnimBlendOp* blendOp = animGroup->GetBlendOperation(memberIdx); const anim::AnimResult* resultPtr = NULL; if (blendOp != NULL) { // ブレンドオペレーションがある場合は // AnimResult オブジェクト経由でターゲットに書き込む anim::AnimResult result; resultPtr = animObj->GetResult(&result, memberIdx); if (resultPtr != NULL) { blendOp->Apply(target, resultPtr); // VALID フラグがオンの成分のみ書き込み } } else { // ブレンドオペレーションがない場合はターゲットを直接上書き resultPtr = animObj->GetResult(target, memberIdx); } // transformのメンバの場合は、setterを呼びださない。 bool isTransformMember = ( (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TRANSFORM) && (member.GetMemberType() == anim::ResTransformMember::MEMBER_TYPE_TRANSFORM) ); if (!isTransformMember && resultPtr) { // メモリ書き込み以外の処理が必要なメンバのためにSetterを呼び出す // (コマンドキャッシュの更新などが行われる) // // Setterがtargetも書き換えるので2回書き込んでいる。 // 1回にしたいが、VALIDフラグがオフの成分があるとtargetの値の取得が必要。 // するとバッファの確保 -> Get -> Apply -> Setとなり、かえって遅くなりそう。 void* object = animGroup->GetTargetObject(memberIdx); member.SetValueForType(object, target); } } } // namespace gfx } // namespace nw