You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1465 lines
42 KiB
1465 lines
42 KiB
//====== 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;
|
|
}
|