/*---------------------------------------------------------------------------* Project: NintendoWare File: anim_ResAnimCurve.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: $ *---------------------------------------------------------------------------*/ #include "../precompiled.h" #include #include #include #include #include namespace nw { namespace anim { namespace res { namespace { /*!--------------------------------------------------------------------------* @brief キー形式毎の特性の定義です。 *---------------------------------------------------------------------------*/ template class ResAnimTraits; // ResAnimTraits の扱うフレーム数は、すべてセグメントの先頭を 0 としたものです。 //--------------------------------------------------------------------------- // QuantizedFrame // 対象セグメントの量子化パラメータでフレーム数を量子化します。 //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // GetFrame // キーのフレーム数を量子化されたまま返します。 //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // GetFrameF32 // キーのフレーム数をデコードして返します。 //--------------------------------------------------------------------------- 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( const ResFloatSegmentFVData*, f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData*, 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( const ResFloatSegmentFVData* pSegment, f32 frame ) { f32 decoded = frame / pSegment->fv32.m_FrameScale; return FrameType(internal::Round(decoded)); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 frame = pKey->GetFrameF32(); return frame * pSegment->fv32.m_FrameScale; } 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( const ResFloatSegmentFVData*, f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->m_Frame; } static f32 GetFrameF32( const ResFloatSegmentFVData*, 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( const ResFloatSegmentFVData* pSegment, f32 frame ) { f32 decoded = frame / pSegment->fvss64.m_FrameScale; return FrameType(internal::Round(decoded)); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 frame = pKey->GetFrameF32(); return frame * pSegment->fvss64.m_FrameScale; } 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( const ResFloatSegmentFVData* pSegment, f32 frame ) { f32 decoded = frame / pSegment->fvss48.m_FrameScale; return FrameType(internal::Round(decoded)); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 frame = pKey->GetFrameF32(); return frame * pSegment->fvss48.m_FrameScale; } 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( const ResFloatSegmentFVData*, f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData*, 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( const ResFloatSegmentFVData* pSegment, f32 frame ) { f32 decoded = frame / pSegment->fvs48.m_FrameScale; return internal::CastF32ToS10_5(decoded); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 frame = pKey->GetFrameF32(); return frame * pSegment->fvs48.m_FrameScale; } 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( const ResFloatSegmentFVData* pSegment, f32 frame ) { f32 decoded = frame / pSegment->fvs32.m_FrameScale; return FrameType(internal::Round(decoded)); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResFloatSegmentFVData* pSegment, const KeyType* pKey ) { f32 frame = pKey->GetFrameF32(); return frame * pSegment->fvs32.m_FrameScale; } 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( const ResIntCurveFVData*, f32 frame ) { return frame; } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResIntCurveFVData*, 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( const ResIntCurveFVData*, f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return pKey->GetFrame(); } static f32 GetFrameF32( const ResIntCurveFVData*, 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( const ResIntCurveFVData*, f32 frame ) { return u32(frame); } static FrameType GetFrame( const KeyType* pKey ) { return u32(pKey->m_Frame); } static f32 GetFrameF32( const ResIntCurveFVData*, 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_, }; static const NormalizeFrameFunc postRepeatMethod[] = { NormalizeFrameNonePost_, NormalizeFrameRepeatPost_, NormalizeFrameMirrorPost_, }; 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 キーを検索するフレーム数です。セグメントの先頭を 0 とします。 @return キーフレームです。 *---------------------------------------------------------------------------*/ template const typename Traits::KeyType* GetKeyFV_( const Segment* pSegment, f32 frame ) { // この関数内での“フレーム”はセグメントの先頭を 0 としたフレーム数 typename Traits::FrameType quantizedFrame = Traits::QuantizedFrame( pSegment, 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 ) { // frame はセグメント先頭を 0 としたフレーム数 return GetKeyFV_( pSegment, frame ); } template f32 CalcStepFloatSegmentFV_( const ResFloatSegmentFVData* pSegment, f32 frame ) { // frame はセグメント先頭を 0 としたフレーム数 const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); return Traits::GetValue( pSegment, pKey ); } template f32 CalcLinearFloatSegmentFV_( const ResFloatSegmentFVData* pSegment, f32 frame ) { // frame はセグメント先頭を 0 としたフレーム数 const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); const typename Traits::KeyType* pLastKey = Traits::GetKey(pSegment, pSegment->m_NumFrameValues - 1); f32 keyFrame = Traits::GetFrameF32( pSegment, pKey ); if ( keyFrame == frame || pKey == pLastKey ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 nextKeyFrame = Traits::GetFrameF32( pSegment, 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 ) { // frame はセグメント先頭を 0 としたフレーム数 const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); const typename Traits::KeyType* pLastKey = Traits::GetKey(pSegment, pSegment->m_NumFrameValues - 1); f32 keyFrame = Traits::GetFrameF32( pSegment, pKey ); if ( keyFrame == frame || pKey == pLastKey ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 p = frame - keyFrame; f32 d = Traits::GetFrameF32( pSegment, 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 ) { // frame はセグメント先頭を 0 としたフレーム数 const typename Traits::KeyType* pKey = GetFloatKeyFV_( pSegment, frame ); const typename Traits::KeyType* pLastKey = Traits::GetKey(pSegment, pSegment->m_NumFrameValues - 1); // UNDONE: 同じフレームにキーが複数存在する場合の対処が必要。 f32 keyFrame = Traits::GetFrameF32( pSegment, pKey ); if ( keyFrame == frame || pKey == pLastKey ) { return Traits::GetValue( pSegment, pKey ); } const typename Traits::KeyType* pNextKey = pKey + 1; f32 p = frame - keyFrame; f32 d = Traits::GetFrameF32( pSegment, 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 if ( frame == pCurve->m_EndFrame ) { // 最終フレームが小数のときの特殊処理 // 小数フレームの場合は一つ手前の整数フレームのコマを引くが、 // 最終フレームに限っては次のコマにその値が保存してある。 u32 lastIndex = index + 1; const ResVector3CurveData::FrameValue& lastFrameValue = pCurve->frames.m_KeyValue[lastIndex]; *result = lastFrameValue.cv; *flags |= lastFrameValue.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 if ( frame == pCurve->m_EndFrame ) { // 最終フレームが小数のときの特殊処理 // 小数フレームの場合は一つ手前の整数フレームのコマを引くが、 // 最終フレームに限っては次のコマにその値が保存してある。 u32 lastIndex = index + 1; const ResVector4CurveData::FrameValue& lastFrameValue = pCurve->frames.m_KeyValue[lastIndex]; math::QUAT quaternion(lastFrameValue.cv); math::QUATToMTX34(&mtx, &quaternion); *flags |= lastFrameValue.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 if ( frame == pCurve->m_EndFrame ) { // 最終フレームが小数のときの特殊処理 // 小数フレームの場合は一つ手前の整数フレームのコマを引くが、 // 最終フレームに限っては次のコマにその値が保存してある。 u32 lastIndex = index + 1; const ResVector3CurveData::FrameValue& lastFrameValue = pCurve->frames.m_KeyValue[lastIndex]; result->f._03 = lastFrameValue.cv.x; result->f._13 = lastFrameValue.cv.y; result->f._23 = lastFrameValue.cv.z; *flags |= lastFrameValue.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 ); } void CalcTransformCurve( math::MTX34* result, const ResFullBakedCurveData* pCurve, f32 frame ) { NW_NULL_ASSERT( pCurve ); frame = NormalizeFrame_( frame, pCurve ); u32 index = u32(frame); // 最終フレームが小数の場合に対応する if (frame == pCurve->m_EndFrame) { // 「最後の整数フレームのコマ」の一つ先に、EndFrameのときの結果がベイクされている index += 1; } MTX34Copy( result, static_cast(&pCurve->frames.m_KeyValue[index]) ); } } /* namespace res */ } /* namespace anim */ } /* namespace nw */