/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_TransformAnimBlendOp.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: 32420 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_TRANSFORMANIMBLENDOP_H_ #define NW_GFX_TRANSFORMANIMBLENDOP_H_ #include namespace nw { namespace gfx { //--------------------------------------------------------------------------- //! @brief トランスフォームアニメーションのブレンドオペレーションの基底クラスです。 //--------------------------------------------------------------------------- class TransformAnimBlendOp : public anim::AnimBlendOp { public: //! 無効な重み値です。 //! //! :private static const float WeightDiscard; //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! @brief コンストラクタです。 //! //! @param[in] hasBlend ブレンド処理があるかどうかです。 //! @param[in] hasPostBlend ブレンド後の処理があるかどうかです。 //! TransformAnimBlendOp(bool hasBlend, bool hasPostBlend) : AnimBlendOp(hasBlend, hasPostBlend) {} //! デストラクタです。 virtual ~TransformAnimBlendOp() {} //@} //---------------------------------------- //! @name 適用 //@{ //! @brief ブレンド処理結果を対象に適用します。 //! //! @param[out] target ブレンド処理結果を適用する対象です。 //! @param[in] result ブレンド処理結果です。 //! virtual void Apply(void* target, const anim::AnimResult* result) const; //! @brief 対象を AnimResult に変換します。 //! //! @param[out] result 出力の AnimResult です。 //! @param[in] source 変換元へのポインタです。 //! //! :private virtual void ConvertToAnimResult(anim::AnimResult* result, const void* source) const; //@} protected: //---------------------------------------- //! @name 基本ブレンド処理 //@{ //! @details :private enum BasicBlendFlags { FLAG_ACCURATE_SCALE_SHIFT = 0, FLAG_QUATERNION_ROTATE_SHIFT = 1, // 正確なスケールブレンドをするかどうかです。 FLAG_ACCURATE_SCALE = 0x1 << FLAG_ACCURATE_SCALE_SHIFT, // クォータニオンで回転をブレンドするかどうかです。オフなら行列の回転成分をブレンドします。 FLAG_QUATERNION_ROTATE = 0x1 << FLAG_QUATERNION_ROTATE_SHIFT }; //! @brief 標準的なスケールのブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] weight ブレンド処理の入力の重みです。 //! //! :private void BlendScaleStandard( CalculatedTransform* dst, const CalculatedTransform* src, const float weight) const; //! @brief 正確なスケールのブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] weight ブレンド処理の入力の重みです。 //! //! :private void BlendScaleAccurate( CalculatedTransform* dst, const CalculatedTransform* src, const float weight) const; //! @brief 正確なスケールブレンドのブレンド後の処理を行います。 //! //! :private //! //! @param[in,out] transform トランスフォームです。 //! //! @return 正しく処理できれば true を返します。 bool PostBlendAccurateScale(CalculatedTransform* transform) const; //! @brief 行列の回転のブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] weight ブレンド処理の入力の重みです。 //! //! :private void BlendRotateMatrix( CalculatedTransform* dst, const CalculatedTransform* src, const float weight) const; //! @brief クォータニオンの回転のブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] weight ブレンド処理の入力の重みです。 //! //! :private void BlendRotateQuaternion( CalculatedTransform* dst, const CalculatedTransform* src, const float weight) const; //! @brief 移動のブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] weight ブレンド処理の入力の重みです。 //! //! :private void BlendTranslate( CalculatedTransform* dst, const CalculatedTransform* src, const float weight) const; //! @brief トランスフォームの上書き処理を行います。 //! //! :private //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] blendFlags ブレンド処理のフラグです。 //! //! @return すべての成分が上書きされたら true を返します。 bool OverrideTransform( CalculatedTransform* dst, const CalculatedTransform* src, const bit32 blendFlags ) const; //@} }; //--------------------------------------------------------------------------- //! @brief トランスフォームアニメーションの標準的なブレンドオペレーションのクラスです。 //! 回転行列の各成分をブレンドした後に、正規直交化します。 //--------------------------------------------------------------------------- class TransformAnimBlendOpStandard : public TransformAnimBlendOp { public: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 TransformAnimBlendOpStandard() : TransformAnimBlendOp(true, true) {} //! デストラクタです。 virtual ~TransformAnimBlendOpStandard() {} //@} //---------------------------------------- //! @name ブレンド //@{ //! @brief ブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] srcWeights ブレンド処理の入力の重みです。 //! //! @return ブレンド処理のループを継続するなら true を返します。 //! virtual bool Blend( anim::AnimResult* dst, float* dstWeights, const anim::AnimResult* src, const float* srcWeights) const { (void)dstWeights; CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); BlendScaleStandard(dstX, srcX, srcWeights[0]); BlendRotateMatrix (dstX, srcX, srcWeights[1]); BlendTranslate (dstX, srcX, srcWeights[2]); return true; } //! @brief ブレンド後の処理を行います。 //! //! @param[in,out] result ブレンド処理結果です。 //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! //! @return 成功すれば true を返します。 //! virtual bool PostBlend(anim::AnimResult* result, const float* weights) const { (void)weights; CalculatedTransform* dstX = reinterpret_cast(result); return dstX->NormalizeRotateMatrix(); } //! @brief 上書き処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! //! @return すべての成分が上書きされたら true を返します。 //! virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const { CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); return OverrideTransform(dstX, srcX, 0); } //@} }; //--------------------------------------------------------------------------- //! @brief トランスフォームアニメーションの正確なスケールブレンドに対応したブレンドオペレーションのクラスです。 //--------------------------------------------------------------------------- class TransformAnimBlendOpAccScale : public TransformAnimBlendOp { public: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 TransformAnimBlendOpAccScale() : TransformAnimBlendOp(true, true) {} //! デストラクタです。 virtual ~TransformAnimBlendOpAccScale() {} //@} //---------------------------------------- //! @name ブレンド //@{ //! @brief ブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] srcWeights ブレンド処理の入力の重みです。 //! //! @return ブレンド処理のループを継続するなら true を返します。 //! virtual bool Blend( anim::AnimResult* dst, float* dstWeights, const anim::AnimResult* src, const float* srcWeights) const { (void)dstWeights; CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); BlendScaleAccurate(dstX, srcX, srcWeights[0]); BlendRotateMatrix (dstX, srcX, srcWeights[1]); BlendTranslate (dstX, srcX, srcWeights[2]); return true; } //! @brief ブレンド後の処理を行います。 //! //! @param[in,out] result ブレンド処理結果です。 //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! //! @return 成功すれば true を返します。 //! virtual bool PostBlend(anim::AnimResult* result, const float* weights) const { (void)weights; CalculatedTransform* dstX = reinterpret_cast(result); const bool scaleRet = PostBlendAccurateScale(dstX); return dstX->NormalizeRotateMatrix() && scaleRet; } //! @brief 上書き処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! //! @return すべての成分が上書きされたら true を返します。 //! virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const { CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); return OverrideTransform(dstX, srcX, FLAG_ACCURATE_SCALE); } //@} }; //--------------------------------------------------------------------------- //! @brief トランスフォームアニメーションのクォータニオンによる回転ブレンドに対応したブレンドオペレーションのクラスです。 //--------------------------------------------------------------------------- class TransformAnimBlendOpQuat : public TransformAnimBlendOp { public: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 TransformAnimBlendOpQuat() : TransformAnimBlendOp(true, true) {} //! デストラクタです。 virtual ~TransformAnimBlendOpQuat() {} //@} //---------------------------------------- //! @name ブレンド //@{ //! @brief ブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] srcWeights ブレンド処理の入力の重みです。 //! //! @return ブレンド処理のループを継続するなら true を返します。 //! virtual bool Blend( anim::AnimResult* dst, float* dstWeights, const anim::AnimResult* src, const float* srcWeights) const { (void)dstWeights; CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); BlendScaleStandard (dstX, srcX, srcWeights[0]); BlendRotateQuaternion(dstX, srcX, srcWeights[1]); BlendTranslate (dstX, srcX, srcWeights[2]); return true; } //! @brief ブレンド後の処理を行います。 //! //! @param[in,out] result ブレンド処理結果です。 //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! //! @return 成功すれば true を返します。 //! virtual bool PostBlend(anim::AnimResult* result, const float* weights) const { (void)weights; CalculatedTransform* dstX = reinterpret_cast(result); return dstX->QuaternionToRotateMatrix(); } //! @brief 上書き処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! //! @return すべての成分が上書きされたら true を返します。 //! virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const { CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); return OverrideTransform(dstX, srcX, FLAG_QUATERNION_ROTATE); } //@} }; //--------------------------------------------------------------------------- //! @brief トランスフォームアニメーションの正確なスケールブレンドとクォータニオンによる回転ブレンドに対応したブレンドオペレーションのクラスです。 //--------------------------------------------------------------------------- class TransformAnimBlendOpAccScaleQuat : public TransformAnimBlendOp { public: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 TransformAnimBlendOpAccScaleQuat() : TransformAnimBlendOp(true, true) {} //! デストラクタです。 virtual ~TransformAnimBlendOpAccScaleQuat() {} //@} //---------------------------------------- //! @name ブレンド //@{ //! @brief ブレンド処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] srcWeights ブレンド処理の入力の重みです。 //! //! @return ブレンド処理のループを継続するなら true を返します。 //! virtual bool Blend( anim::AnimResult* dst, float* dstWeights, const anim::AnimResult* src, const float* srcWeights) const { (void)dstWeights; CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); BlendScaleAccurate (dstX, srcX, srcWeights[0]); BlendRotateQuaternion(dstX, srcX, srcWeights[1]); BlendTranslate (dstX, srcX, srcWeights[2]); return true; } //! @brief ブレンド後の処理を行います。 //! //! @param[in,out] result ブレンド処理結果です。 //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! //! @return 成功すれば true を返します。 //! virtual bool PostBlend(anim::AnimResult* result, const float* weights) const { (void)weights; CalculatedTransform* dstX = reinterpret_cast(result); const bool scaleRet = PostBlendAccurateScale(dstX); return dstX->QuaternionToRotateMatrix() && scaleRet; } //! @brief 上書き処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! //! @return すべての成分が上書きされたら true を返します。 //! virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const { CalculatedTransform* dstX = reinterpret_cast(dst); const CalculatedTransform* srcX = reinterpret_cast(src); return OverrideTransform(dstX, srcX, FLAG_ACCURATE_SCALE | FLAG_QUATERNION_ROTATE); } //@} }; //--------------------------------------------------------------------------- //! @brief スケルタルアニメーションではない、トランスフォームノードのアニメーションのためのブレンドオペレーションです。 //--------------------------------------------------------------------------- class AnimBlendOpTransform : public TransformAnimBlendOp { public: //---------------------------------------- //! @name コンストラクタ/デストラクタ //@{ //! コンストラクタです。 AnimBlendOpTransform() : TransformAnimBlendOp(true, true) {} //! デストラクタです。 virtual ~AnimBlendOpTransform() {} //@} //---------------------------------------- //! @name ブレンド //@{ //! @brief ブレンド処理を行います。 //! 必要なフラグ設定などを行い、処理を TransformAnimBlendOpStandard にゆだねます。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! @param[in] src ブレンド処理の入力です。 //! @param[in] srcWeight ブレンド処理の入力の重みです。 //! //! @return ブレンド処理のループを継続するなら true を返します。 //! virtual bool Blend( anim::AnimResult* dst, float* dstWeights, const anim::AnimResult* src, const float* srcWeight) const { NW_NULL_ASSERT(dst); NW_NULL_ASSERT(src); NW_NULL_ASSERT(srcWeight); // TransformAnimIntepolator が FLAG_IS_IGNORE_ALL を立てるのと同じことを // 初回ブレンドのみここで行なう。 if (!dst->IsEnabledFlags(VALID_SINGLE)) { CalculatedTransform* transform = reinterpret_cast(dst->GetValueBuffer()); transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL); // VALID_SINGLE を使うのは AnimBlendOpFloat::Blend() などにあわせている。 dst->EnableFlags(VALID_SINGLE); } // 重みを配列にする。 float srcWeights[3] = { *srcWeight, *srcWeight, *srcWeight }; return blendOp.Blend( reinterpret_cast(dst->GetValueBuffer()), dstWeights, reinterpret_cast(src->GetValueBuffer()), srcWeights); } //! @brief ブレンド後の処理を行います。 //! //! @param[in,out] result ブレンド処理結果です。 //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。 //! このブレンドオペレーションでは使用しません。 //! //! @return 成功すれば true を返します。 //! virtual bool PostBlend(anim::AnimResult* result, const float* weight) const { NW_NULL_ASSERT(result); CalculatedTransform* transform = reinterpret_cast(result->GetValueBuffer()); bool resultBlend; // TransformAnimBlendOpStandard::PostBlend() では weights を使用しないので、 // weight が指定されているかどうかにかかわらず NULL を渡す。 #if 0 if (weight) { float weights[3] = { *weight, *weight, *weight }; resultBlend= blendOp.PostBlend( reinterpret_cast(transform), weights); } else #endif { NW_UNUSED_VARIABLE(weight); resultBlend= blendOp.PostBlend( reinterpret_cast(transform), NULL); } // フラグ更新を行なう。 // TODO: TransformAnimInterpolator と同じようなフラグ更新の方法に変更する。 transform->UpdateScaleFlags(); transform->UpdateRotateFlags(); transform->UpdateTranslateFlags(); transform->UpdateCompositeFlags(); transform->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); // このフラグを立てないと TransformNode::UpdateTransform() で計算が行なわれない。 transform->EnableFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); return resultBlend; } //! @brief 上書き処理を行います。 //! //! @param[in,out] dst ブレンド処理結果です。 //! @param[in] src ブレンド処理の入力です。 //! //! @return すべての成分が上書きされたら true を返します。 //! virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const { // transformを取得 CalculatedTransform* transform = reinterpret_cast(dst->GetValueBuffer()); // TransformAnimIntepolator が FLAG_IS_IGNORE_ALL を立てるのと同じことを // 初回ブレンドのみここで行なう。 if (!dst->IsEnabledFlags(VALID_SINGLE)) { transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL); // VALID_SINGLE を使うのは AnimBlendOpFloat::Blend() などにあわせている。 dst->EnableFlags(VALID_SINGLE); } bool result = blendOp.Override( reinterpret_cast(dst->GetValueBuffer()), reinterpret_cast(src->GetValueBuffer())); // 全ての成分が上書きされない時のことを考慮し、 // BlendOpの中からは、すべてのブレンドが終わったタイミングは分からないので毎回フラグをたてる。 transform->UpdateScaleFlags(); transform->UpdateRotateFlags(); transform->UpdateTranslateFlags(); transform->UpdateCompositeFlags(); // blendと同様にTransformMatrixが変更されたフラグを立てる transform->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY); // このフラグを立てないと TransformNode::UpdateTransform() で計算が行なわれない。 transform->EnableFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); return result; } private: // 処理を委ねる BlendOperation の実体 TransformAnimBlendOpStandard blendOp; }; } // namespace gfx } // namespace nw #endif // NW_GFX_TRANSFORMANIMBLENDOP_H_