/*---------------------------------------------------------------------------* Project: NintendoWare File: anim_ResAnimCurve.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 19698 $ *---------------------------------------------------------------------------*/ #include "../precompiled.h" #include #include #include #include #include namespace nw { namespace anim { namespace res { namespace { /*!--------------------------------------------------------------------------* @brief キー形式毎の特性の定義です。 *---------------------------------------------------------------------------*/ template class ResAnimTraits; template <> class ResAnimTraits { public: typedef ResFloatKeyFV64Data KeyType; typedef f32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fv64.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static f32 GetValue( const ResFloatSegmentFVData*, const KeyType* pKey ) { return pKey->GetValue(); } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFV32Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fv32.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static f32 GetValue( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 value = pKey->GetValue(); return value * pSegment->fv32.m_Scale + pSegment->fv32.m_Offset; } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVSS128Data KeyType; typedef f32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvss128.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->m_Frame; } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->m_Frame; } static f32 GetValue( const ResFloatSegmentFVData*, const KeyType* pKey ) { return pKey->m_Value; } static f32 GetInSlope( const KeyType* pKey ) { return pKey->m_InSlope; } static f32 GetOutSlope( const KeyType* pKey ) { return pKey->m_OutSlope; } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVSS64Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvss64.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return (pKey->m_FrameValue & 0x00000FFF); } static f32 GetFrameF32( const KeyType* pKey ) { return f32( GetFrame(pKey) ); } static f32 GetValue( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 value = pKey->GetValue(); return value * pSegment->fvss64.m_Scale + pSegment->fvss64.m_Offset; } static f32 GetInSlope( const KeyType* pKey ) { return pKey->GetInSlope(); } static f32 GetOutSlope( const KeyType* pKey ) { return pKey->GetOutSlope(); } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVSS48Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvss48.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static f32 GetValue( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 value = pKey->GetValue(); return value * pSegment->fvss48.m_Scale + pSegment->fvss48.m_Offset; } static f32 GetInSlope( const KeyType* pKey ) { return pKey->GetInSlope(); } static f32 GetOutSlope( const KeyType* pKey ) { return pKey->GetOutSlope(); } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVS96Data KeyType; typedef f32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvs96.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static f32 GetValue( const ResFloatSegmentFVData*, const KeyType* pKey ) { return pKey->GetValue(); } static f32 GetSlope( const KeyType* pKey ) { return pKey->GetSlope(); } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVS48Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvs48.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return internal::CastF32ToS10_5(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static f32 GetValue( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 value = pKey->GetValue(); return value * pSegment->fvs48.m_Scale + pSegment->fvs48.m_Offset; } static f32 GetSlope( const KeyType* pKey ) { return pKey->GetSlope(); } }; template <> class ResAnimTraits { public: typedef ResFloatKeyFVS32Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResFloatSegmentFVData* pSegment, uint keyIdx ) { return &(pSegment->fvs32.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->m_Frame; } static f32 GetFrameF32( const KeyType* pKey ) { return f32( GetFrame( pKey ) ); } static f32 GetValue( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 value = f32(pKey->m_ValueSlope[0] + ((pKey->m_ValueSlope[1] & 0x0F) << 8) ); return value * pSegment->fvs32.m_Scale + pSegment->fvs32.m_Offset; } static f32 GetSlope( const KeyType* pKey ) { return pKey->GetSlope(); } }; template <> class ResAnimTraits { public: typedef ResIntKeyFV64Data KeyType; typedef f32 FrameType; static const KeyType* GetKey( const ResIntCurveFVData* pCurve, uint keyIdx ) { return &(pCurve->fv64.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static s32 GetValue( const ResIntCurveFVData*, const KeyType* pKey ) { return pKey->GetValue(); } }; template <> class ResAnimTraits { public: typedef ResIntKeyFV32Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResIntCurveFVData* pCurve, uint keyIdx ) { return &(pCurve->fv32.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const KeyType* pKey ) { return pKey->GetFrameF32(); } static s32 GetValue( const ResIntCurveFVData* /*pCurve*/, const KeyType* pKey ) { return pKey->GetValue(); } }; template <> class ResAnimTraits { public: typedef ResIntKeyFV16Data KeyType; typedef u32 FrameType; static const KeyType* GetKey( const ResIntCurveFVData* pCurve, uint keyIdx ) { return &(pCurve->fv16.m_KeyValue[ keyIdx ]); } static FrameType QuantizedFrame( f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return u32(pKey->m_Frame); } static f32 GetFrameF32( const KeyType* pKey ) { return f32( GetFrame( pKey ) ); } static s32 GetValue( const ResIntCurveFVData* /*pCurve*/, const KeyType* pKey ) { return s32(pKey->m_Value); } }; typedef f32 (*NormalizeFrameFunc)( f32 frame, f32 startFrame, f32 endFrame ); f32 NormalizeFrameNonePre_( f32 frame, f32 startFrame, f32 /* endFrame */ ) { return (frame < startFrame) ? startFrame : frame; } f32 NormalizeFrameNonePost_( f32 frame, f32 /*startFrame*/, f32 endFrame ) { return (frame > endFrame) ? endFrame : frame; } f32 NormalizeFrameRepeatPre_( f32 frame, f32 startFrame, f32 endFrame ) { f32 duration = endFrame - startFrame; s32 cnt = static_cast(std::floor( (frame - startFrame) / duration )); frame -= cnt * duration; return frame; } f32 NormalizeFrameRepeatPost_( f32 frame, f32 startFrame, f32 endFrame ) { f32 duration = endFrame - startFrame; s32 cnt = static_cast(std::floor( (frame - startFrame) / duration )); frame -= cnt * duration; return frame; } f32 NormalizeFrameMirrorPre_( f32 frame, f32 startFrame, f32 endFrame ) { bool needsReverse = false; f32 duration = endFrame - startFrame; s32 cnt = static_cast(std::floor( (frame - startFrame) / duration )); frame -= cnt * duration; needsReverse = (cnt & 1)? true : false; return needsReverse ? startFrame + endFrame - frame : frame; } f32 NormalizeFrameMirrorPost_( f32 frame, f32 startFrame, f32 endFrame ) { bool needsReverse = false; f32 duration = endFrame - startFrame; s32 cnt = static_cast(std::floor( (frame - startFrame) / duration )); frame -= cnt * duration; needsReverse = (cnt & 1)? true : false; return needsReverse ? startFrame + endFrame - frame : frame; } /*!--------------------------------------------------------------------------* @brief フレームを正規化します。 @param[in] frame 正規化するフレームです。 @param[in] pCurve アニメーションデータへのポインタです。 @return *---------------------------------------------------------------------------*/ f32 NormalizeFrame_( f32 frame, const ResAnimCurveData* pCurve ) { static const NormalizeFrameFunc preRepeatMethod[] = { NormalizeFrameNonePre_, NormalizeFrameRepeatPre_, NormalizeFrameMirrorPre_, NormalizeFrameRepeatPre_ }; static const NormalizeFrameFunc postRepeatMethod[] = { NormalizeFrameNonePost_, NormalizeFrameRepeatPost_, NormalizeFrameMirrorPost_, NormalizeFrameRepeatPost_ }; NW_ASSERT( pCurve->m_InRepeatMethod < ResAnimCurveData::METHOD_NUM ); NW_ASSERT( pCurve->m_OutRepeatMethod < ResAnimCurveData::METHOD_NUM ); if ( frame < pCurve->m_StartFrame ) { return preRepeatMethod[ pCurve->m_InRepeatMethod ]( frame, pCurve->m_StartFrame, pCurve->m_EndFrame ); } // リピート時に、EndFrame と等しいフレームは、StartFrame と同じものとして扱うので、 // 終端の判定のみ if の判定条件にイコールを入れている。 if ( frame >= pCurve->m_EndFrame ) { return postRepeatMethod[ pCurve->m_OutRepeatMethod ]( frame, pCurve->m_StartFrame, pCurve->m_EndFrame ); } return frame; } /*!--------------------------------------------------------------------------* @brief 指定されたフレーム以下の最大のキーフレームを検索して返します。 @param[in] pSegment キーを検索するセグメントです。 @param[in] frame キーを検索するフレーム数です。 @return キーフレームです。 *---------------------------------------------------------------------------*/ template const typename Traits::KeyType* GetKeyFV_( const Segment* pSegment, f32 frame ) { typename Traits::FrameType quantizedFrame = Traits::QuantizedFrame( frame ); // 先頭のキー以前の場合は特別扱い // 先頭のフレームに複数のキーがある場合、それ以前のフレームでは最初のキーを選択する const typename Traits::KeyType* pFirstKey = Traits::GetKey(pSegment, 0); if ( quantizedFrame <= Traits::GetFrame( pFirstKey ) ) { return pFirstKey; } // 末尾のキーを超える場合は特別扱い const typename Traits::KeyType* pLastKey = Traits::GetKey(pSegment, pSegment->m_NumFrameValues - 1); if ( Traits::GetFrame( pLastKey ) <= quantizedFrame ) { return pLastKey; } // キーが等幅で打たれていると仮定して、キーの位置を推測する。 uint keyIdx = static_cast( frame * pSegment->m_InvDuration * (pSegment->m_NumFrameValues - 1) ); NW_ASSERT( keyIdx <= pSegment->m_NumFrameValues - 1U ); const typename Traits::KeyType* pKey = Traits::GetKey(pSegment, keyIdx); // 推測位置から線形探索 if ( quantizedFrame < Traits::GetFrame( pKey ) ) { do { NW_ASSERT( Traits::GetKey(pSegment, 0) < pKey ); --pKey; } while ( quantizedFrame < Traits::GetFrame( pKey ) ); } else { do { NW_ASSERT( pKey < Traits::GetKey(pSegment, pSegment->m_NumFrameValues - 1) ); ++pKey; } while ( Traits::GetFrame( pKey ) <= quantizedFrame ); // ここにきた時点で1つ通り過ぎている NW_ASSERT( Traits::GetKey(pSegment, 0) < pKey ); --pKey; } return pKey; } /*!--------------------------------------------------------------------------* @brief 指定されたフレームに相当するセグメントを返します。 @param[in] pCurve セグメントを検索するセグメントカーブです。 @param[in] frame セグメントを検索するフレーム数です。 @return カーブの中から対象となるセグメントを検索します。 *---------------------------------------------------------------------------*/ NW_INLINE const ResFloatSegmentData* GetFloatSegment_( const ResSegmentFloatCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); NW_ASSERT( pCurve->m_StartFrame <= frame && frame <= pCurve->m_EndFrame ); // 単一セグメントである場合は唯一のセグメントを返します。 if ( pCurve->m_Flags & ResSegmentFloatCurveData::FLAG_MONO_SEGMENT ) { return reinterpret_cast( pCurve->segmentsTable.toSegments[0].to_ptr() ); } s32 segmentCount = pCurve->segmentsTable.m_NumSegments; NW_ASSERT( segmentCount > 0 ); const ut::Offset* pOffsetTable = &(pCurve->segmentsTable.toSegments[0]); for ( const ut::Offset* pOffset = pOffsetTable; pOffset < pOffsetTable + segmentCount; ++pOffset ) { const ResFloatSegmentData* pSegment = reinterpret_cast( pOffset->to_ptr() ); if ( pSegment->m_EndFrame > frame ) { return pSegment; } } return reinterpret_cast( pOffsetTable[ segmentCount - 1 ].to_ptr() ); } template const typename Traits::KeyType* GetFloatKeyFV_( const ResFloatSegmentFVData* pSegment, f32 frame ) { return GetKeyFV_( pSegment, frame ); } template f32 CalcStepFloatSegmentFV_( const ResFloatSegmentFVData* pSegment, f32 frame ) { const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); return Traits::GetValue( pSegment, pKey ); } template f32 CalcLinearFloatSegmentFV_( const ResFloatSegmentFVData* pSegment, f32 frame ) { const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); f32 keyFrame = Traits::GetFrameF32( pKey ); if ( keyFrame == frame ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 nextKeyFrame = Traits::GetFrameF32( pNextKey ); f32 rate = (frame - keyFrame) / (nextKeyFrame - keyFrame); return Traits::GetValue( pSegment, pKey ) * (1.0f - rate) + Traits::GetValue( pSegment, pNextKey ) * rate; } template f32 CalcHermiteFloatSegmentFVSS_( const ResFloatSegmentFVData* pSegment, f32 frame ) { const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); f32 keyFrame = Traits::GetFrameF32( pKey ); if ( keyFrame == frame ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 p = frame - keyFrame; f32 d = Traits::GetFrameF32( pNextKey ) - keyFrame; f32 v0 = Traits::GetValue( pSegment, pKey ); f32 v1 = Traits::GetValue( pSegment, pNextKey ); f32 t0 = Traits::GetOutSlope( pKey ); f32 t1 = Traits::GetInSlope( pNextKey ); return nw::math::Hermite( v0, t0, v1, t1, p, d ); } template f32 CalcHermiteFloatSegmentFVS_( const ResFloatSegmentFVData* pSegment, f32 frame ) { const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); // UNDONE: 同じフレームにキーが複数存在する場合の対処が必要。 f32 keyFrame = Traits::GetFrameF32( pKey ); if ( keyFrame == frame ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 p = frame - keyFrame; f32 d = Traits::GetFrameF32( pNextKey ) - keyFrame; f32 v0 = Traits::GetValue( pSegment, pKey ); f32 v1 = Traits::GetValue( pSegment, pNextKey ); f32 t0 = Traits::GetSlope( pKey ); f32 t1 = Traits::GetSlope( pNextKey ); return nw::math::Hermite( v0, t0, v1, t1, p, d ); } typedef f32 (*CalcFloatSegmentFVFunc)( const ResFloatSegmentFVData* pSegment, f32 frame ); static CalcFloatSegmentFVFunc s_CalcFloatSegmentFVTable[][8] = { { CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, CalcStepFloatSegmentFV_< ResAnimTraits >, }, { CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, CalcLinearFloatSegmentFV_< ResAnimTraits >, }, { CalcHermiteFloatSegmentFVSS_< ResAnimTraits >, CalcHermiteFloatSegmentFVSS_< ResAnimTraits >, CalcHermiteFloatSegmentFVSS_< ResAnimTraits >, CalcHermiteFloatSegmentFVS_< ResAnimTraits >, CalcHermiteFloatSegmentFVS_< ResAnimTraits >, CalcHermiteFloatSegmentFVS_< ResAnimTraits >, NULL, NULL, } }; template const typename Traits::KeyType* GetIntKeyFV_( const ResIntCurveFVData* pCurve, f32 frame ) { return GetKeyFV_( pCurve, frame ); } template s32 CalcIntCurveFV_( const ResIntCurveFVData* pCurve, f32 frame ) { const typename Traits::KeyType* pKey = GetIntKeyFV_( pCurve, frame ); return Traits::GetValue( pCurve, pKey ); } typedef s32 (*CalcIntCurveFVFunc)( const ResIntCurveFVData* pCurve, f32 frame ); static CalcIntCurveFVFunc s_CalcIntCurveFVTable[] = { CalcIntCurveFV_< ResAnimTraits >, CalcIntCurveFV_< ResAnimTraits >, CalcIntCurveFV_< ResAnimTraits >, }; NW_INLINE f32 CalcFloatSegment_( const ResFloatSegmentData* pSegment, f32 frame ) { NW_NULL_ASSERT( pSegment ); NW_ASSERT( pSegment->m_StartFrame <= frame && frame <= pSegment->m_EndFrame ); NW_ASSERT(!(pSegment->m_Flags & ResFloatSegmentData::FLAG_BAKED)); if ( pSegment->m_Flags & ResFloatSegmentData::FLAG_CONSTANT ) { return pSegment->constantValue; } u32 quantizeType = (pSegment->m_Flags & ResFloatSegmentData::FLAG_QUANTIZATION_TYPE_MASK) >> ResFloatSegmentData::FLAG_QUANTIZATION_TYPE_SHIFT; u32 interporateMode = (pSegment->m_Flags & ResFloatSegmentData::FLAG_INTERPORATE_MODE_MASK) >> ResFloatSegmentData::FLAG_INTERPORATE_MODE_SHIFT; return s_CalcFloatSegmentFVTable[ interporateMode ][ quantizeType ]( &(pSegment->fv), frame - pSegment->m_StartFrame ); } NW_INLINE f32 CalcSegmentFloatCurve_( const ResSegmentFloatCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); NW_ASSERT( pCurve->m_StartFrame <= frame && frame <= pCurve->m_EndFrame ); if ( pCurve->m_Flags & ResSegmentFloatCurveData::FLAG_CONSTANT ) { return pCurve->m_ConstantValue; } const ResFloatSegmentData* pSegment = GetFloatSegment_( pCurve, frame ); if ( frame < pSegment->m_StartFrame ) { // 量子化の影響で、セグメント間に隙間があいてしまうことがあるため frame = pSegment->m_StartFrame; } return CalcFloatSegment_( pSegment, frame ); } NW_INLINE f32 CalcCompositeFloatCurve_( const ResCompositeFloatCurveData* pCurve, f32 frame ) { const ResFloatCurveData* pLeftCurve = reinterpret_cast( pCurve->toLeftCurve.to_ptr() ); const ResFloatCurveData* pRightCurve = reinterpret_cast( pCurve->toRightCurve.to_ptr() ); f32 leftValue = CalcFloatCurve( pLeftCurve, frame ); f32 rightValue = CalcFloatCurve( pRightCurve, frame ); // UNDONE: CompositeCurve には未対応。 bool curve の乗算をしていない。 return leftValue + rightValue; } bool CalcBoolCurveCV_( const ResBoolCurveData* pCurve, f32 frame ) { NW_ASSERT( pCurve->m_StartFrame <= frame && frame <= pCurve->m_EndFrame ); float frameOffset = frame - pCurve->m_StartFrame; // EndFrameが小数の場合に、PostInfinityを正しく計算する if (frame == pCurve->m_EndFrame) { frameOffset = math::FCeil(frameOffset); } u32 index = u32(frameOffset) / 8; u32 shift = u32(frameOffset) % 8; return ( (pCurve->cv.m_KeyValue[ index ] >> shift) & 0x1) != 0; } void CalcVector3CurveCV_( math::VEC3* result, bit32* flags, const ResVector3CurveData* pCurve, f32 frame ) { u32 index = u32(frame); f32 remainder = frame - index; const ResVector3CurveData::FrameValue& frameValue = pCurve->frames.m_KeyValue[index]; if ( remainder == 0 ) { // 整数フレーム *result = frameValue.cv; *flags |= frameValue.flag; } else { // 小数フレーム f32 nextFrame = NormalizeFrame_( frame + 1.0f, pCurve ); u32 nextIndex = u32(nextFrame); const ResVector3CurveData::FrameValue& nextFrameValue = pCurve->frames.m_KeyValue[nextIndex]; VEC3Lerp( result, static_cast(&frameValue.cv), static_cast(&nextFrameValue.cv), remainder ); // 補間の両端でフラグが立っているなら、補間後も立っているはず // 両端で立たず、2点の間のどこかで立つことはありうるが、その1フレームだけ軽くなってもメリットは薄そう // それより、平均的な処理負荷を下げるためシンプルな実装にする *flags |= (frameValue.flag & nextFrameValue.flag); } } void CalcRotateCurveCV_( math::MTX34* result, bit32* flags, const ResVector4CurveData* pCurve, f32 frame ) { u32 index = u32(frame); f32 remainder = frame - index; const ResVector4CurveData::FrameValue& frameValue = pCurve->frames.m_KeyValue[index]; math::MTX34 mtx; if ( remainder == 0 ) { // 整数フレーム // クォータニオンを用意 math::QUAT quaternion(frameValue.cv); // クォータニオンから回転行列を生成する math::QUATToMTX34(&mtx, &quaternion); *flags |= frameValue.flag; } else { // 小数フレーム f32 nextFrame = NormalizeFrame_( frame + 1.0f, pCurve ); u32 nextIndex = u32(nextFrame); const ResVector4CurveData::FrameValue& nextFrameValue = pCurve->frames.m_KeyValue[nextIndex]; // クォータニオンを用意 math::QUAT lerpResult; math::QUAT q1(frameValue.cv); math::QUAT q2(nextFrameValue.cv); // 補間してから回転行列を生成する math::QUATLerp(&lerpResult, &q1, &q2, remainder); math::QUATToMTX34(&mtx, &lerpResult); // 意図はCalcVector3CurveCV_のコメントを参照 *flags |= (frameValue.flag & nextFrameValue.flag); } // Mtx34の4列目はTranslateの値が入るので、 // Rotateのカーブ評価であるこの関数ではあえて上書きを行わない。 result->f._00 = mtx.f._00; result->f._01 = mtx.f._01; result->f._02 = mtx.f._02; //result->f._03 = 0.0f; result->f._10 = mtx.f._10; result->f._11 = mtx.f._11; result->f._12 = mtx.f._12; //result->f._13 = 0.0f; result->f._20 = mtx.f._20; result->f._21 = mtx.f._21; result->f._22 = mtx.f._22; //result->f._23 = 0.0f; } void CalcTranslateCurveCV_( math::MTX34* result, bit32* flags, const ResVector3CurveData* pCurve, f32 frame ) { u32 index = u32(frame); f32 remainder = frame - index; const ResVector3CurveData::FrameValue& frameValue = pCurve->frames.m_KeyValue[index]; if ( remainder == 0 ) { // 整数フレーム result->f._03 = frameValue.cv.x; result->f._13 = frameValue.cv.y; result->f._23 = frameValue.cv.z; *flags |= frameValue.flag; } else { // 小数フレーム f32 nextFrame = NormalizeFrame_( frame + 1.0f, pCurve ); u32 nextIndex = u32(nextFrame); const ResVector3CurveData::FrameValue& nextFrameValue = pCurve->frames.m_KeyValue[nextIndex]; math::VEC3 v; VEC3Lerp( &v, static_cast(&frameValue.cv), static_cast(&nextFrameValue.cv), remainder ); result->f._03 = v.x; result->f._13 = v.y; result->f._23 = v.z; // 意図はCalcVector3CurveCV_のコメントを参照 *flags |= (frameValue.flag & nextFrameValue.flag); } } } // namespace f32 CalcFloatCurve( const ResFloatCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); frame = NormalizeFrame_( frame, pCurve ); if ( pCurve->m_Flags & ResFloatCurveData::FLAG_COMPOSITE_CURVE ) { return CalcCompositeFloatCurve_( reinterpret_cast( pCurve ), frame ); } else { return CalcSegmentFloatCurve_( reinterpret_cast( pCurve ), frame ); } } s32 CalcIntCurve( const ResIntCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); NW_ASSERT(!(pCurve->m_Flags & ResIntCurveData::FLAG_BAKED)); frame = NormalizeFrame_( frame, pCurve ); if ( pCurve->m_Flags & ResIntCurveData::FLAG_CONSTANT ) { return pCurve->constantValue; } u32 quantizedType = (pCurve->m_Flags & ResIntCurveData::FLAG_QUANTIZATION_TYPE_MASK) >> ResIntCurveData::FLAG_QUANTIZATION_TYPE_SHIFT; return s_CalcIntCurveFVTable[ quantizedType ]( &(pCurve->fv), frame ); } bool CalcBoolCurve( const ResBoolCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); frame = NormalizeFrame_( frame, pCurve ); if ( pCurve->m_Flags & ResBoolCurveData::FLAG_CONSTANT ) { return ((pCurve->m_Flags & ResBoolCurveData::FLAG_CONSTANT_VALUE) != 0); } if ( pCurve->m_Flags & ResBoolCurveData::FLAG_BAKED ) { return CalcBoolCurveCV_( pCurve, frame ); } else { u32 quantizedType = (pCurve->m_Flags & ResBoolCurveData::FLAG_QUANTIZATION_TYPE_MASK) >> ResBoolCurveData::FLAG_QUANTIZATION_TYPE_SHIFT; return (s_CalcIntCurveFVTable[ quantizedType ]( &(pCurve->fv), frame ) != 0); } } void CalcVector3Curve( math::VEC3* result, bit32* flags, const ResVector3CurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); if ( pCurve->m_Flags & ResVector3CurveData::FLAG_CONSTANT ) { // コンスタントの場合は最初のフレームの値を使用する frame = pCurve->m_StartFrame; } else { frame = NormalizeFrame_( frame, pCurve ); } // TODO: 量子化対応 CalcVector3CurveCV_( result, flags, pCurve, frame ); } /*!--------------------------------------------------------------------------* @brief ベイクされたRotateのカーブ評価です。カーブはVector4ですが、書き込み先はMtx34です。 *---------------------------------------------------------------------------*/ void CalcRotateCurve(math::MTX34* result, bit32* flags, const ResVector4CurveData* pCurve, f32 frame) { NW_NULL_ASSERT( pCurve ); frame = NormalizeFrame_( frame, pCurve ); if ( pCurve->m_Flags & ResVector4CurveData::FLAG_CONSTANT ) { // コンスタントの場合は最初のフレームの値を使用する frame = pCurve->m_StartFrame; } // TODO: 量子化対応 CalcRotateCurveCV_( result, flags, pCurve, frame ); } /*!--------------------------------------------------------------------------* @brief ベイクされたTranslateのカーブ評価です。カーブはVector3ですが、書き込み先はMtx34です。 *---------------------------------------------------------------------------*/ void CalcTranslateCurve(math::MTX34* result, bit32* flags, const ResVector3CurveData* pCurve, f32 frame) { NW_NULL_ASSERT( pCurve ); if ( pCurve->m_Flags & ResVector3CurveData::FLAG_CONSTANT ) { // コンスタントの場合は最初のフレームの値を使用する frame = pCurve->m_StartFrame; } else { frame = NormalizeFrame_( frame, pCurve ); } // TODO: 量子化対応 CalcTranslateCurveCV_( result, flags, pCurve, frame ); } } /* namespace res */ } /* namespace anim */ } /* namespace nw */