//===== Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ==== // // Animation commands // //========================================================================== // Valve includes #include "datamodel/dmelementfactoryhelper.h" #include "mdlobjects/dmeanimationassemblycommand.h" #include "mdlobjects/dmebonemask.h" #include "mdlobjects/dmesequence.h" #include "mdlobjects/mpp_utils.h" #include "bone_setup.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_DME_AAC, "DmeAnimationAssemblyCommand" ); //----------------------------------------------------------------------------- // Get the CDmeSequence & CDmeChannelsClip from the specified CDmElement //----------------------------------------------------------------------------- static bool ConvertToDmeSequenceAndDmeChannelsClip( CDmeSequence *&pDmeSequence, CDmeChannelsClip *&pDmeChannelsClip, CDmElement *pDmElement, const CUtlString &sDmElementId ) { if ( !pDmElement ) { Log_Error( LOG_DME_AAC, "%s: No DmElement Specified specified\n", sDmElementId.Get() ); return false; } CDmeSequence *pDmeSequenceTmp = CastElement< CDmeSequence >( pDmElement ); if ( !pDmeSequenceTmp ) { Log_Error( LOG_DME_AAC, "%s: No DmeSequence Specified specified\n", sDmElementId.Get() ); return false; } CDmeChannelsClip *pDmeChannelsClipTmp = pDmeSequenceTmp->GetDmeChannelsClip(); if ( !pDmeChannelsClipTmp ) { Log_Error( LOG_DME_AAC, "%s: Specified Sequence %s Has No DmeChannelsClip\n", sDmElementId.Get(), ComputeDmElementIdStr( pDmeSequenceTmp ).Get() ); return false; } pDmeSequence = pDmeSequenceTmp; pDmeChannelsClip = pDmeChannelsClipTmp; return true; } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmeAnimationAssemblyCommand, CDmeAnimationAssemblyCommand ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeAnimationAssemblyCommand::OnConstruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeAnimationAssemblyCommand::OnDestruction() { } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmeFixupLoop, CDmeFixupLoop ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeFixupLoop::OnConstruction() { m_nStartFrame.Init( this, "startFrame" ); m_nEndFrame.Init( this, "endFrame" ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeFixupLoop::OnDestruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- bool CDmeFixupLoop::Apply( CDmElement *pDmElement ) { CDmeSequence *pDmeSequenceDst = NULL; CDmeChannelsClip *pDmeChannelsClipDst = NULL; if ( !ConvertToDmeSequenceAndDmeChannelsClip( pDmeSequenceDst, pDmeChannelsClipDst, pDmElement, ComputeDmElementIdStr( this ) ) ) return false; const DmeFramerate_t dmeFrameRateDst = pDmeSequenceDst->GetFrameRate(); const int nFrameCountDst = pDmeSequenceDst->GetFrameCount(); int nStartFrame = m_nStartFrame.Get(); int nEndFrame = m_nEndFrame.Get(); // Make sure loop doesn't exceed animation length if ( nEndFrame - nStartFrame > nFrameCountDst ) { nEndFrame = nFrameCountDst + nStartFrame; if ( nEndFrame < 0 ) { nEndFrame = 0; nStartFrame = -( nFrameCountDst - 1 ); } } DmeTime_t nStartTime( nStartFrame, dmeFrameRateDst ); DmeTime_t nEndTime( nEndFrame, dmeFrameRateDst ); for ( int i = 0; i < pDmeChannelsClipDst->m_Channels.Count(); ++i ) { CDmeChannel *pDmeChannelDst = pDmeChannelsClipDst->m_Channels[i]; if ( !pDmeChannelDst ) continue; CDmeLog *pDmeLogDst = pDmeChannelDst->GetLog(); if ( !pDmeLogDst ) continue; CDmeVector3Log *pDmeVector3LogDst = CastElement< CDmeVector3Log >( pDmeLogDst ); if ( pDmeVector3LogDst ) { Apply( pDmeVector3LogDst, nStartTime, nEndTime ); continue; } CDmeQuaternionLog *pDmeQuaternionLogDst = CastElement< CDmeQuaternionLog >( pDmeLogDst ); if ( pDmeQuaternionLogDst ) { Apply( pDmeQuaternionLogDst, nStartTime, nEndTime ); continue; } // ERROR - Unsupported log type Log_Warning( LOG_DME_AAC, "%s: Unsupported DmeLog Type: \"%s\"\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeSequenceDst ).Get() ); } return true; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template < class T > void ComputeDelta( T &result, const T &a, const T &b ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template<> void ComputeDelta< Vector >( Vector &vResult, const Vector &vA, const Vector &vB ) { VectorSubtract( vA, vB, vResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template<> void ComputeDelta< Quaternion >( Quaternion &qResult, const Quaternion &qA, const Quaternion &qB ) { QuaternionMA( qA, -1.0f, qB, qResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template < class T > void AddScaledDelta( T &result, float flScale, const T &a, const T &b ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template<> void AddScaledDelta< Vector >( Vector &vResult, float flScale, const Vector &vDelta, const Vector &vOrig ) { VectorMA( vOrig, flScale, vDelta, vResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template<> void AddScaledDelta< Quaternion >( Quaternion &qResult, float flScale, const Quaternion &qDelta, const Quaternion &qOrig ) { QuaternionSM( flScale, qDelta, qOrig, qResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template < class T > void CDmeFixupLoop::Apply( CDmeTypedLog< T > *pDmeTypedLogDst, const DmeTime_t &dmeTimeStart, const DmeTime_t &dmeTimeEnd ) const { if ( !pDmeTypedLogDst ) return; const DmeTime_t dmeTimeRange( dmeTimeEnd - dmeTimeStart ); if ( dmeTimeRange.GetSeconds() <= 0.0 ) return; if ( dmeTimeStart.GetSeconds() > 0.0f ) return; const float flTimeRange = dmeTimeRange.GetSeconds(); const int nKeyCount = pDmeTypedLogDst->GetKeyCount(); if ( nKeyCount <= 0 ) return; CUtlVector< DmeTime_t > times; CUtlVector< T > values; for ( int i = 0; i < nKeyCount; ++i ) { times.AddToTail( pDmeTypedLogDst->GetKeyTime( i ) ); values.AddToTail( pDmeTypedLogDst->GetKeyValue( i ) ); } Assert( nKeyCount == pDmeTypedLogDst->GetKeyCount() ); T delta; ComputeDelta< T >( delta, values[ nKeyCount - 1 ], values[ 0 ] ); T newValue; if ( dmeTimeStart.GetSeconds() < 0.0f ) { const DmeTime_t dmeTimeBegin = times[ nKeyCount - 1 ] + dmeTimeStart; for ( int nKeyIndex = 0; nKeyIndex < nKeyCount; ++nKeyIndex ) { const DmeTime_t &dmeTimeKey = times[ nKeyIndex ]; if ( dmeTimeKey < dmeTimeBegin ) continue; float flScale = ( dmeTimeKey - dmeTimeBegin ).GetSeconds() / flTimeRange; flScale = 3.0f * flScale * flScale - 2.0f * flScale * flScale * flScale; AddScaledDelta( newValue, -flScale, delta, values[ nKeyIndex ] ); values[ nKeyIndex ] = newValue; } } if ( dmeTimeEnd.GetSeconds() > 0.0f ) { const DmeTime_t dmeTimeBegin = times[ 0 ]; for ( int nKeyIndex = 0; nKeyIndex < nKeyCount; ++nKeyIndex ) { const DmeTime_t dmeTimeKey = times[ nKeyIndex ]; if ( dmeTimeKey > dmeTimeEnd ) break; float flScale = ( dmeTimeEnd - ( dmeTimeKey - dmeTimeBegin ) ).GetSeconds() / flTimeRange; flScale = 3.0f * flScale * flScale - 2.0f * flScale * flScale * flScale; AddScaledDelta( newValue, flScale, delta, values[ nKeyIndex ] ); values[ nKeyIndex ] = newValue; } } CDmeTypedLogLayer< T > *pDmeTypedLogLayer = CastElement< CDmeTypedLogLayer< T > >( pDmeTypedLogDst->AddNewLayer() ); if ( pDmeTypedLogLayer ) { pDmeTypedLogLayer->SetAllKeys( times, values ); } } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmeSubtract, CDmeSubtract ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeSubtract::OnConstruction() { m_eSequence.Init( this, "sequence", FATTRIB_NEVERCOPY ); m_nFrame.Init( this, "frame" ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeSubtract::OnDestruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- bool CDmeSubtract::Apply( CDmElement *pDmElement ) { CDmeSequence *pDmeSequenceDst = NULL; CDmeChannelsClip *pDmeChannelsClipDst = NULL; if ( !ConvertToDmeSequenceAndDmeChannelsClip( pDmeSequenceDst, pDmeChannelsClipDst, pDmElement, ComputeDmElementIdStr( this ) ) ) return false; CDmeSequence *pDmeSequenceSrc = NULL; CDmeChannelsClip *pDmeChannelsClipSrc = NULL; if ( !ConvertToDmeSequenceAndDmeChannelsClip( pDmeSequenceSrc, pDmeChannelsClipSrc, m_eSequence.GetElement(), ComputeDmElementIdStr( this ) ) ) return false; const DmeFramerate_t dmeFrameRateSrc = pDmeSequenceSrc->GetFrameRate(); const DmeTime_t dmeTimeSrc( m_nFrame.Get(), dmeFrameRateSrc ); if ( dmeTimeSrc < pDmeChannelsClipSrc->GetStartTime() ) { Log_Warning( LOG_DME_AAC, "%s: .%s %d (%.2fs @ %g fps) < %s Start Time of %.2fs\n", ComputeDmElementIdStr( this ).Get(), m_nFrame.GetAttribute()->GetName(), m_nFrame.Get(), dmeTimeSrc.GetSeconds(), dmeFrameRateSrc.GetFramesPerSecond(), ComputeDmElementIdStr( pDmeSequenceSrc ).Get(), pDmeChannelsClipSrc->GetStartTime().GetSeconds() ); } if ( dmeTimeSrc > pDmeChannelsClipSrc->GetEndTime() ) { Log_Warning( LOG_DME_AAC, "%s: .%s %d (%.2fs @ %g fps) > %s End Time of %.2fs\n", ComputeDmElementIdStr( this ).Get(), m_nFrame.GetAttribute()->GetName(), m_nFrame.Get(), dmeTimeSrc.GetSeconds(), dmeFrameRateSrc.GetFramesPerSecond(), ComputeDmElementIdStr( pDmeSequenceSrc ).Get(), pDmeChannelsClipSrc->GetEndTime().GetSeconds() ); } // Match up channels by name. for ( int i = 0; i < pDmeChannelsClipDst->m_Channels.Count(); ++i ) { CDmeChannel *pDmeChannelDst = pDmeChannelsClipDst->m_Channels[i]; if ( !pDmeChannelDst ) continue; CDmeLog *pDmeLogDst = pDmeChannelDst->GetLog(); if ( !pDmeLogDst ) continue; const char *pszDmeChannelName = pDmeChannelDst->GetName(); CDmeVector3Log *pDmeVector3LogDst = CastElement< CDmeVector3Log >( pDmeLogDst ); CDmeQuaternionLog *pDmeQuaternionLogDst = CastElement< CDmeQuaternionLog >( pDmeLogDst ); bool bFound = false; for ( int j = 0; j < pDmeChannelsClipSrc->m_Channels.Count(); ++j ) { CDmeChannel *pDmeChannelSrc = pDmeChannelsClipSrc->m_Channels[j]; if ( !pDmeChannelSrc || Q_stricmp( pszDmeChannelName, pDmeChannelSrc->GetName() ) ) continue; CDmeLog *pDmeLogSrc = pDmeChannelSrc->GetLog(); if ( !pDmeLogDst ) continue; CDmeVector3Log *pDmeVector3LogSrc = CastElement< CDmeVector3Log >( pDmeLogSrc ); if ( pDmeVector3LogSrc && pDmeVector3LogDst ) { Subtract( pDmeVector3LogDst, pDmeVector3LogSrc, dmeTimeSrc ); bFound = true; continue; } CDmeQuaternionLog *pDmeQuaternionLogSrc = CastElement< CDmeQuaternionLog >( pDmeLogSrc ); if ( pDmeQuaternionLogSrc && pDmeQuaternionLogDst ) { Subtract( pDmeQuaternionLogDst, pDmeQuaternionLogSrc, dmeTimeSrc ); bFound = true; continue; } } if ( !bFound ) { Log_Warning( LOG_DME_AAC, "%s: No Channel Found To Subtract From %s\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeChannelDst ).Get() ); } } return true; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template< class T > void CDmeSubtract::Subtract( CDmeTypedLog< T > *pDmeTypedLogDst, const CDmeTypedLog< T > *pDmeTypedLogSrc, const DmeTime_t &dmeTimeSrc ) const { const T valueSrc = pDmeTypedLogSrc->GetValue( dmeTimeSrc ); CUtlVector< DmeTime_t > times; CUtlVector< T > values; T valueDst; for ( int i = 0; i < pDmeTypedLogDst->GetKeyCount(); ++i ) { times.AddToTail( pDmeTypedLogDst->GetKeyTime( i ) ); Subtract( valueDst, pDmeTypedLogDst->GetKeyValue( i ), valueSrc ); values.AddToTail( valueDst ); } CDmeTypedLogLayer< T > *pDmeTypedLogLayer = CastElement< CDmeTypedLogLayer< T > >( pDmeTypedLogDst->AddNewLayer() ); if ( pDmeTypedLogLayer ) { pDmeTypedLogLayer->SetAllKeys( times, values ); } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeSubtract::Subtract( Vector &vResult, const Vector &vDst, const Vector &vSrc ) const { VectorSubtract( vDst, vSrc, vResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeSubtract::Subtract( Quaternion &qResult, const Quaternion &qDst, const Quaternion &qSrc ) const { QuaternionSM( -1, qSrc, qDst, qResult ); } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmePreSubtract, CDmePreSubtract ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmePreSubtract::OnConstruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmePreSubtract::OnDestruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmePreSubtract::Subtract( Vector &vResult, const Vector &vDst, const Vector &vSrc ) const { VectorSubtract( vSrc, vDst, vResult ); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmePreSubtract::Subtract( Quaternion &qResult, const Quaternion &qDst, const Quaternion &qSrc ) const { QuaternionMA( qDst, -1, qSrc, qResult ); } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmeRotateTo, CDmeRotateTo ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeRotateTo::OnConstruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeRotateTo::OnDestruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- bool CDmeRotateTo::Apply( CDmElement *pDmElement ) { CDmeSequence *pDmeSequenceDst = NULL; CDmeChannelsClip *pDmeChannelsClipDst = NULL; if ( !ConvertToDmeSequenceAndDmeChannelsClip( pDmeSequenceDst, pDmeChannelsClipDst, pDmElement, ComputeDmElementIdStr( this ) ) ) return false; CDmeDag *pDmeDag = pDmeSequenceDst->m_eSkeleton.GetElement(); if ( !pDmeDag ) { Log_Error( LOG_DME_AAC, "%s: Specified Sequence %s Has No Skeleton\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeSequenceDst ).Get() ); return false; } // If the skeleton is a CDmeModel then all children of the skeleton // are nodes that have no parent, i.e. root nodes which must be // adjusted, otherwise if it's a normal DmeDag assume it's the only // root node of the skeleton CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag ); if ( pDmeModel ) { for ( int i = 0; i < pDmeModel->GetChildCount(); ++i ) { SubApply( pDmeModel->GetChild( i ), pDmeChannelsClipDst, pDmeModel->IsZUp() ); } } else { Log_Warning( LOG_DME_AAC, "%s: Cannot Determine If Sequence %s Is Y Or Z Up, Assuming Z Up\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeSequenceDst ).Get() ); SubApply( pDmeDag, pDmeChannelsClipDst, true ); } return true; } //----------------------------------------------------------------------------- // Find the translate & rotate channels and logs which refer to the specified // DmeDag //----------------------------------------------------------------------------- static bool GetDmeChannelsForDag( CDmeTypedLog< Vector > *&pDmeTranslateLog, CDmeTypedLog< Quaternion > *&pDmeRotateLog, CDmeDag *pDmeDag, CDmeChannelsClip *pDmeChannelsClip ) { pDmeTranslateLog = NULL; pDmeRotateLog = NULL; if ( !pDmeDag || !pDmeChannelsClip ) return false; CDmeTransform *pDmeTransform = pDmeDag->GetTransform(); if ( !pDmeTransform ) return false; for ( int i = 0; pDmeChannelsClip->m_Channels.Count(); ++i ) { CDmeChannel *pDmeChannel = pDmeChannelsClip->m_Channels[i]; if ( !pDmeChannel ) continue; if ( pDmeChannel->GetToElement() != pDmeTransform ) continue; CDmeLog *pDmeLog = pDmeChannel->GetLog(); if ( !pDmeLog ) continue; CDmeTypedLog< Vector > *pDmeTranslateLogTmp = CastElement< CDmeTypedLog< Vector > >( pDmeLog ); if ( pDmeTranslateLogTmp ) { if ( pDmeTranslateLog == NULL ) { pDmeTranslateLog = pDmeTranslateLogTmp; // Quit if we've found both translate & rotate if ( pDmeRotateLog ) break; } else { Log_Warning( LOG_DME_AAC, "%s: Multiple Translate Channels Found For Dag, Using %s, Ignoring %s\n", ComputeDmElementIdStr( pDmeDag ).Get(), ComputeDmElementIdStr( pDmeTranslateLog ).Get(), ComputeDmElementIdStr( pDmeChannel ).Get() ); } continue; } CDmeTypedLog< Quaternion > *pDmeRotateLogTmp = CastElement< CDmeTypedLog< Quaternion > >( pDmeLog ); if ( pDmeRotateLogTmp ) { if ( pDmeRotateLog == NULL ) { pDmeRotateLog = pDmeRotateLogTmp; // Quit if we've found both translate & rotate if ( pDmeTranslateLog ) break; } else { Log_Warning( LOG_DME_AAC, "%s: Multiple Rotate Channels Found For Dag, Using %s, Ignoring %s\n", ComputeDmElementIdStr( pDmeDag ).Get(), ComputeDmElementIdStr( pDmeRotateLog ).Get(), ComputeDmElementIdStr( pDmeChannel ).Get() ); } continue; } } return pDmeTranslateLog != NULL && pDmeRotateLog != NULL; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- static void ComputeMergedKeyTimes( CUtlVector< DmeTime_t > &mergedTimes, CDmeLog *pDmeLogA, CDmeLog *pDmeLogB ) { mergedTimes.RemoveAll(); CUtlRBTree< DmeTime_t > timesTree( CDefOps< DmeTime_t >::LessFunc ); for ( int i = 0; i < 2; ++i ) { CDmeLog *pDmeLog = ( i == 0 ) ? pDmeLogA : pDmeLogB; if ( !pDmeLog ) continue; for ( int j = 0; j < pDmeLog->GetKeyCount(); ++j ) { timesTree.InsertIfNotFound( pDmeLog->GetKeyTime( j ) ); } } for ( CUtlRBTree< DmeTime_t >::IndexType_t i = timesTree.FirstInorder(); timesTree.IsValidIndex( i ); i = timesTree.NextInorder( i ) ) { mergedTimes.AddToTail( timesTree.Element( i ) ); } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template < class T > static void GetAllKeys( CUtlVector< DmeTime_t > &keyTimes, CUtlVector< T > &keyValues, CDmeTypedLog< T > *pDmeTypedLog ) { keyTimes.RemoveAll(); keyValues.RemoveAll(); const int nKeyCount = pDmeTypedLog->GetKeyCount(); if ( nKeyCount <= 0 ) return; keyTimes.EnsureCapacity( nKeyCount ); keyValues.EnsureCapacity( nKeyCount ); Assert( keyTimes.Count() == 0 ); Assert( keyValues.Count() == 0 ); for ( int i = 0; i < nKeyCount; ++i ) { keyTimes.AddToTail( pDmeTypedLog->GetKeyTime( i ) ); keyValues.AddToTail( pDmeTypedLog->GetKeyValue( i ) ); } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeRotateTo::SubApply( CDmeDag *pDmeDag, CDmeChannelsClip *pDmeChannelsClip, bool bZUp ) { if ( !pDmeDag || !pDmeChannelsClip ) return; CDmeTransform *pDmeTransform = pDmeDag->GetTransform(); if ( !pDmeTransform ) return; CDmeTypedLog< Vector > *pDmeTranslateLog = NULL; CDmeTypedLog< Quaternion > *pDmeRotateLog = NULL; if ( !GetDmeChannelsForDag( pDmeTranslateLog, pDmeRotateLog, pDmeDag, pDmeChannelsClip ) ) { Log_Error( LOG_DME_AAC, "%s: Couldn't Find Translate & Rotate channels for DmeDag %s\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeDag ).Get() ); return; } Assert( pDmeTranslateLog && pDmeRotateLog ); matrix3x4_t mRoot; { float flDeltaAngle = 0.0f; const DmeTime_t dmeTimeBegin = pDmeTranslateLog->GetBeginTime(); const DmeTime_t dmeTimeEnd = pDmeTranslateLog->GetEndTime(); const Vector vPos( pDmeTranslateLog->GetValue( dmeTimeEnd ) - pDmeTranslateLog->GetValue( dmeTimeBegin ) ); // TODO: Handle Y/Z Up if ( bZUp ) { // ZUp if ( vPos.x != 0.0f || vPos.y != 0.0f ) { const float flAngle = atan2( vPos.y, vPos.x ) * ( 180.0f / M_PI ); flDeltaAngle = m_flAngle.Get() - flAngle; } AngleMatrix( QAngle( 0.0f, flDeltaAngle, 0.0f ), mRoot ); } else { // YUp if ( vPos.x != 0.0f || vPos.z != 0.0f ) { const float flAngle = atan2( vPos.x, vPos.z ) * ( 180.0f / M_PI ); flDeltaAngle = m_flAngle.Get() - flAngle; } AngleMatrix( QAngle( flDeltaAngle, 0.0f, 0.0f ), mRoot ); } } matrix3x4_t mSrc; matrix3x4_t mDst; CUtlVector< DmeTime_t > mergedKeyTimes; ComputeMergedKeyTimes( mergedKeyTimes, pDmeTranslateLog, pDmeRotateLog ); Vector vTmp; CUtlVector< Vector > vValues; Quaternion qTmp; CUtlVector< Quaternion > qValues; for ( int i = 0; i < mergedKeyTimes.Count(); ++i ) { const DmeTime_t &dmeTime = mergedKeyTimes[i]; AngleMatrix( RadianEuler( pDmeRotateLog->GetValue( dmeTime ) ), pDmeTranslateLog->GetValue( dmeTime ), mSrc ); ConcatTransforms( mRoot, mSrc, mDst ); MatrixAngles( mDst, qTmp, vTmp ); vValues.AddToTail( vTmp ); qValues.AddToTail( qTmp ); } CDmeTypedLogLayer< Vector > *pDmeTranslateLayer = CastElement< CDmeTypedLogLayer< Vector > >( pDmeTranslateLog->AddNewLayer() ); if ( pDmeTranslateLayer ) { pDmeTranslateLayer->SetAllKeys( mergedKeyTimes, vValues ); pDmeTranslateLayer->RemoveRedundantKeys( true ); } else { Log_Error( LOG_DME_AAC, "%s: Couldn't Create Translate Layer\n", ComputeDmElementIdStr( this ).Get() ); } CDmeTypedLogLayer< Quaternion > *pDmeRotateLayer = CastElement< CDmeTypedLogLayer< Quaternion > >( pDmeRotateLog->AddNewLayer() ); if ( pDmeRotateLayer ) { pDmeRotateLayer->SetAllKeys( mergedKeyTimes, qValues ); pDmeRotateLayer->RemoveRedundantKeys( true ); } else { Log_Error( LOG_DME_AAC, "%s: Couldn't Create Rotate Layer\n", ComputeDmElementIdStr( this ).Get() ); } } //----------------------------------------------------------------------------- // Expose this class to the scene database //----------------------------------------------------------------------------- IMPLEMENT_ELEMENT_FACTORY( DmeBoneMaskCmd, CDmeBoneMaskCmd ); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeBoneMaskCmd::OnConstruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeBoneMaskCmd::OnDestruction() { } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- bool CDmeBoneMaskCmd::Apply( CDmElement *pDmElement ) { CDmeSequence *pDmeSequenceDst = NULL; CDmeChannelsClip *pDmeChannelsClipDst = NULL; if ( !ConvertToDmeSequenceAndDmeChannelsClip( pDmeSequenceDst, pDmeChannelsClipDst, pDmElement, ComputeDmElementIdStr( this ) ) ) return false; CDmeDag *pDmeDag = pDmeSequenceDst->m_eSkeleton.GetElement(); if ( !pDmeDag ) { Log_Error( LOG_DME_AAC, "%s: Specified Sequence %s Has No Skeleton\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeSequenceDst ).Get() ); return false; } CDmeBoneMask *pDmeBoneMask = pDmeSequenceDst->m_eBoneMask.GetElement(); if ( !pDmeBoneMask ) { Log_Error( LOG_DME_AAC, "%s: Specified Sequence %s Has No Bone Mask\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeSequenceDst ).Get() ); return false; } CUtlStack< CDmeDag * > depthFirstStack; depthFirstStack.Push( pDmeDag ); while ( depthFirstStack.Count() ) { depthFirstStack.Pop( pDmeDag ); if ( !pDmeDag ) continue; for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { depthFirstStack.Push( pDmeDag->GetChild( i ) ); } SubApply( pDmeChannelsClipDst, pDmeDag, pDmeBoneMask ); } return true; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDmeBoneMaskCmd::SubApply( CDmeChannelsClip *pDmeChannelsClip, CDmeDag *pDmeDag, CDmeBoneMask *pDmeBoneMask ) { if ( !pDmeChannelsClip || !pDmeDag || !pDmeBoneMask ) return; const float flWeight = pDmeBoneMask->GetBoneWeight( pDmeDag->GetName() ); // Nothing to do if full weight if ( flWeight == 1.0f ) return; CDmeTransform *pDmeTransform = pDmeDag->GetTransform(); if ( !pDmeTransform ) return; CDmeTypedLog< Vector > *pDmeTranslateLog = NULL; CDmeTypedLog< Quaternion > *pDmeRotateLog = NULL; if ( !GetDmeChannelsForDag( pDmeTranslateLog, pDmeRotateLog, pDmeDag, pDmeChannelsClip ) ) { Log_Error( LOG_DME_AAC, "%s: Couldn't Find Translate & Rotate channels for DmeDag %s\n", ComputeDmElementIdStr( this ).Get(), ComputeDmElementIdStr( pDmeDag ).Get() ); return; } Vector vTmp; CUtlVector< DmeTime_t > vTimes; CUtlVector< Vector > vValues; GetAllKeys( vTimes, vValues, pDmeTranslateLog ); for ( int i = 0; i < vValues.Count(); ++i ) { VectorScale( vValues[i], flWeight, vTmp ); vValues[i] = vTmp; } Quaternion qTmp; CUtlVector< DmeTime_t > qTimes; CUtlVector< Quaternion > qValues; GetAllKeys( qTimes, qValues, pDmeRotateLog ); for ( int i = 0; i < qValues.Count(); ++i ) { QuaternionScale( qValues[i], flWeight, qTmp ); qValues[i] = qTmp; } CDmeTypedLogLayer< Vector > *pDmeTranslateLayer = CastElement< CDmeTypedLogLayer< Vector > >( pDmeTranslateLog->AddNewLayer() ); if ( pDmeTranslateLayer ) { pDmeTranslateLayer->SetAllKeys( vTimes, vValues ); pDmeTranslateLayer->RemoveRedundantKeys( true ); } else { Log_Error( LOG_DME_AAC, "%s: Couldn't Create Translate Layer\n", ComputeDmElementIdStr( this ).Get() ); } CDmeTypedLogLayer< Quaternion > *pDmeRotateLayer = CastElement< CDmeTypedLogLayer< Quaternion > >( pDmeRotateLog->AddNewLayer() ); if ( pDmeRotateLayer ) { pDmeRotateLayer->SetAllKeys( qTimes, qValues ); pDmeRotateLayer->RemoveRedundantKeys( true ); } else { Log_Error( LOG_DME_AAC, "%s: Couldn't Create Rotate Layer\n", ComputeDmElementIdStr( this ).Get() ); } }