/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_TransformAnimBlendOp.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 { //! トランスフォームアニメーションのブレンドオペレーションで使用する定数です。 const float TransformAnimBlendOp::WeightDiscard = -1.0f; namespace { /*!--------------------------------------------------------------------------* @brief Vector3 の値をすべて Flog で変換します。 *---------------------------------------------------------------------------*/ void FlogVector3(math::VEC3* dst) { dst->x = math::FLog(dst->x); dst->y = math::FLog(dst->y); dst->z = math::FLog(dst->z); } /*!--------------------------------------------------------------------------* @brief Vector3 のブレンド処理を行います。 @param[in,out] dst ブレンド処理結果です。 @param[in] src ブレンド処理の入力です。 @param[in] weight ブレンド比率です。 @param[in] overrideFlag 値を上書き更新するかどうかのフラグです。 *---------------------------------------------------------------------------*/ void BlendVector3( math::VEC3* dst, const math::VEC3* src, const float weight, const bool overrideFlag ) { if (overrideFlag) { VEC3Scale(dst, src, weight); } else { math::VEC3 tmp; VEC3Scale(&tmp, src, weight); VEC3Add(dst, dst, &tmp); } } } // namespace //---------------------------------------------------------- void TransformAnimBlendOp::Apply(void* target, const anim::AnimResult* result) const { *reinterpret_cast(target) = *reinterpret_cast(result->GetValueBuffer()); } //---------------------------------------------------------- void TransformAnimBlendOp::ConvertToAnimResult( anim::AnimResult* result, const void* source ) const { *reinterpret_cast(result->GetValueBuffer()) = *reinterpret_cast(source); } //---------------------------------------------------------- void TransformAnimBlendOp::BlendScaleStandard( CalculatedTransform* dst, const CalculatedTransform* src, const float weight ) const { if (weight != TransformAnimBlendOp::WeightDiscard) { // スケール値を直接ブレンド BlendVector3(&dst->m_Scale, &src->Scale(), weight, dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE)); dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE); dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); } } //---------------------------------------------------------- void TransformAnimBlendOp::BlendScaleAccurate( CalculatedTransform* dst, const CalculatedTransform* src, const float weight ) const { if (weight != TransformAnimBlendOp::WeightDiscard) { // 正確なスケールブレンド // s = Π(s(i)^weight) = exp(Σ(log(s(i)) * weight)) // exp の計算は最後に行う math::VEC3 logScale = src->Scale(); FlogVector3(&logScale); BlendVector3(&dst->m_Scale, &logScale, weight, dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE)); dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE); dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); } } //---------------------------------------------------------- bool TransformAnimBlendOp::PostBlendAccurateScale(CalculatedTransform* transform) const { math::VEC3& scale = transform->m_Scale; scale.x = math::FExp(scale.x); scale.y = math::FExp(scale.y); scale.z = math::FExp(scale.z); transform->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); return true; } //---------------------------------------------------------- void TransformAnimBlendOp::BlendRotateMatrix( CalculatedTransform* dst, const CalculatedTransform* src, const float weight ) const { if (weight != TransformAnimBlendOp::WeightDiscard) { math::MTX34& dstMtx = dst->m_TransformMatrix; const math::MTX34& srcMtx = src->TransformMatrix(); if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE)) { dstMtx.f._00 = srcMtx.f._00 * weight; dstMtx.f._01 = srcMtx.f._01 * weight; dstMtx.f._02 = srcMtx.f._02 * weight; dstMtx.f._10 = srcMtx.f._10 * weight; dstMtx.f._11 = srcMtx.f._11 * weight; dstMtx.f._12 = srcMtx.f._12 * weight; // ブレンド後の処理で回転行列を正規直交化するので、 2 行目の計算は不要 } else { dstMtx.f._00 += srcMtx.f._00 * weight; dstMtx.f._01 += srcMtx.f._01 * weight; dstMtx.f._02 += srcMtx.f._02 * weight; dstMtx.f._10 += srcMtx.f._10 * weight; dstMtx.f._11 += srcMtx.f._11 * weight; dstMtx.f._12 += srcMtx.f._12 * weight; // ブレンド後の処理で回転行列を正規直交化するので、 2 行目の計算は不要 } dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE); dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); } } //---------------------------------------------------------- void TransformAnimBlendOp::BlendRotateQuaternion( CalculatedTransform* dst, const CalculatedTransform* src, const float weight ) const { if (weight != TransformAnimBlendOp::WeightDiscard) { math::MTX34& dstMtx = dst->m_TransformMatrix; const math::MTX34& srcMtx = src->TransformMatrix(); float& addedWeight = dstMtx.f._11; math::QUAT srcQ; if (src->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND)) { srcQ = math::QUAT(srcMtx.f._00, srcMtx.f._01, srcMtx.f._02, srcMtx.f._10); } else { math::MTX34ToQUAT(&srcQ, &srcMtx); } math::QUAT dstQ; if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE)) { addedWeight = weight; dstQ = srcQ; } else { dstQ = math::QUAT(dstMtx.f._00, dstMtx.f._01, dstMtx.f._02, dstMtx.f._10); addedWeight += weight; const float t = (addedWeight != 0.0f) ? weight / addedWeight : 0.0f; math::QUATSlerp(&dstQ, &dstQ, &srcQ, t); } dstMtx.f._00 = dstQ.x; dstMtx.f._01 = dstQ.y; dstMtx.f._02 = dstQ.z; dstMtx.f._10 = dstQ.w; dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE); dst->SetTransformMatrix(dstMtx); } } //---------------------------------------------------------- void TransformAnimBlendOp::BlendTranslate( CalculatedTransform* dst, const CalculatedTransform* src, const float weight ) const { if (weight != TransformAnimBlendOp::WeightDiscard) { const math::MTX34& dstMtx = dst->TransformMatrix(); const math::MTX34& srcMtx = src->TransformMatrix(); math::VEC3 srcT(srcMtx.f._03, srcMtx.f._13, srcMtx.f._23); if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE)) { VEC3Scale(&srcT, &srcT, weight); dst->SetTranslate(srcT); dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE); } else { math::VEC3 dstT(dstMtx.f._03, dstMtx.f._13, dstMtx.f._23); BlendVector3(&dstT, &srcT, weight, false); dst->SetTranslate(dstT); } } } //---------------------------------------------------------- bool TransformAnimBlendOp::OverrideTransform( CalculatedTransform* dst, const CalculatedTransform* src, const bit32 blendFlags ) const { const bool needToConverted = dst->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND) && !src->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND); math::MTX34 dstMtx = dst->TransformMatrix(); const math::MTX34& srcMtx = src->TransformMatrix(); if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE) && !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE)) { dst->SetScale(src->Scale()); dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE); if (needToConverted && (blendFlags & FLAG_ACCURATE_SCALE)) { math::VEC3& dstScale = dst->m_Scale; FlogVector3(&dstScale); dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); } } if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE) && !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE)) { dstMtx.f._00 = srcMtx.f._00; dstMtx.f._01 = srcMtx.f._01; dstMtx.f._02 = srcMtx.f._02; dstMtx.f._10 = srcMtx.f._10; dstMtx.f._11 = srcMtx.f._11; dstMtx.f._12 = srcMtx.f._12; dstMtx.f._20 = srcMtx.f._20; dstMtx.f._21 = srcMtx.f._21; dstMtx.f._22 = srcMtx.f._22; dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE); if (needToConverted && (blendFlags & FLAG_QUATERNION_ROTATE)) { dst->RotateMatrixToQuaternion(); } } if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE) && !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE)) { dstMtx.f._03 = srcMtx.f._03; dstMtx.f._13 = srcMtx.f._13; dstMtx.f._23 = srcMtx.f._23; dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE); } dst->SetTransformMatrix(dstMtx); return !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE) && !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE) && !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE); } } // namespace gfx } // namespace nw