csgo-2018-source/mdlobjects/dmeanimationassemblycommand.cpp
2021-07-24 21:11:47 -07:00

970 lines
29 KiB
C++

//===== 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() );
}
}