|
|
//====== Copyright (c) 1996-2009, Valve Corporation, All rights reserved. =====
//
// Purpose:
//
//=============================================================================
// Valve includes
#include "tier1/utlstack.h"
#include "movieobjects/dmeanimationlist.h"
#include "movieobjects/dmechannel.h"
#include "movieobjects/dmeconnectionoperator.h"
#include "movieobjects/dmelog.h"
#include "mdlobjects/dmebbox.h"
#include "mdlobjects/dmebodygrouplist.h"
#include "mdlobjects/dmebodygroup.h"
#include "mdlobjects/dmecollisionmodel.h"
#include "mdlobjects/dmeeyeball.h"
#include "mdlobjects/dmeeyeballglobals.h"
#include "mdlobjects/dmeik.h"
#include "mdlobjects/dmelodlist.h"
#include "mdlobjects/dmelod.h"
#include "mdlobjects/dmesequencelist.h"
#include "mdlobjects/dmesequence.h"
#include "mdlobjects/dmedefinebonelist.h"
#include "mdlobjects/dmedefinebone.h"
#include "mdlobjects/mpp_utils.h"
//-----------------------------------------------------------------------------
// Returns the matrix & quaternion to reorient
//-----------------------------------------------------------------------------
void GetReorientData( matrix3x4_t &m, Quaternion &q, bool bMakeZUp ) { if ( bMakeZUp ) { static const matrix3x4_t mYtoZ( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f );
m = mYtoZ; } else { static const matrix3x4_t mZtoY( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f );
m = mZtoY; }
MatrixQuaternion( m, q ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientDmeAnimation( CDmeDag *pDmeDag, const matrix3x4_t &mOrient, const Quaternion &qOrient ) { if ( !pDmeDag ) return;
CUtlVector< CDmeChannel * > dmeChannelList;
if ( !FindReferringElements( dmeChannelList, pDmeDag->GetTransform(), g_pDataModel->GetSymbol( "toElement" ) ) || dmeChannelList.Count() < 0 ) return;
const int nDmeChannelCount = dmeChannelList.Count(); for ( int i = 0; i < nDmeChannelCount; ++i ) { CDmeChannel *pDmeChannel = dmeChannelList[ i ]; if ( !pDmeChannel ) continue;
CDmeLog *pDmeLog = pDmeChannel->GetLog(); if ( !pDmeLog ) continue;
const int nLogLayerCount = pDmeLog->GetNumLayers(); for ( int j = 0; j < nLogLayerCount; ++j ) { CDmeLogLayer *pDmeLogLayer = pDmeLog->GetLayer( j );
CDmeVector3LogLayer *pDmeVector3LogLayer = CastElement< CDmeVector3LogLayer >( pDmeLogLayer ); if ( pDmeVector3LogLayer ) { RotatePositionLog( pDmeVector3LogLayer, mOrient ); continue; }
CDmeQuaternionLogLayer *pDmeQuaternionLogLayer = CastElement< CDmeQuaternionLogLayer >( pDmeLogLayer ); if ( pDmeQuaternionLogLayer ) { RotateOrientationLog( pDmeQuaternionLogLayer, mOrient, true ); continue; } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientDmeTransform( CDmeTransform *pDmeTransform, const matrix3x4_t &mOrient, const Quaternion &qOrient ) { if ( !pDmeTransform ) return;
Vector vTmp; VectorRotate( pDmeTransform->GetPosition(), mOrient, vTmp ); pDmeTransform->SetPosition( vTmp );
Quaternion qTmp; QuaternionMult( qOrient, pDmeTransform->GetOrientation(), qTmp ); pDmeTransform->SetOrientation( qTmp ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientDmeDefineBone( CDmeDefineBone *pDmeDefineBone, const matrix3x4_t &mOrient, const Quaternion &qOrient ) { if ( !pDmeDefineBone ) return;
Vector vTmp; VectorRotate( pDmeDefineBone->m_Translation, mOrient, vTmp ); pDmeDefineBone->m_Translation = vTmp;
Quaternion qTmp0; Quaternion qTmp1; QAngle aTmp; AngleQuaternion( pDmeDefineBone->m_Rotation, qTmp0 ); QuaternionMult( qOrient, qTmp0, qTmp1 ); QuaternionAngles( qTmp1, aTmp ); pDmeDefineBone->m_Rotation = aTmp;
// Don't touch realign rotation for now
/*
VectorRotate( pDmeDefineBone->m_RealignTranslation, mOrient, vTmp ); pDmeDefineBone->m_RealignTranslation = vTmp;
AngleQuaternion( pDmeDefineBone->m_RealignRotation, qTmp0 ); QuaternionMult( qOrient, qTmp0, qTmp1 ); QuaternionAngles( qTmp1, aTmp ); pDmeDefineBone->m_RealignRotation = aTmp; */ }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientDmeModelChildren( CDmeModel *pDmeModel, const matrix3x4_t &mOrient, const Quaternion &qOrient, CDmeDefineBoneList *pDmeDefineBoneList, bool bDefineBoneDone ) { if ( !pDmeModel ) return;
CDmeTransformList *pDmeTransformList = pDmeModel->FindBaseState( "bind" ); const int nTransformCount = pDmeTransformList ? pDmeTransformList->GetTransformCount() : 0;
const int nChildCount = pDmeModel->GetChildCount(); for ( int i = 0; i < nChildCount; ++i ) { CDmeDag *pDmeDag = pDmeModel->GetChild( i ); if ( !pDmeDag ) continue;
ReorientDmeTransform( pDmeDag->GetTransform(), mOrient, qOrient );
// TODO: Separate out DmeDefineBoneList
if ( !bDefineBoneDone && pDmeDefineBoneList ) { for ( int j = 0; j < pDmeDefineBoneList->m_DefineBones.Count(); ++j ) { CDmeDefineBone *pDmeDefineBone = pDmeDefineBoneList->m_DefineBones[j]; if ( !pDmeDefineBone ) continue;
if ( Q_strcmp( pDmeDag->GetName(), pDmeDefineBone->GetName() ) ) continue;
ReorientDmeDefineBone( pDmeDefineBone, mOrient, qOrient ); } }
if ( pDmeTransformList ) { int nJointIndex = pDmeModel->GetJointIndex( pDmeDag ); if ( nJointIndex >= 0 && nJointIndex < nTransformCount ) { ReorientDmeTransform( pDmeTransformList->GetTransform( nJointIndex ), mOrient, qOrient ); } }
ReorientDmeAnimation( pDmeDag, mOrient, qOrient ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ReorientDmeModel( CDmeModel *pDmeModel, bool bMakeZUp, CDmeDefineBoneList *pDmeDefineBoneList, bool bDefineBoneDone ) { if ( !pDmeModel ) return false;
if ( bMakeZUp == pDmeModel->IsZUp() ) return true; // Nothing to do
matrix3x4_t m; Quaternion q;
GetReorientData( m, q, bMakeZUp );
ReorientDmeModelChildren( pDmeModel, m, q, pDmeDefineBoneList, bDefineBoneDone );
pDmeModel->ZUp( true );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ReorientDmeModel( CDmeModel *pDmeModel, bool bMakeZUp ) { return ReorientDmeModel( pDmeModel, bMakeZUp, NULL, true ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool ReorientDmxModelFile( CDmElement *pDmElementRoot, bool bMakeZUp ) { if ( !pDmElementRoot ) return false;
const bool bModel = ReorientDmeModel( pDmElementRoot->GetValueElement< CDmeModel >( "model" ), bMakeZUp ); const bool bSkel = ReorientDmeModel( pDmElementRoot->GetValueElement< CDmeModel >( "skeleton" ), bMakeZUp );
const char *pSrcFile = g_pDataModel->GetFileName( pDmElementRoot->GetFileId() ); if ( pSrcFile && *pSrcFile ) { char szPath[ MAX_PATH ];
Q_strncpy( szPath, pSrcFile, sizeof( szPath ) ); Q_SetExtension( szPath, "zup", sizeof( szPath ) ); g_pDataModel->SaveToFile( szPath, NULL, "keyvalues2", "model", pDmElementRoot ); }
return bModel || bSkel; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientIkRuleList( CDmeSequence *pDmeSimpleSequence, const matrix3x4_t &m ) { if ( !pDmeSimpleSequence ) return;
const int nIkRuleCount = pDmeSimpleSequence->m_eIkRuleList.Count(); if ( nIkRuleCount <= 0 ) return;
for ( int i = 0; i < nIkRuleCount; ++i ) { CDmeIkRule *pDmeIkRule = pDmeSimpleSequence->m_eIkRuleList[ i ]; if ( !pDmeIkRule ) continue;
CDmeIkAttachmentRule *pDmeIkAttachmentRule = CastElement< CDmeIkAttachmentRule >( pDmeIkRule ); if ( pDmeIkAttachmentRule ) { if ( pDmeIkAttachmentRule->HasAttribute( "fallbackPosition", AT_VECTOR3 ) ) { Vector p; VectorIRotate( pDmeIkAttachmentRule->GetValue< Vector >( "fallbackPosition" ), m, p ); pDmeIkAttachmentRule->SetValue< Vector >( "fallbackPosition", p ); } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientSequenceList( CDmeSequenceList *pDmeSequenceList, bool bMakeZUp, const matrix3x4_t &m ) { if ( !pDmeSequenceList ) return;
const int nSequenceCount = pDmeSequenceList->m_Sequences.Count(); for ( int i = 0; i < nSequenceCount; ++i ) { CDmeSequence *pDmeSimpleSequence = CastElement< CDmeSequence >( pDmeSequenceList->m_Sequences[i] ); if ( !pDmeSimpleSequence ) continue;
ReorientDmeModel( CastElement< CDmeModel >( pDmeSimpleSequence->m_eSkeleton.GetElement() ), bMakeZUp );
ReorientIkRuleList( pDmeSimpleSequence, m ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientGlobalFlags( CDmElement *pDmeRoot, const matrix3x4_t &m ) { if ( !pDmeRoot ) return;
CDmeBBox *pDmeBBox = pDmeRoot->GetValueElement< CDmeBBox >( "bbox" ); if ( pDmeBBox ) { Vector bbmn; Vector bbmx;
ITransformAABB( m, pDmeBBox->m_vMinBounds, pDmeBBox->m_vMaxBounds, bbmn, bbmx ); pDmeBBox->m_vMinBounds = bbmn; pDmeBBox->m_vMaxBounds = bbmx; }
if ( pDmeRoot->HasAttribute( "illuminationPosition", AT_VECTOR3 ) ) { Vector vIllumPosition; VectorIRotate( pDmeRoot->GetValue< Vector >( "illuminationPosition" ), m, vIllumPosition ); pDmeRoot->SetValue< Vector >( "illuminationPosition", vIllumPosition ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientEyeballGlobals( CDmeEyeballGlobals *pDmeEyeballGlobals, const matrix3x4_t &m ) { if ( !pDmeEyeballGlobals ) return;
Vector vEyePosition; VectorIRotate( pDmeEyeballGlobals->m_vEyePosition.Get(), m, vEyePosition ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientEyeballs( CDmeLODList *pDmeLODList, const matrix3x4_t &m ) { if ( !pDmeLODList ) return;
const int nEyeballCount = pDmeLODList->m_EyeballList.Count(); if ( nEyeballCount <= 0 ) return;
for ( int nEyeballIndex = 0; nEyeballIndex < nEyeballCount; ++nEyeballIndex ) { CDmeEyeball *pDmeEyeball = pDmeLODList->m_EyeballList.Get( nEyeballIndex ); if ( !pDmeEyeball ) continue; } }
//-----------------------------------------------------------------------------
//
// Returns true is the rest of the MPP file should be reoriented
// Returns false if the orientation could not be determined or
// it's already oriented correctly
//
//-----------------------------------------------------------------------------
bool ReorientBodyGroupList( CDmeBodyGroupList *pDmeBodyGroupList, CDmeDefineBoneList *pDmeDefineBoneList, bool bMakeZUp, const matrix3x4_t &m ) { if ( !pDmeBodyGroupList ) return false;
bool bUpAxisSet = false; bool bZUp = false; bool bDefineBoneDone = false;
const int nBodyGroupCount = pDmeBodyGroupList->m_BodyGroups.Count(); for ( int i = 0; i < nBodyGroupCount; ++i ) { CDmeBodyGroup *pDmeBodyGroup = pDmeBodyGroupList->m_BodyGroups[i]; if ( !pDmeBodyGroup ) continue;
const int nBodyPartCount = pDmeBodyGroup->m_BodyParts.Count(); for ( int j = 0; j < nBodyPartCount; ++j ) { CDmeBodyPart *pDmeBodyPart = pDmeBodyGroup->m_BodyParts[j]; CDmeLODList *pDmeLODList = CastElement< CDmeLODList >( pDmeBodyPart ); if ( !pDmeBodyPart || !pDmeLODList || pDmeBodyPart->LODCount() == 0 ) continue;
const int nLODCount = pDmeLODList->m_LODs.Count(); for ( int k = 0; k < nLODCount; ++k ) { CDmeLOD *pDmeLOD = pDmeLODList->m_LODs[k]; if ( !pDmeLOD ) continue;
CDmeModel *pDmeModel = pDmeLOD->m_Model.GetElement(); if ( !pDmeModel ) continue;
if ( !bUpAxisSet ) { bZUp = pDmeModel->IsZUp(); bUpAxisSet = true; } else { if ( pDmeModel->IsZUp() != bZUp ) { Warning( "Z Up Mismatch\n" ); } }
if ( bZUp != bMakeZUp ) { ReorientDmeModel( pDmeModel, bMakeZUp, pDmeDefineBoneList, bDefineBoneDone ); if ( !bDefineBoneDone ) { bDefineBoneDone = true; } ReorientEyeballs( pDmeLODList, m ); } } } }
return bZUp != bMakeZUp; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void ReorientCollisionModel( CDmeCollisionModel *pDmeCollisionModel, bool bMakeZUp ) { if ( !pDmeCollisionModel ) return;
ReorientDmeModel( pDmeCollisionModel->GetValueElement< CDmeModel >( "model" ), bMakeZUp ); }
//-----------------------------------------------------------------------------
// Reorients everything in an MPP file
//-----------------------------------------------------------------------------
void ReorientMppFile( CDmElement *pRoot, bool bMakeZUp ) { matrix3x4_t m; Quaternion q; GetReorientData( m, q, bMakeZUp );
if ( ReorientBodyGroupList( pRoot->GetValueElement< CDmeBodyGroupList >( "bodyGroupList" ), pRoot->GetValueElement< CDmeDefineBoneList >( "defineBoneList" ), bMakeZUp, m ) ) { ReorientGlobalFlags( pRoot, m );
ReorientCollisionModel( pRoot->GetValueElement< CDmeCollisionModel >( "collisionModel" ), bMakeZUp );
ReorientEyeballGlobals( pRoot->GetValueElement< CDmeEyeballGlobals >( "eyeballGlobals" ), m );
ReorientSequenceList( pRoot->GetValueElement< CDmeSequenceList >( "sequenceList" ), bMakeZUp, m ); } else { // Msg( "File Already %s Up\n", bMakeZUp ? "Z" : "Y" );
} }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void MppReorient( CDmElement *pRoot, bool bMakeZUp ) { ReorientMppFile( pRoot, bMakeZUp ); }
//-----------------------------------------------------------------------------
// Get a list of all DmeDag nodes which are the ancestors of the
// specified node. Returns false if this cannot be computed because
// of a cycle or a NULL DmeDag was passed
//
// + hierarchyList[0] // Root
// + hierarchyList[1] // 0 is parent of 1
// + hierarchyList[2] // 1 is parent of 2
// ...
// + hierarchyList[n] == pDmeDag //
//
//-----------------------------------------------------------------------------
bool GetDagHierarchy( CUtlVector< CDmeDag * > &hierarchyList, CDmeDag *pDmeDag ) { if ( !pDmeDag ) return false;
CUtlRBTree< DmElementHandle_t > visited( DefLessFunc( DmElementHandle_t ) );
hierarchyList.RemoveAll(); for ( ; pDmeDag; pDmeDag = pDmeDag->GetParent() ) { if ( visited.IsValidIndex( visited.Find( pDmeDag->GetHandle() ) ) ) { // Found a cycle
return false; }
visited.Insert( pDmeDag->GetHandle() ); hierarchyList.AddToHead( pDmeDag ); }
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void GetDmeChannelList( CUtlVector< CDmeChannel * > &PChannelList, CUtlVector< CDmeChannel * > &OChannelList, const CUtlVector< CDmeDag * > &dagList ) { PChannelList.RemoveAll();
for ( int i = 0; i < dagList.Count(); ++i ) { CUtlVector< CDmeChannel * > dmeChannelList;
bool bPHandled = false; bool bOHandled = false;
if ( FindReferringElements( dmeChannelList, dagList[i]->GetTransform(), g_pDataModel->GetSymbol( "toElement" ) ) && dmeChannelList.Count() > 0 ) { for ( int j = 0; j < dmeChannelList.Count(); ++j ) { CDmeLog *pDmeLog = dmeChannelList[j]->GetLog(); if ( !pDmeLog ) continue;
for ( int k = 0; k < pDmeLog->GetNumLayers(); ++k ) { CDmeLogLayer *pDmeLogLayer = pDmeLog->GetLayer( k );
CDmeVector3LogLayer *pDmeVector3LogLayer = CastElement< CDmeVector3LogLayer >( pDmeLogLayer ); if ( !bPHandled && pDmeVector3LogLayer ) { bPHandled = true; PChannelList.AddToTail( dmeChannelList[j] ); continue; }
CDmeQuaternionLogLayer *pDmeQuaternionLogLayer = CastElement< CDmeQuaternionLogLayer >( pDmeLogLayer ); if ( !bOHandled && pDmeQuaternionLogLayer ) { bOHandled = true; OChannelList.AddToTail( dmeChannelList[j] ); continue; } } } }
if ( !bPHandled ) { PChannelList.AddToTail( NULL ); }
if ( !bOHandled ) { OChannelList.AddToTail( NULL ); } } }
//-----------------------------------------------------------------------------
// Computes common data for GetAbsMotion & SetAbsMotion
//-----------------------------------------------------------------------------
bool PrepAndValidateMotionData( CDmeChannel **pDmeDagPositionChannel, CDmeChannel **pDmeDagOrientationChannel, CDmeDag *pDmeDag, CUtlVector< CDmeDag * > &hierarchyList, CUtlVector< CDmeChannel * > &PChannelList, CUtlVector< CDmeChannel * > &OChannelList, CUtlRBTree< DmeTime_t > &keyTimes ) { if ( !pDmeDag ) return false;
hierarchyList.RemoveAll(); if ( !GetDagHierarchy( hierarchyList, pDmeDag ) ) return false; // Found a cycle, abort!
PChannelList.RemoveAll(); OChannelList.RemoveAll(); GetDmeChannelList( PChannelList, OChannelList, hierarchyList ); if ( hierarchyList.Count() != PChannelList.Count() || hierarchyList.Count() != OChannelList.Count() ) return false;
CDmeChannel *pSrcPChannel = PChannelList.Tail(); if ( pDmeDagPositionChannel ) { *pDmeDagPositionChannel = pSrcPChannel; }
CDmeLog *pSrcPLog = pSrcPChannel ? pSrcPChannel->GetLog() : NULL;
CDmeChannel *pSrcOChannel = OChannelList.Tail(); if ( pDmeDagOrientationChannel ) { *pDmeDagOrientationChannel = pSrcOChannel; }
CDmeLog *pSrcOLog = pSrcOChannel ? pSrcOChannel->GetLog() : NULL;
// Build a list of key times containing all keys from both logs
if ( pSrcPLog ) { for ( int i = 0; i < pSrcPLog->GetKeyCount(); ++i ) { keyTimes.InsertIfNotFound( pSrcPLog->GetKeyTime( i ) ); } }
if ( pSrcOLog ) { for ( int i = 0; i < pSrcOLog->GetKeyCount(); ++i ) { keyTimes.InsertIfNotFound( pSrcOLog->GetKeyTime( i ) ); } }
return true; }
//-----------------------------------------------------------------------------
// Returns a CDmElement with two attributes:
//
// "positionChannel" - CDmeChannel
// "orientationChannel" - CDmeChannel
//
// These two CDmeChannel's are the worldSpace position and orientation
// of the specified DmeDag node computed over the same time frame as
// the original DmeChannel driving the DmeDag node.
//
// If the DmeDag node isn't animated then two single frame DmeChannels
// are returned with a single sample at DmeTime_t( 0.0 )
//
// NOTE: This should probably take a time frame over which to bake
// and a sample rate and then simply set time and evaluate the
// DmeOperator's in the scene so that rig operator's, etc...
// will work and it doesn't have to be driven by just a DmeChannel
//-----------------------------------------------------------------------------
void GetAbsMotion( CDmeChannel **ppDmePChannel, CDmeChannel **ppDmeOChannel, CDmeDag *pDmeDag ) { if ( !pDmeDag | !ppDmePChannel || !ppDmeOChannel ) return;
*ppDmePChannel = NULL; *ppDmeOChannel = NULL;
CUtlVector< CDmeDag * > hierarchyList; CUtlVector< CDmeChannel * > PChannelList; CUtlVector< CDmeChannel * > OChannelList; CUtlRBTree< DmeTime_t > keyTimes( DefLessFunc( DmeTime_t ) ); CDmeChannel *pSrcPChannel = NULL; CDmeChannel *pSrcOChannel = NULL;
if ( !PrepAndValidateMotionData( &pSrcPChannel, &pSrcOChannel, pDmeDag, hierarchyList, PChannelList, OChannelList, keyTimes ) ) return;
CDmeChannel *pDstPChannel = pSrcPChannel ? CreateElement< CDmeChannel >( pSrcPChannel->GetName(), pSrcPChannel->GetFileId() ) : CreateElement< CDmeChannel >( ( CUtlString( pDmeDag->GetName() ) + "_p" ).Get(), pDmeDag->GetFileId() ); *ppDmePChannel = pDstPChannel; CDmeVector3Log *pDstPLog = pDstPChannel->CreateLog< Vector >(); pDstPLog->SetValueThreshold( 1.0e-6 );
CDmeChannel *pDstOChannel = pSrcOChannel ? CreateElement< CDmeChannel >( pSrcOChannel->GetName(), pSrcPChannel->GetFileId() ) : CreateElement< CDmeChannel >( ( CUtlString( pDmeDag->GetName() ) + "_o" ).Get(), pDmeDag->GetFileId() ); *ppDmeOChannel = pDstOChannel; CDmeQuaternionLog *pDstOLog = pDstOChannel->CreateLog< Quaternion >(); pDstOLog->SetValueThreshold( 1.0e-6 );
matrix3x4_t wm; matrix3x4_t twm; matrix3x4_t m;
Vector v; Quaternion q;
if ( keyTimes.Count() > 0 ) { // Node is animated, so loop through all of the keys and sample all
// animation curves
// Loop through all logs, get current time, accumulate matrix
for ( CUtlRBTree< DmeTime_t >::IndexType_t i = keyTimes.FirstInorder(); keyTimes.IsValidIndex( i ); i = keyTimes.NextInorder( i ) ) { const DmeTime_t dmeTime = keyTimes[i];
SetIdentityMatrix( wm );
for ( int j = 0; j < hierarchyList.Count(); ++j ) { v.Init( 0.0f, 0.0f, 0.0f ); q = quat_identity;
CDmeChannel *pPChannel = PChannelList[j]; if ( pPChannel ) { pPChannel->GetPlaybackValueAtTime( dmeTime, v ); } else { v = hierarchyList[j]->GetTransform()->GetPosition(); }
CDmeChannel *pOChannel = OChannelList[j]; if ( pOChannel ) { pOChannel->GetPlaybackValueAtTime( dmeTime, q ); } else { q = hierarchyList[j]->GetTransform()->GetOrientation(); }
QuaternionMatrix( q, v, m ); MatrixCopy( wm, twm ); ConcatTransforms( twm, m, wm ); }
MatrixAngles( wm, q, v ); pDstOLog->SetKey( dmeTime, q ); pDstPLog->SetKey( dmeTime, v ); } } else { // Node is not animated, so use current value for all nodes...
SetIdentityMatrix( wm ); Vector wt( 0.0f, 0.0f, 0.0f );
for ( int j = 0; j < hierarchyList.Count(); ++j ) { v.Init( 0.0f, 0.0f, 0.0f ); q = quat_identity;
CDmeTransform *pDmeTransform = hierarchyList[j]->GetTransform(); if ( pDmeTransform ) { v = hierarchyList[j]->GetTransform()->GetPosition(); q = hierarchyList[j]->GetTransform()->GetOrientation(); }
wt += v;
QuaternionMatrix( q, v, m ); MatrixCopy( wm, twm ); ConcatTransforms( twm, m, wm ); }
MatrixAngles( wm, q, v );
pDstOLog->SetKey( DmeTime_t( 0.0 ), q ); pDstPLog->SetKey( DmeTime_t( 0.0 ), v ); } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool SetAbsMotion( CDmeDag *pDmeDag, CDmeChannel *pDmePositionChannel, CDmeChannel *pDmeOrientationChannel ) { CUtlVector< CDmeDag * > hierarchyList; CUtlVector< CDmeChannel * > PChannelList; CUtlVector< CDmeChannel * > OChannelList; CUtlRBTree< DmeTime_t > keyTimes( DefLessFunc( DmeTime_t ) ); CDmeChannel *pDmeDagPChannel = NULL; CDmeChannel *pDmeDagOChannel = NULL;
if ( !PrepAndValidateMotionData( &pDmeDagPChannel, &pDmeDagOChannel, pDmeDag, hierarchyList, PChannelList, OChannelList, keyTimes ) ) return false;
CDmeVector3Log *pDstPLog = pDmeDagPChannel ? CastElement< CDmeVector3Log >( pDmeDagPChannel->GetLog() ) : NULL; CDmeQuaternionLog *pDstOLog = pDmeDagOChannel ? CastElement< CDmeQuaternionLog >( pDmeDagOChannel->GetLog() ) : NULL;
matrix3x4_t pwm; matrix3x4_t ipwm; matrix3x4_t tpwm; matrix3x4_t m; matrix3x4_t wm;
CUtlVector< matrix3x4_t > localMatrices;
Vector v; Quaternion q;
// Loop through all logs except last one to get parent world matrix at each key time
if ( keyTimes.Count() <= 0 ) { CDmeLog *pSrcPLog = pDmePositionChannel ? pDmePositionChannel->GetLog() : NULL; if ( pSrcPLog ) { for ( int i = 0; i < pSrcPLog->GetKeyCount(); ++i ) { keyTimes.InsertIfNotFound( pSrcPLog->GetKeyTime( i ) ); } }
CDmeLog *pSrcOLog = pDmeOrientationChannel ? pDmeOrientationChannel->GetLog() : NULL; if ( pSrcOLog ) { for ( int i = 0; i < pSrcOLog->GetKeyCount(); ++i ) { keyTimes.InsertIfNotFound( pSrcOLog->GetKeyTime( i ) ); } } }
if ( keyTimes.Count() <= 0 ) { keyTimes.Insert( DmeTime_t( 0.0 ) ); }
for ( CUtlRBTree< DmeTime_t >::IndexType_t i = keyTimes.FirstInorder(); keyTimes.IsValidIndex( i ); i = keyTimes.NextInorder( i ) ) { const DmeTime_t dmeTime = keyTimes[i];
SetIdentityMatrix( pwm );
for ( int j = 0; j < hierarchyList.Count() - 1; ++j ) { v.Init( 0.0f, 0.0f, 0.0f ); q = quat_identity;
CDmeChannel *pPChannel = PChannelList[j]; if ( pPChannel ) { pPChannel->GetPlaybackValueAtTime( dmeTime, v ); } else { v = hierarchyList[j]->GetTransform()->GetPosition(); }
CDmeChannel *pOChannel = OChannelList[j]; if ( pOChannel ) { pOChannel->GetPlaybackValueAtTime( dmeTime, q ); } else { q = hierarchyList[j]->GetTransform()->GetOrientation(); }
QuaternionMatrix( q, v, m ); MatrixCopy( pwm, tpwm ); ConcatTransforms( tpwm, m, pwm ); }
// pwm is the parent world matrix at dmeTime
MatrixInvert( pwm, ipwm );
// wm is the world matrix of dmeDag at dmeTime
pDmePositionChannel->GetPlaybackValueAtTime( dmeTime, v ); pDmeOrientationChannel->GetPlaybackValueAtTime( dmeTime, q ); QuaternionMatrix( q, v, wm );
ConcatTransforms( ipwm, wm, m ); localMatrices.AddToTail( m ); }
Assert( static_cast< int >( keyTimes.Count() ) == localMatrices.Count() );
if ( pDstPLog && pDstOLog ) { // Destination node is animated
pDstPLog->ClearKeys(); pDstOLog->ClearKeys();
// Now set the key/values in the logs
int nMatIndex = 0; for ( CUtlRBTree< DmeTime_t >::IndexType_t i = keyTimes.FirstInorder(); keyTimes.IsValidIndex( i ); i = keyTimes.NextInorder( i ), ++nMatIndex ) { const DmeTime_t dmeTime = keyTimes[i]; MatrixAngles( localMatrices[nMatIndex], q, v ); pDstPLog->SetKey( dmeTime, v ); pDstOLog->SetKey( dmeTime, q ); } } else { // Destination node is static
hierarchyList.Tail()->GetTransform()->SetTransform( localMatrices[0] ); }
return true; }
//-----------------------------------------------------------------------------
// Creates a guaranteed unique DmFileId_t
//-----------------------------------------------------------------------------
DmFileId_t CreateUniqueDmFileId() { UniqueId_t uniqueId; CreateUniqueId( &uniqueId );
char buf[64]; UniqueIdToString( uniqueId, buf, ARRAYSIZE( buf ) );
return g_pDataModel->FindOrCreateFileId( buf ); }
//=============================================================================
// MppSequenceIt - MPP File Sequence Iterator
//=============================================================================
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
MppSequenceIt::MppSequenceIt( CDmeAssetRoot *pDmeAssetRoot ) : m_nSequenceIndex( -1 ) { if ( pDmeAssetRoot ) { CDmeSequenceList *pDmeSequenceList = pDmeAssetRoot->GetValueElement< CDmeSequenceList >( "sequenceList" ); if ( pDmeSequenceList ) { CUtlVector< CDmeSequenceBase * > sortedSequenceList; pDmeSequenceList->GetSortedSequenceList( sortedSequenceList );
const int nSortedSequenceCount = sortedSequenceList.Count(); m_hDmeSequenceList.EnsureCapacity( nSortedSequenceCount ); for ( int i = 0; i < nSortedSequenceCount; ++i ) { CDmeSequence *pDmeSequence = CastElement< CDmeSequence >( sortedSequenceList[i] ); if ( !pDmeSequence ) continue;
m_hDmeSequenceList.AddToTail( pDmeSequence->GetHandle() ); } } }
Next(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeSequence *MppSequenceIt::Get() const { if ( m_nSequenceIndex < 0 || m_nSequenceIndex >= m_hDmeSequenceList.Count() ) return NULL;
return CastElement< CDmeSequence >( g_pDataModel->GetElement( m_hDmeSequenceList[m_nSequenceIndex] ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool MppSequenceIt::IsDone() const { return Get() == NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void MppSequenceIt::Next() { for ( int i = m_nSequenceIndex + 1; i < m_hDmeSequenceList.Count(); ++i ) { CDmeSequence *pDmeSequence = CastElement< CDmeSequence >( g_pDataModel->GetElement( m_hDmeSequenceList[i] ) ); if ( pDmeSequence ) { m_nSequenceIndex = i; return; } }
m_nSequenceIndex = m_hDmeSequenceList.Count(); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void MppSequenceIt::Reset() { m_nSequenceIndex = -1; Next(); }
//-----------------------------------------------------------------------------
// Adds the passed pDmeModel to the skeletonList if it isn't already in the
// list and it isn't NULL
//-----------------------------------------------------------------------------
static void AddUniqueSkeleton( CUtlVector< CDmeModel * > &skeletonList, CDmeModel *pDmeModel ) { if ( !pDmeModel ) return;
bool bFound = false;
for ( int i = 0; i < skeletonList.Count(); ++i ) { if ( pDmeModel == skeletonList[i] ) { bFound = true; break; } }
if ( !bFound ) { skeletonList.AddToTail( pDmeModel ); } }
//-----------------------------------------------------------------------------
// Returns a list of all unique skeletons used by animations/sequences under the MPP DmeAssetRoot
//-----------------------------------------------------------------------------
void MppGetAnimationSkeletonList( CUtlVector< CDmeModel * > &skeletonList, CDmeAssetRoot *pDmeAssetRoot ) { skeletonList.RemoveAll();
for ( MppSequenceIt sIt( pDmeAssetRoot ); !sIt.IsDone(); sIt.Next() ) { AddUniqueSkeleton( skeletonList, CastElement< CDmeModel >( sIt.Get()->m_eSkeleton.GetElement() ) ); } }
//-----------------------------------------------------------------------------
// Returns a list of all unique skeletons used by the physics model under the MPP DmeAssetRoot
//-----------------------------------------------------------------------------
void MppGetPhysicsSkeletonList( CUtlVector< CDmeModel * > &skeletonList, CDmeAssetRoot *pDmeAssetRoot ) { skeletonList.RemoveAll();
if ( !pDmeAssetRoot ) return;
CDmeCollisionModel *pDmeCollisionModel = pDmeAssetRoot->GetValueElement< CDmeCollisionModel >( "collisionModel" ); if ( !pDmeCollisionModel ) return;
const char *const pszAttrs[] = { "skeleton", "model" };
for ( int i = 0; i < 2; ++i ) { AddUniqueSkeleton( skeletonList, pDmeCollisionModel->GetValueElement< CDmeModel >( pszAttrs[i] ) ); } }
//-----------------------------------------------------------------------------
// Returns a list of all unique skeletons used by the models under the MPP DmeAssetRoot
//-----------------------------------------------------------------------------
void MppGetModelSkeletonList( CUtlVector< CDmeModel * > &skeletonList, CDmeAssetRoot *pDmeAssetRoot ) { skeletonList.RemoveAll();
if ( !pDmeAssetRoot ) return;
CDmeBodyGroupList *pDmeBodyGroupList = pDmeAssetRoot->GetValueElement< CDmeBodyGroupList >( "bodyGroupList" ); if ( !pDmeBodyGroupList ) return;
const char *const pszAttrs[] = { "skeleton", "model" };
for ( int i = 0; i < pDmeBodyGroupList->m_BodyGroups.Count(); ++i ) { CDmeBodyGroup *pDmeBodyGroup = pDmeBodyGroupList->m_BodyGroups[i]; if ( !pDmeBodyGroup ) continue;
for ( int j = 0; j < pDmeBodyGroup->m_BodyParts.Count(); ++j ) { CDmeLODList *pDmeLODList = CastElement< CDmeLODList >( pDmeBodyGroup->m_BodyParts[j] ); if ( !pDmeLODList ) continue;
for ( int k = 0; k < pDmeLODList->m_LODs.Count(); ++k ) { CDmeLOD *pDmeLOD = pDmeLODList->m_LODs[k]; if ( !pDmeLOD ) continue;
for ( int i = 0; i < 2; ++i ) { AddUniqueSkeleton( skeletonList, pDmeLOD->GetValueElement< CDmeModel >( pszAttrs[i] ) ); } } } } }
//-----------------------------------------------------------------------------
// Returns a list of all unique skeletons under the specified MPP DmeAssetRoot
//-----------------------------------------------------------------------------
void MppGetSkeletonList( CUtlVector< CDmeModel * > &skeletonList, CDmeAssetRoot *pDmeAssetRoot, int nMppSkeletonMask /* = kMppAllSkeletonMask */ ) { skeletonList.RemoveAll();
if ( !pDmeAssetRoot ) return;
for ( int i = 0; i < 3; ++i ) { CUtlVector< CDmeModel * > tmpSkeletonList; switch ( i ) { case 0: if ( nMppSkeletonMask & MPP_ANIM_SKELETON_MASK ) { MppGetAnimationSkeletonList( tmpSkeletonList, pDmeAssetRoot ); } break; case 1: if ( nMppSkeletonMask & MPP_PHYSICS_SKELETON_MASK ) { MppGetPhysicsSkeletonList( tmpSkeletonList, pDmeAssetRoot ); } break; case 2: if ( nMppSkeletonMask & MPP_MODEL_SKELETON_MASK ) { MppGetModelSkeletonList( tmpSkeletonList, pDmeAssetRoot ); } break; }
for ( int j = 0; j < tmpSkeletonList.Count(); ++j ) { CDmeModel *pDmeModel = tmpSkeletonList[j]; if ( !pDmeModel ) continue;
bool bFound = false;
for ( int k = 0; k < skeletonList.Count(); ++k ) { if ( pDmeModel == skeletonList[k] ) { bFound = true; break; } }
if ( !bFound ) { skeletonList.AddToTail( pDmeModel ); } } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeTransform *FindMatchingSkeletonTransform( CDmeModel *pDmeModel, CDmeTransform *pDmeTransform ) { if ( !pDmeModel || !pDmeTransform ) return NULL;
CDmeDag *pDmeDag = NULL; CDmeDag *pDmeDagChild = NULL; CDmeTransform *pDmeDagTransform = NULL;
CUtlStack< CDmeDag * > depthFirstDagStack; depthFirstDagStack.Push( pDmeModel );
while ( depthFirstDagStack.Count() ) { depthFirstDagStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
pDmeDagTransform = pDmeDag->GetTransform(); if ( pDmeDagTransform && !Q_stricmp( pDmeTransform->GetName(), pDmeDagTransform->GetName() ) ) return pDmeDagTransform;
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { pDmeDagChild = pDmeDag->GetChild( i ); if ( !pDmeDagChild ) continue;
depthFirstDagStack.Push( pDmeDagChild ); } }
return NULL; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeConnectionOperator *CreateOutgoingConnectionOperator( CDmeTransform *pSrcTransform, CDmAttribute *pSrcAttribute, DmFileId_t nFileId ) { if ( !pSrcTransform || !pSrcAttribute ) return NULL;
CUtlString sName( pSrcTransform->GetName() ); sName += "."; sName += pSrcAttribute->GetName();
CDmeConnectionOperator *pDmeConnectionOperator = CreateElement< CDmeConnectionOperator >( sName.Get(), nFileId ); if ( !pDmeConnectionOperator ) return NULL;
pDmeConnectionOperator->SetInput( pSrcTransform, pSrcAttribute->GetName() );
return pDmeConnectionOperator; }
//-----------------------------------------------------------------------------
// Adds the appropriate attribute of the specified DmeTransform as an output
// of the DmeConnectionOperator if an attribute of the same name as the
// input operator can be found on the specified DmeTransform
//-----------------------------------------------------------------------------
static bool MppConnectDmeTransforms( CDmeConnectionOperator *pDmeConnectionOperator, CDmeTransform *pDstTransform ) { if ( !pDmeConnectionOperator || !pDstTransform ) return false;
CDmAttribute *pInputAttribute = pDmeConnectionOperator->GetInputAttribute(); if ( !pInputAttribute ) return false;
CDmeAttributeReference *pDmeAttributeReference = pInputAttribute->GetValueElement< CDmeAttributeReference >(); if ( !pDmeAttributeReference ) return false;
CDmAttribute *pSrcAttribute = pDmeAttributeReference->GetReferencedAttribute(); if ( !pSrcAttribute ) return false;
CDmAttribute *pDstAttribute = pDstTransform->GetAttribute( pSrcAttribute->GetName() ); if ( !pDstAttribute ) return false;
pDmeConnectionOperator->AddOutput( pDstTransform, pDstAttribute->GetName() );
return true; }
//-----------------------------------------------------------------------------
// Return true if this DmeTransform has a DmeChannel driving either the
// position or orientation attributes (or both).
//-----------------------------------------------------------------------------
static bool MppIsDmeTransformAnimated( CDmeTransform *pDmeTransform ) { // Assert( 0 );
return true; }
//-----------------------------------------------------------------------------
// For each DmeTransform in the source skeleton that has its position or
// orientation attribute driven by a DmeChannel, create two DmeConnectionOperator
// elements, one for position and one for orientation and use those attributes
// as the input to the DmeConnectionOperator. For each skeleton in the
// dstSkeletonList, if there is a DmeTransform that matches up by a case insensitive
// name search via a depth first walk, connect the appropriate position or
// orientation attribute to the outputs of the DmeConnectionOperator.
// All created DmeConnectionOperators are stored in an attribute on pSrcSkeleton
// called __MppAnimationDmeConnectionOperators which should already exist
// and are given the nFileId passed
//-----------------------------------------------------------------------------
static void MppConnectSkeletons( CDmeModel *pSrcSkeleton, const CUtlVector< CDmeModel * > &dstSkeletonList, DmFileId_t nFileId ) { if ( !pSrcSkeleton || dstSkeletonList.Count() <= 0 ) return;
CDmAttribute *pConnectionOps = pSrcSkeleton->GetAttribute( "__MppAnimationDmeConnectionOperators", AT_ELEMENT_ARRAY ); if ( !pConnectionOps ) return;
CDmrElementArray< CDmeConnectionOperator > connectionOps( pConnectionOps );
// Do a depth first DmeDag walk of the source skeleton finding DmeTransforms which
// have connections to DmeOperators... which is tricky because of the way DmeOperators
// are defined... kind of needs an upfront knowledge of what DmeOperators might be
// connected and how they are structured for this to function...
CUtlStack< CDmeDag * > depthFirstStack; depthFirstStack.Push( pSrcSkeleton );
CDmeDag *pDmeDag = NULL;
while ( depthFirstStack.Count() ) { depthFirstStack.Pop( pDmeDag ); if ( !pDmeDag ) continue;
CDmeTransform *pSrcDmeTransform = pDmeDag->GetTransform(); if ( pSrcDmeTransform ) { if ( MppIsDmeTransformAnimated( pSrcDmeTransform ) ) { for ( int i = 0; i < 2; ++i ) { CDmAttribute *pSrcAttribute = i == 0 ? pSrcDmeTransform->GetPositionAttribute() : pSrcDmeTransform->GetOrientationAttribute();
CDmeConnectionOperator *pDmeConnectionOperator = CreateOutgoingConnectionOperator( pSrcDmeTransform, pSrcAttribute, nFileId ); if ( !pDmeConnectionOperator ) continue;
for ( int j = 0; j < dstSkeletonList.Count(); ++j ) { CDmeModel *pDstSkeleton = dstSkeletonList[j]; if ( pDstSkeleton == pSrcSkeleton ) continue;
CDmeTransform *pDstDmeTransform = FindMatchingSkeletonTransform( pDstSkeleton, pSrcDmeTransform ); if ( !pDstDmeTransform || pSrcDmeTransform == pDstDmeTransform ) continue;
MppConnectDmeTransforms( pDmeConnectionOperator, pDstDmeTransform ); }
if ( pDmeConnectionOperator->NumOutputAttributes() <= 0 ) { g_pDataModel->DestroyElement( pDmeConnectionOperator->GetHandle() ); } else { connectionOps.AddToTail( pDmeConnectionOperator ); } } } }
for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i ) { depthFirstStack.Push( pDmeDag->GetChild( i ) ); } } }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static void MppDisconnectAnimationSkeleton( CDmeModel *pDmeModel ) { // Assert( 0 );
}
//-----------------------------------------------------------------------------
// Connects all of the non-animation skeletons to each animation skeleton via DmeConnectionOperators
//-----------------------------------------------------------------------------
DmFileId_t MppConnectSkeletonsForAnimation( CDmeAssetRoot *pDmeAssetRoot ) { if ( !pDmeAssetRoot ) return DMFILEID_INVALID;
CUtlVector< CDmeModel * > animationSkeletonList; MppGetSkeletonList( animationSkeletonList, pDmeAssetRoot, MPP_ANIM_SKELETON_MASK );
CUtlVector< CDmeModel * > skeletonList; MppGetSkeletonList( skeletonList, pDmeAssetRoot, MPP_MODEL_SKELETON_MASK | MPP_PHYSICS_SKELETON_MASK );
if ( animationSkeletonList.Count() <= 0 || skeletonList.Count() <= 0 ) return DMFILEID_INVALID;
DmFileId_t nFileId = CreateUniqueDmFileId();
for ( int i = 0; i < animationSkeletonList.Count(); ++i ) { CDmeModel *pSrcSkeleton = animationSkeletonList[i]; if ( !pSrcSkeleton ) continue;
MppDisconnectAnimationSkeleton( pSrcSkeleton );
CDmAttribute *pConnectionOps = pSrcSkeleton->AddAttribute( "__MppAnimationDmeConnectionOperators", AT_ELEMENT_ARRAY ); pConnectionOps->AddFlag( FATTRIB_DONTSAVE ); CDmrElementArray< CDmeConnectionOperator > connectionOps( pConnectionOps );
MppConnectSkeletons( pSrcSkeleton, skeletonList, nFileId ); }
return nFileId; }
//-----------------------------------------------------------------------------
// Disconnects all of the non-animation skeletons from each animation skeleton
// and destroys the elements created by MppConnectSkeletonsForAnimation
//-----------------------------------------------------------------------------
void MppDisconnectSkeletonsFromAnimation( CDmeAssetRoot *pDmeAssetRoot ) { }
//-----------------------------------------------------------------------------
// Utility to return DmElement id as name:string
//-----------------------------------------------------------------------------
CUtlString ComputeDmElementIdStr( const CDmElement *pDmElement ) { if ( !pDmElement ) return CUtlString( "NULL(Unknown):\"Unknown\"" );
CUtlString sReturn;
sReturn = pDmElement->GetTypeString(); sReturn += "("; sReturn = pDmElement->GetName(); sReturn += "):\"";
char pszBuf[64]; UniqueIdToString( pDmElement->GetId(), pszBuf, ARRAYSIZE( pszBuf ) ); sReturn += pszBuf;
sReturn += "\"";
return sReturn; }
|