970 lines
29 KiB
C++
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() );
|
|
}
|
|
} |