csgo-2018-source/movieobjects/dmemodel.cpp
2021-07-24 21:11:47 -07:00

1490 lines
45 KiB
C++

//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
//
// Dme version of a skeletal model (gets compiled into a MDL)
//
//=============================================================================
#include "movieobjects/dmemodel.h"
#include "movieobjects_interfaces.h"
#include "datamodel/dmelementfactoryhelper.h"
#include "datacache/imdlcache.h"
#include "materialsystem/imaterialsystem.h"
#include "tier2/tier2.h"
#include "studio.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "movieobjects/dmemesh.h"
#include "movieobjects/dmechannel.h"
#include "movieobjects/dmelog.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeModel, CDmeModel );
//-----------------------------------------------------------------------------
// Stack of DmeModels currently being rendered. Used to set up render state
//-----------------------------------------------------------------------------
CUtlStack< CDmeModel * > CDmeModel::s_ModelStack;
static CUtlVector< matrix3x4_t > s_PoseToWorld;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDmeModel::OnConstruction()
{
m_JointList.Init( this, "jointList" );
m_BaseStates.Init( this, "baseStates" );
m_UpAxis.InitAndSet( this, "upAxis", "Y" );
m_eAxisSystem.InitAndCreate( this, "axisSystem" ); // Defaults to Y up
}
void CDmeModel::OnDestruction()
{
}
//-----------------------------------------------------------------------------
// Add joint
//-----------------------------------------------------------------------------
int CDmeModel::AddJoint( CDmeDag *pJoint )
{
const int nIndex = GetJointIndex( pJoint );
if ( nIndex >= 0 )
return nIndex;
return m_JointList.AddToTail( pJoint );
}
//-----------------------------------------------------------------------------
// Add joint
//-----------------------------------------------------------------------------
CDmeJoint *CDmeModel::AddJoint( const char *pJointName, CDmeDag *pParent )
{
CDmeJoint *pJoint = CreateElement< CDmeJoint >( pJointName, GetFileId() );
CDmeTransform *pTransform = pJoint->GetTransform();
pTransform->SetName( pJointName );
if ( !pParent )
{
pParent = this;
}
pParent->AddChild( pJoint );
m_JointList.AddToTail( pJoint );
return pJoint;
}
//-----------------------------------------------------------------------------
// Returns the number of joint transforms we know about
//-----------------------------------------------------------------------------
int CDmeModel::GetJointCount() const
{
return m_JointList.Count();
}
//-----------------------------------------------------------------------------
// Determines joint transform index given a joint transform
//-----------------------------------------------------------------------------
int CDmeModel::GetJointIndex( CDmeDag *pJoint ) const
{
const int nJointCount = m_JointList.Count();
for ( int i = 0; i < nJointCount; ++i )
{
if ( pJoint == m_JointList[ i ] )
{
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Determines joint transform index given a joint name
//-----------------------------------------------------------------------------
int CDmeModel::GetJointIndex( const char *pJointName ) const
{
const int nJointCount = m_JointList.Count();
for ( int i = 0; i < nJointCount; ++i )
{
if ( !V_strcmp( pJointName, m_JointList[ i ]->GetName() ) )
{
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Determines joint transform index given a joint name hash
//-----------------------------------------------------------------------------
int CDmeModel::GetJointIndex( CUtlStringToken nJointNameHash ) const
{
const int nJointCount = m_JointList.Count();
for ( int i = 0; i < nJointCount; ++i )
{
if ( MakeStringToken( m_JointList[ i ]->GetName() ) == nJointNameHash )
{
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Returns the DmeDag for the specified joint index
//-----------------------------------------------------------------------------
CDmeDag *CDmeModel::GetJoint( int nIndex )
{
return m_JointList[ nIndex ];
}
const CDmeDag *CDmeModel::GetJoint( int nIndex ) const
{
return m_JointList[ nIndex ];
}
//-----------------------------------------------------------------------------
// Determines joint transform index given a joint name
//-----------------------------------------------------------------------------
CDmeTransform *CDmeModel::GetJointTransform( int nIndex )
{
return m_JointList[ nIndex ]->GetTransform();
}
const CDmeTransform *CDmeModel::GetJointTransform( int nIndex ) const
{
return m_JointList[ nIndex ]->GetTransform();
}
//-----------------------------------------------------------------------------
// Finds a base state by name, returns NULL if not found
//-----------------------------------------------------------------------------
CDmeTransformList *CDmeModel::FindBaseState( const char *pBaseStateName )
{
int nCount = m_BaseStates.Count();
for ( int i = 0; i < nCount; ++i )
{
if ( !V_stricmp( m_BaseStates[i]->GetName(), pBaseStateName ) )
return m_BaseStates[i];
}
return NULL;
}
//-----------------------------------------------------------------------------
// Captures the current joint transforms into a base state
//-----------------------------------------------------------------------------
void CDmeModel::CaptureJointsToBaseState( const char *pBaseStateName )
{
CDmeTransformList *pTransformList = FindBaseState( pBaseStateName );
if ( !pTransformList )
{
pTransformList = CreateElement<CDmeTransformList>( pBaseStateName, GetFileId() );
m_BaseStates.AddToTail( pTransformList );
}
// Make the transform list have the correct number of elements
const int nJointCount = m_JointList.Count();
const int nCurrentCount = pTransformList->GetTransformCount();
if ( nJointCount > nCurrentCount )
{
for ( int i = nCurrentCount; i < nJointCount; ++i )
{
CDmeTransform *pTransform = CreateElement<CDmeTransform>( m_JointList[i]->GetName(), pTransformList->GetFileId() );
pTransformList->m_Transforms.AddToTail( pTransform );
}
}
else if ( nJointCount < nCurrentCount )
{
pTransformList->m_Transforms.RemoveMultiple( nJointCount, nCurrentCount - nJointCount );
}
// Copy the state over
for ( int i = 0; i < nJointCount; ++i )
{
matrix3x4_t mat;
CDmeDag *pDmeDag = m_JointList[i];
if ( !pDmeDag )
{
char szTmpBuf0[ 38 ];
UniqueIdToString( GetId(), szTmpBuf0, ARRAYSIZE( szTmpBuf0 ) );
Warning( "DmeModel::CaptureJointsToBaseState( %s ): DmeModel %s[%s].jointList[ %d ] is NULL\n", pBaseStateName, GetName(), szTmpBuf0, i );
continue;
}
CDmeTransform *pDmeTransform = pDmeDag->GetTransform();
if ( !pDmeTransform )
{
char szTmpBuf0[ 38 ];
UniqueIdToString( GetId(), szTmpBuf0, ARRAYSIZE( szTmpBuf0 ) );
char szTmpBuf1[ 38 ];
UniqueIdToString( pDmeDag->GetId(), szTmpBuf1, ARRAYSIZE( szTmpBuf1 ) );
Warning( "DmeModel::CaptureJointsToBaseState( %s ) - DmeModel %s[%s].jointList[ %d ].transform ( %s[%s].transform ) is NULL\n", pBaseStateName, GetName(), szTmpBuf0, i, pDmeDag->GetName(), szTmpBuf1 );
continue;
}
pDmeTransform->GetTransform( mat );
pTransformList->SetTransform( i, mat );
}
}
//-----------------------------------------------------------------------------
// Sets the joint transforms to the values in the specified base state, if it exists
//-----------------------------------------------------------------------------
void CDmeModel::PushBaseStateToJoints( const char *pBaseStateName )
{
CDmeTransformList *pTransformList = FindBaseState( pBaseStateName );
if ( !pTransformList )
return;
for ( int ii = 0; ii < pTransformList->GetTransformCount(); ++ii )
{
CDmeTransform *pSrcDmeTransform = pTransformList->GetTransform( ii );
CDmeDag *pDmeJoint = GetJoint( ii );
if ( !pSrcDmeTransform || !pDmeJoint )
continue;
CDmeTransform *pDstDmeTransform = pDmeJoint->GetTransform();
if ( !pDstDmeTransform )
continue;
pDstDmeTransform->SetPosition( pSrcDmeTransform->GetPosition() );
pDstDmeTransform->SetOrientation( pSrcDmeTransform->GetOrientation() );
}
}
//-----------------------------------------------------------------------------
// Loads up joint transforms for this model
//-----------------------------------------------------------------------------
void CDmeModel::LoadJointTransform( CDmeDag *pJoint, CDmeTransformList *pBindPose, const matrix3x4_t &parentToWorld, const matrix3x4_t &parentToBindPose, bool bSetHardwareState )
{
// Determines joint transform index; no index, no traversing lower in the hierarchy
const int nJointIndex = GetJointIndex( pJoint );
if ( nJointIndex < 0 )
return;
// FIXME: Sucky search here necessary to find bone matrix index
matrix3x4_t jointToWorld, jointToParent;
pJoint->GetTransform()->GetTransform( jointToParent );
ConcatTransforms( parentToWorld, jointToParent, jointToWorld );
matrix3x4_t bindJointToParent, bindPoseToJoint, bindPoseToWorld, jointToBindPose;
if ( pBindPose )
{
if ( nJointIndex >= pBindPose->GetTransformCount() )
{
Warning( "Model is in an invalid state! There are different numbers of bones in the bind pose and joint transform list!\n" );
return;
}
pBindPose->GetTransform( nJointIndex )->GetTransform( bindJointToParent );
}
else
{
MatrixCopy( jointToParent, bindJointToParent );
}
ConcatTransforms( parentToBindPose, bindJointToParent, jointToBindPose );
MatrixInvert( jointToBindPose, bindPoseToJoint );
ConcatTransforms( jointToWorld, bindPoseToJoint, bindPoseToWorld );
if ( bSetHardwareState )
{
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->LoadBoneMatrix( nJointIndex, bindPoseToWorld );
}
MatrixCopy( bindPoseToWorld, s_PoseToWorld[ nJointIndex ] );
int nChildCount = pJoint->GetChildCount();
for ( int i = 0; i < nChildCount; ++i )
{
CDmeDag *pChildJoint = pJoint->GetChild(i);
if ( !pChildJoint )
continue;
LoadJointTransform( pChildJoint, pBindPose, jointToWorld, jointToBindPose, bSetHardwareState );
}
}
//-----------------------------------------------------------------------------
// Sets up the render state for the model
//-----------------------------------------------------------------------------
CDmeModel::SetupBoneRetval_t CDmeModel::SetupBoneMatrixState( const matrix3x4_t& shapeToWorld, bool bForceSoftwareSkin )
{
const int nJointCount = m_JointList.Count();
if ( nJointCount <= 0 )
return NO_SKIN_DATA;
int nBoneBatchCount = g_pMaterialSystemHardwareConfig->MaxVertexShaderBlendMatrices();
bool bSetHardwareState = ( nJointCount <= nBoneBatchCount ) && !bForceSoftwareSkin;
s_PoseToWorld.EnsureCount( nJointCount );
// Finds a base state by name, returns NULL if not found
CDmeTransformList *pBindPose = FindBaseState( "bind" );
matrix3x4_t parentToBindPose;
SetIdentityMatrix( parentToBindPose );
int nChildCount = GetChildCount();
for ( int i = 0; i < nChildCount; ++i )
{
CDmeDag *pChildJoint = GetChild(i);
if ( !pChildJoint )
continue;
LoadJointTransform( pChildJoint, pBindPose, shapeToWorld, parentToBindPose, bSetHardwareState );
}
return bSetHardwareState ? BONES_SET_UP : TOO_MANY_BONES;
}
matrix3x4_t *CDmeModel::SetupModelRenderState( const matrix3x4_t& shapeToWorld, bool bHasSkinningData, bool bForceSoftwareSkin )
{
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
if ( bHasSkinningData && ( s_ModelStack.Count() > 0 ) )
{
SetupBoneRetval_t retVal = s_ModelStack.Top()->SetupBoneMatrixState( shapeToWorld, bForceSoftwareSkin );
if ( retVal == TOO_MANY_BONES )
{
pRenderContext->MatrixMode( MATERIAL_MODEL );
pRenderContext->LoadIdentity( );
return s_PoseToWorld.Base();
}
if ( retVal != NO_SKIN_DATA )
return NULL;
}
if ( bForceSoftwareSkin )
{
pRenderContext->MatrixMode( MATERIAL_MODEL );
pRenderContext->LoadIdentity( );
s_PoseToWorld.EnsureCount( 1 );
MatrixCopy( shapeToWorld, s_PoseToWorld[0] );
return s_PoseToWorld.Base();
}
pRenderContext->MatrixMode( MATERIAL_MODEL );
pRenderContext->LoadMatrix( shapeToWorld );
return NULL;
}
void CDmeModel::CleanupModelRenderState()
{
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->MatrixMode( MATERIAL_MODEL );
pRenderContext->LoadIdentity();
}
//-----------------------------------------------------------------------------
// Recursively render the Dag hierarchy
//-----------------------------------------------------------------------------
void CDmeModel::Draw( CDmeDrawSettings *pDrawSettings /* = NULL */ )
{
s_ModelStack.Push( this );
BaseClass::Draw( pDrawSettings );
s_ModelStack.Pop( );
}
//-----------------------------------------------------------------------------
// Set if Z is the up axis of the model
//-----------------------------------------------------------------------------
void CDmeModel::ZUp( bool bZUp )
{
if ( bZUp )
{
// Z up is technically ambiguous, but only Maya created SMD Z Up files, everything else assumes Z up is Valve engine Z up
SetAxisSystem( CDmeAxisSystem::AS_VALVE_ENGINE );
}
else
{
SetAxisSystem( CDmeAxisSystem::AS_MAYA_YUP );
}
}
//-----------------------------------------------------------------------------
// Returns the matrix that moves DmeModel data to engine space
//-----------------------------------------------------------------------------
void CDmeModel::GetModelToEngineMat( matrix3x4_t &modelToEngineMat )
{
CDmeDag::DmeToEngineMatrix( modelToEngineMat, IsZUp() );
}
//-----------------------------------------------------------------------------
// Returns the matrix that moves engine data to DmeModel space
//-----------------------------------------------------------------------------
void CDmeModel::GetEngineToModelMat( matrix3x4_t &engineToModelMat )
{
CDmeDag::EngineToDmeMatrix( engineToModelMat, IsZUp() );
}
//-----------------------------------------------------------------------------
// Returns true if the data under the DmeModel is AS_VALVE_ENGINE_SPACE ( Up: Z, Fwd: X, Left: Y )
// Returns false otherwise, NOTE: false doesn't imply any other axis system, examine m_eAxisSystem to see
//-----------------------------------------------------------------------------
bool CDmeModel::IsZUp() const
{
Assert( m_eAxisSystem.GetElement() );
if ( m_eAxisSystem.GetElement()->IsEqual( CDmeAxisSystem::AS_VALVE_ENGINE ) )
return true;
if ( m_eAxisSystem.GetElement()->IsEqual( CDmeAxisSystem::AS_MAYA_YUP ) )
return false;
AssertMsg( false, "CDmeModel::IsZUp() called, but axis system is neither AS_VALVE_ENGINE or AS_MAYA_YUP, cannot represent via true/false, ambiguous state" );
return false;
}
//-----------------------------------------------------------------------------
// Replace all instances of a material with a different material
//-----------------------------------------------------------------------------
void CDmeModel::ReplaceMaterial( CDmeDag *pDag, const char *pOldMaterialName, const char *pNewMaterialName )
{
if ( !pDag )
return;
CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
if ( pMesh )
{
pMesh->ReplaceMaterial( pOldMaterialName, pNewMaterialName );
}
int nCount = pDag->GetChildCount();
for ( int i = 0; i < nCount; ++i )
{
CDmeDag *pChild = pDag->GetChild( i );
ReplaceMaterial( pChild, pOldMaterialName, pNewMaterialName );
}
}
void CDmeModel::ReplaceMaterial( const char *pOldMaterialName, const char *pNewMaterialName )
{
ReplaceMaterial( this, pOldMaterialName, pNewMaterialName );
}
//-----------------------------------------------------------------------------
// Gets the joint with the specified name
//-----------------------------------------------------------------------------
CDmeDag *CDmeModel::GetJoint( const char *pJointName )
{
CDmeDag *pJoint = NULL;
const int nJointCount = m_JointList.Count();
for ( int i = 0; i < nJointCount; ++i )
{
pJoint = m_JointList[ i ];
if ( !pJoint )
continue;
if ( !V_stricmp( pJointName, pJoint->GetName() ) )
return pJoint;
}
return NULL;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeModel::ReskinMeshes( const int *pJointTransformIndexRemap )
{
ReskinMeshes( this, pJointTransformIndexRemap );
}
//-----------------------------------------------------------------------------
// Reskin meshes based on bone collapse
//-----------------------------------------------------------------------------
void CDmeModel::ReskinMeshes( CDmeDag *pDag, const int *pJointTransformIndexRemap )
{
if ( !pDag )
return;
CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
if ( pMesh )
{
pMesh->Reskin( pJointTransformIndexRemap );
}
int nCount = pDag->GetChildCount();
for ( int i = 0; i < nCount; ++i )
{
CDmeDag *pChild = pDag->GetChild( i );
ReskinMeshes( pChild, pJointTransformIndexRemap );
}
}
//-----------------------------------------------------------------------------
// Remove joints
//-----------------------------------------------------------------------------
void CDmeModel::RemoveJoints( int nNewJointCount, const int *pInvJointRemap )
{
const int nOldJointTransformCount = m_JointList.Count();
const int nSizeInBytes = nNewJointCount * sizeof(CDmeTransform*);
CDmeDag **ppJoints = (CDmeDag**)stackalloc( nSizeInBytes );
for ( int i = 0; i < nNewJointCount; ++i )
{
ppJoints[i] = m_JointList[ pInvJointRemap[i] ];
}
m_JointList.RemoveAll();
for ( int i = 0; i < nNewJointCount; ++i )
{
m_JointList.AddToTail( ppJoints[i] );
}
CUtlVectorFixedGrowable< CDmeTransform*, 256 > transforms;
const int nCount = m_BaseStates.Count();
for ( int i = 0; i < nCount; ++i )
{
CDmeTransformList *pList = m_BaseStates[i];
int nTransformCount = pList->GetTransformCount();
transforms.SetCount( nTransformCount );
int nStateJointCount = nNewJointCount;
for ( int j = 0; j < nNewJointCount; ++j )
{
transforms[j] = pList->GetTransform( pInvJointRemap[j] );
}
for ( int j = nOldJointTransformCount; j < nTransformCount; ++j )
{
transforms[ nStateJointCount++ ] = pList->GetTransform( j );
}
pList->m_Transforms.RemoveAll();
for ( int j = 0; j < nStateJointCount; ++j )
{
pList->m_Transforms.AddToTail( transforms[ j ] );
}
}
}
//-----------------------------------------------------------------------------
// Updates all base states by adding missing joints
//-----------------------------------------------------------------------------
void CDmeModel::UpdateBaseStates()
{
const int nJointCount = m_JointList.Count();
for ( int i = 0; i < m_BaseStates.Count(); ++i )
{
CDmeTransformList *pTransformList = m_BaseStates[i];
if ( !pTransformList )
continue;
// Make the transform list have the correct number of elements
const int nCurrentCount = pTransformList->GetTransformCount();
if ( nJointCount < nCurrentCount )
{
pTransformList->m_Transforms.RemoveMultiple( nJointCount, nCurrentCount - nJointCount );
return;
}
else if ( nJointCount == nCurrentCount )
{
return;
}
Assert( nJointCount > nCurrentCount );
for ( int i = nCurrentCount; i < nJointCount; ++i )
{
CDmeTransform *pTransform = CreateElement<CDmeTransform>( m_JointList[i]->GetName(), pTransformList->GetFileId() );
pTransformList->m_Transforms.AddToTail( pTransform );
matrix3x4_t mat;
CDmeDag *pDmeDag = m_JointList[i];
if ( !pDmeDag )
continue;
CDmeTransform *pDmeTransform = pDmeDag->GetTransform();
if ( !pDmeTransform )
continue;
pDmeTransform->GetTransform( mat );
pTransformList->SetTransform( i, mat );
}
}
}
//-----------------------------------------------------------------------------
// Removes all children from this joint, moving shapes to be
//-----------------------------------------------------------------------------
void CDmeModel::RemoveAllChildren( CDmeDag *pDag, CDmeDag *pSubtreeRoot, const matrix3x4_t &jointToSubtreeRoot )
{
if ( !pDag )
return;
CDmeTransform *pDagTransform = pDag->GetTransform();
matrix3x4_t curToSubtreeRoot, dagToParent;
pDagTransform->GetTransform( dagToParent );
ConcatTransforms( jointToSubtreeRoot, dagToParent, curToSubtreeRoot );
if ( !CastElement< CDmeJoint >( pDag ) )
{
pSubtreeRoot->AddChild( pDag );
pDagTransform->SetTransform( curToSubtreeRoot );
}
int nCount = pDag->GetChildCount();
for ( int i = 0; i < nCount; ++i )
{
RemoveAllChildren( pDag->GetChild(i), pSubtreeRoot, curToSubtreeRoot );
}
pDag->RemoveAllChildren();
}
void CDmeModel::RemoveAllChildren( CDmeDag *pSubtreeRoot )
{
matrix3x4_t root;
SetIdentityMatrix( root );
int nCount = pSubtreeRoot->GetChildCount();
for ( int i = 0; i < nCount; ++i )
{
CDmeDag *pChild = pSubtreeRoot->GetChild(i);
if ( !CastElement< CDmeJoint >( pChild ) )
continue;
RemoveAllChildren( pChild, pSubtreeRoot, root );
}
// Regetting the child count, as it has changed from the RemoveAllChildren calls
nCount = pSubtreeRoot->GetChildCount();
for ( int i = nCount; --i >= 0; )
{
if ( !CastElement< CDmeJoint >( pSubtreeRoot->GetChild(i) ) )
continue;
pSubtreeRoot->RemoveChild( i );
}
}
//-----------------------------------------------------------------------------
// Collapses all joints below the specified joint name, reskinning any meshes
// referring to collapsed joints to use the specified joint instead
//-----------------------------------------------------------------------------
void CDmeModel::CollapseJoints( const char *pJointName )
{
CDmeDag *pJoint = GetJoint( pJointName );
if ( !pJoint )
return;
// Determine which joints must be collapsed
CDmeDag *pParent;
const int nCount = m_JointList.Count();
bool *pIsCollapsed = (bool*)stackalloc( nCount * sizeof(bool) );
for ( int i = 0; i < nCount; ++i )
{
CDmeDag *pTestJoint = m_JointList[ i ];
if ( !pTestJoint )
continue;
pIsCollapsed[i] = ( pJoint->FindChild( pParent, pTestJoint ) >= 0 );
}
// Build remap indices
int nNewJointCount = 0;
int nCollapseJointIndex = 0;
int* pJointRemap = (int*)stackalloc( nCount * sizeof(int) );
int* pInvJointRemap = (int*)stackalloc( nCount * sizeof(int) );
for ( int i = 0; i < nCount; ++i )
{
if ( pIsCollapsed[i] )
{
pJointRemap[i] = -1;
continue;
}
if ( pJoint == m_JointList[i] )
{
nCollapseJointIndex = nNewJointCount;
}
pInvJointRemap[nNewJointCount] = i;
pJointRemap[i] = nNewJointCount++;
}
for ( int i = 0; i < nCount; ++i )
{
if ( pJointRemap[i] < 0 )
{
pJointRemap[i] = nCollapseJointIndex;
}
}
// Reskin meshes
ReskinMeshes( this, pJointRemap );
// Fixup joint transform + base state lists
RemoveJoints( nNewJointCount, pInvJointRemap );
// Remove all children from this node
RemoveAllChildren( pJoint );
stackfree( pIsCollapsed );
stackfree( pJointRemap );
stackfree( pInvJointRemap );
}
//-----------------------------------------------------------------------------
// Returns the matrix & quaternion to reorient
//-----------------------------------------------------------------------------
void CDmeModel::GetReorientData( matrix3x4_t &m, Quaternion &q, bool bMakeZUp )
{
// YUP_ACTIVE: FIXME
if ( bMakeZUp )
{
static const matrix3x4_t mYtoZ(
0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f );
m = mYtoZ;
matrix3x4a_t mA;
CDmeAxisSystem::GetConversionMatrix( mA, CDmeAxisSystem::AS_MAYA_YUP, CDmeAxisSystem::AS_VALVE_ENGINE );
Assert( MatricesAreEqual( mYtoZ, mA ) );
}
else
{
static const matrix3x4_t mZtoY(
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f );
m = mZtoY;
matrix3x4a_t mA;
CDmeAxisSystem::GetConversionMatrix( mA, CDmeAxisSystem::AS_VALVE_ENGINE, CDmeAxisSystem::AS_MAYA_YUP );
Assert( MatricesAreEqual( mZtoY, mA, 1.0e-4 ) );
}
MatrixQuaternion( m, q );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeModel::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 CDmeModel::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 );
}
//-----------------------------------------------------------------------------
// Changes the orientation of the vertices and normals of a CDmeMesh using
// the given transform.
//-----------------------------------------------------------------------------
void CDmeModel::ReorientDmeMesh( CDmeMesh *pDmeMesh, matrix3x4_t absMat )
{
CDisableUndoScopeGuard();
CDmeVertexData *pDmeVertexData = pDmeMesh->GetBindBaseState();
FieldIndex_t nFieldPosIndex = pDmeVertexData->FindFieldIndex( CDmeVertexDataBase::FIELD_POSITION );
FieldIndex_t nFieldNormIndex = pDmeVertexData->FindFieldIndex( CDmeVertexDataBase::FIELD_NORMAL );
if ( nFieldPosIndex >= 0 && nFieldNormIndex > 0 )
{
CDmAttribute *pDmPositionAttr = pDmeVertexData->GetVertexData( nFieldPosIndex );
CDmAttribute *pDmNormalAttr = pDmeVertexData->GetVertexData( nFieldNormIndex );
CDmrArray< Vector > positions( pDmPositionAttr );
CDmrArray< Vector > normals( pDmNormalAttr );
CUtlVector<Vector> newPositions;
matrix3x4_t normalMat;
MatrixInverseTranspose( absMat, normalMat );
for ( int i = 0; i < positions.Count(); ++i )
{
Vector newPosition;
VectorTransform( positions[i], absMat, newPosition );
positions.Set( i, newPosition );
}
for ( int i = 0; i < normals.Count(); ++i )
{
Vector normalizedNormal;
Vector newNormal;
VectorCopy( normals[i], normalizedNormal );
VectorNormalize( normalizedNormal );
VectorRotate( normalizedNormal, normalMat, newNormal );
normals.Set( i, newNormal );
}
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeModel::ReorientDmeModelChildren( CDmeModel *pDmeModel, const matrix3x4_t &mOrient, const Quaternion &qOrient )
{
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 );
if ( pDmeTransformList )
{
int nJointIndex = pDmeModel->GetJointIndex( pDmeDag );
if ( nJointIndex >= 0 && nJointIndex < nTransformCount )
{
ReorientDmeTransform( pDmeTransformList->GetTransform( nJointIndex ), mOrient, qOrient );
}
}
ReorientDmeAnimation( pDmeDag, mOrient, qOrient );
}
}
//-----------------------------------------------------------------------------
// Changes the orientation of a given CDmeDag's mesh data and those of any
// children the CDmeDag has.
//-----------------------------------------------------------------------------
void CDmeModel::ReorientChildDmeMeshes_R( CDmeDag *pDmeDag )
{
// Reorient the Dag's shape
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
if ( pDmeMesh )
{
matrix3x4_t absMat;
pDmeDag->GetAbsTransform( absMat );
ReorientDmeMesh( pDmeMesh, absMat );
}
// Recurse all child CDmeDags and
const int nChildCount = pDmeDag->GetChildCount();
for ( int i = 0; i < nChildCount; ++i )
{
ReorientChildDmeMeshes_R( pDmeDag->GetChild( i ) );
}
}
//-----------------------------------------------------------------------------
// Walks through the immediate children of this DmeModel and bakes the world
// space transform of any DmeMesh into its vertices and then sets the transform
// of that mesh to the identity. Currently only called by hammer import and
// hammer <-> modo in modo via ReorientToEngineSpace & ReorientToDCCToolSpace
// dmeutils to convert DmeMesh to CMesh uses ReorientToValveEngineSpace
// which does not call FreezeChildMeshes. FreezeChildMeshes is also not a
// complete implementation as it doesn't take into account deltas on meshes
//-----------------------------------------------------------------------------
void CDmeModel::FreezeChildMeshes()
{
const int nChildCount = GetChildCount();
for ( int i = 0; i < nChildCount; ++i )
{
CDmeDag *pDmeDag = GetChild( i );
if ( !pDmeDag )
continue;
ReorientChildDmeMeshes_R( pDmeDag );
// Zero out the rotation since ReorientChildDmeMeshes_R bakes it into the mesh
CDmeTransform *pTransform = pDmeDag->GetTransform();
if ( pTransform )
{
Quaternion qZero;
qZero.Init();
pTransform->SetOrientation( qZero );
}
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeModel::SetAxisSystem( CDmeAxisSystem::PredefinedAxisSystem ePredefAxisSystem )
{
if ( !m_eAxisSystem.GetElement() )
return false;
return m_eAxisSystem.GetElement()->Init( ePredefAxisSystem );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeModel::SetAxisSystem(
CDmeAxisSystem::Axis_t eUpAxis,
CDmeAxisSystem::ForwardParity_t eForwardParity,
CDmeAxisSystem::CoordSys_t eCoordSys /* = CDmeAxisSystem::AS_RIGHT_HANDED */ )
{
if ( !m_eAxisSystem.GetElement() )
return false;
return m_eAxisSystem.GetElement()->Init( eUpAxis, eForwardParity, eCoordSys );
}
//-----------------------------------------------------------------------------
// This expects the app has handled undo
//-----------------------------------------------------------------------------
bool CDmeModel::ConvertToAxisSystem( CDmeAxisSystem::PredefinedAxisSystem eToPredefinedAxisSystem )
{
if ( !m_eAxisSystem.GetElement() )
return false;
CDmeAxisSystem::Axis_t eToUpAxis;
CDmeAxisSystem::ForwardParity_t eToForwardParity;
CDmeAxisSystem::CoordSys_t eToCoordSys;
if ( !CDmeAxisSystem::GetPredefinedAxisSystem( eToUpAxis, eToForwardParity, eToCoordSys, eToPredefinedAxisSystem ) )
return false;
return ConvertToAxisSystem( eToUpAxis, eToForwardParity, eToCoordSys );
}
//-----------------------------------------------------------------------------
// This expects the app has handled undo
//-----------------------------------------------------------------------------
bool CDmeModel::ConvertToAxisSystem(
CDmeAxisSystem::Axis_t eToUpAxis,
CDmeAxisSystem::ForwardParity_t eToForwardParity,
CDmeAxisSystem::CoordSys_t eToCoordSys /* = CDmeAxisSystem::AS_RIGHT_HANDED */ )
{
if ( !m_eAxisSystem.GetElement() )
return false;
if ( !CDmeAxisSystem::IsValid( eToUpAxis, eToForwardParity, eToCoordSys ) )
return false;
const CDmeAxisSystem *pFromDmeAxisSystem = m_eAxisSystem.GetElement();
Assert( pFromDmeAxisSystem->IsValid() );
const CDmeAxisSystem::Axis_t eFromUpAxis = pFromDmeAxisSystem->GetUpAxis();
const CDmeAxisSystem::ForwardParity_t eFromForwardParity = pFromDmeAxisSystem->GetForwardParity();
const CDmeAxisSystem::CoordSys_t eFromCoordSys = pFromDmeAxisSystem->GetCoordSys();
Assert( CDmeAxisSystem::IsValid( eToUpAxis, eToForwardParity, eToCoordSys ) );
if ( eFromUpAxis == eToUpAxis &&
eFromForwardParity == eToForwardParity &&
eFromCoordSys == eToCoordSys )
{
// No change needed
return true;
}
matrix3x4a_t mConversion = g_MatrixIdentity;
CDmeAxisSystem::GetConversionMatrix( mConversion, eFromUpAxis, eFromForwardParity, eFromCoordSys, eToUpAxis, eToForwardParity, eToCoordSys );
const Quaternion qConversion = MatrixQuaternion( mConversion );
ReorientDmeModelChildren( this, mConversion, qConversion );
m_UpAxis.Set( "axisSystem" );
return SetAxisSystem( eToUpAxis, eToForwardParity, eToCoordSys );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeModel::GetConversionMatrix( matrix3x4a_t &mConversion, CDmeAxisSystem::PredefinedAxisSystem eToPredefinedAxisSystem )
{
const CDmeAxisSystem *pFromDmeAxisSystem = m_eAxisSystem.GetElement();
Assert( pFromDmeAxisSystem->IsValid() );
const CDmeAxisSystem::Axis_t eFromUpAxis = pFromDmeAxisSystem->GetUpAxis();
const CDmeAxisSystem::ForwardParity_t eFromForwardParity = pFromDmeAxisSystem->GetForwardParity();
const CDmeAxisSystem::CoordSys_t eFromCoordSys = pFromDmeAxisSystem->GetCoordSys();
CDmeAxisSystem::Axis_t eToUpAxis;
CDmeAxisSystem::ForwardParity_t eToForwardParity;
CDmeAxisSystem::CoordSys_t eToCoordSys;
if ( !CDmeAxisSystem::GetPredefinedAxisSystem( eToUpAxis, eToForwardParity, eToCoordSys, eToPredefinedAxisSystem ) )
return false;
CDmeAxisSystem::GetConversionMatrix( mConversion, eFromUpAxis, eFromForwardParity, eFromCoordSys, eToUpAxis, eToForwardParity, eToCoordSys );
return true;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeModel::TransformScene(
const Vector &vScale /*= Vector( 1.0f, 1.0f, 1.0f )*/,
const Vector &vTranslate /*= vec3_origin*/,
const DegreeEuler &eRotation /*= DegreeEuler( 0.0f, 0.0f, 0.0f )*/,
float flEps /*= 1.0e-4 */ )
{
if ( !VectorsAreEqual( vScale, Vector( 1.0f, 1.0f, 1.0f ), flEps ) )
{
ScaleScene( vScale );
}
if ( !VectorsAreEqual( vTranslate, vec3_origin, flEps ) || !DegreeEulersAreEqual( eRotation, DegreeEuler( 0.0f, 0.0f, 0.0f ), flEps ) )
{
matrix3x4a_t mTransform;
AngleMatrix( RadianEuler( eRotation ), vTranslate, mTransform );
matrix3x4a_t mIdentity;
SetIdentityMatrix( mIdentity );
matrix3x4a_t mDag;
CDmeTransform *pDmeModelTransform = GetTransform();
pDmeModelTransform->GetTransform( mDag );
if ( MatricesAreEqual( mDag, mIdentity, flEps ) )
{
// DmeModel is just a group, leave it alone, put transform on all children
const int nChildCount = GetChildCount();
for ( int i = 0; i < nChildCount; ++i )
{
CDmeDag *pDmeDagChild = GetChild( i );
CDmeTransform *pDmeTransform = pDmeDagChild->GetTransform();
pDmeTransform->GetTransform( mDag );
pDmeTransform->SetTransform( ConcatTransforms( mTransform, mDag ) );
}
}
else
{
// DmeModel has transformation data of its own... put transform on it
pDmeModelTransform->SetTransform( ConcatTransforms( mTransform, mDag ) );
}
}
CaptureJointsToBaseState( "bind" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeModel::ScaleScene( const Vector &vScale )
{
CUtlStack< CDmeDag * > depthFirstStack;
depthFirstStack.Push( this );
while ( depthFirstStack.Count() > 0 )
{
CDmeDag *pDmeDag = depthFirstStack.Top();
depthFirstStack.Pop();
if ( !pDmeDag )
continue;
const int nChildCount = pDmeDag->GetChildCount();
for ( int i = nChildCount + 1; i >= 0; --i )
{
depthFirstStack.Push( pDmeDag->GetChild( i ) );
}
CDmeTransform *pDmeTransform = pDmeDag->GetTransform();
Vector vLocalPos = pDmeTransform->GetPosition();
vLocalPos.x *= vScale.x;
vLocalPos.y *= vScale.y;
vLocalPos.z *= vScale.z;
pDmeTransform->SetPosition( vLocalPos );
matrix3x4a_t mScale;
SetScaleMatrix( vScale, mScale );
matrix3x4a_t mScaleInvTranspose;
MatrixInverseTranspose( mScale, mScaleInvTranspose );
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
if ( pDmeMesh )
{
CUtlVector< CDmeVertexDataBase * > vertexDataList;
const int nStateCount = pDmeMesh->BaseStateCount();
for ( int i = 0; i < nStateCount; ++i )
{
CDmeVertexDataBase *pDmeVertexData = pDmeMesh->GetBaseState( i );
if ( pDmeVertexData )
{
vertexDataList.AddToTail( pDmeVertexData );
}
}
// TODO: See if delta data needs to be scaled differently, positions shouldn't but normals might
const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
for ( int i = 0; i < nDeltaStateCount; ++i )
{
CDmeVertexDataBase *pDmeVertexData = pDmeMesh->GetDeltaState( i );
if ( pDmeVertexData )
{
vertexDataList.AddToTail( pDmeVertexData );
}
}
const int nVertexDataCount = vertexDataList.Count();
for ( int i = 0; i < nVertexDataCount; ++i )
{
CDmeVertexDataBase *pDmeVertexData = vertexDataList[i];
const FieldIndex_t nPosFieldIndex = pDmeVertexData->FindFieldIndex( CDmeVertexDataBase::FIELD_POSITION );
if ( nPosFieldIndex >= 0 )
{
CDmrArray< Vector > vertexData = pDmeVertexData->GetVertexData( nPosFieldIndex );
const int nDataCount = vertexData.Count();
for ( int j = 0; j < nDataCount; ++j )
{
vertexData.Set( j, VectorTransform( vertexData.Get( j ), mScale ) );
}
}
const FieldIndex_t nNormalFieldIndex = pDmeVertexData->FindFieldIndex( CDmeVertexDataBase::FIELD_NORMAL );
if ( nPosFieldIndex >= 0 )
{
CDmrArray< Vector > vertexData = pDmeVertexData->GetVertexData( nNormalFieldIndex );
const int nDataCount = vertexData.Count();
for ( int j = 0; j < nDataCount; ++j )
{
vertexData.Set( j, VectorTransform( vertexData.Get( j ), mScaleInvTranspose ).Normalized() );
}
}
}
}
}
}
#if 0
//-----------------------------------------------------------------------------
// temp function for validation of code changes, used by CompareDmeDag_R
//-----------------------------------------------------------------------------
static bool CompareDmeMeshes( CDmeMesh *pDmeMeshA, CDmeMesh *pDmeMeshB )
{
if ( !pDmeMeshA && !pDmeMeshB )
return true;
if ( !pDmeMeshA || !pDmeMeshB )
return false;
pDmeMeshA->Resolve();
pDmeMeshB->Resolve();
if ( pDmeMeshA->BaseStateCount() != pDmeMeshB->BaseStateCount() )
{
AssertMsg( 0, "DmeMesh BaseStateCount mismatch: %s:%d vs %s:%d\n", pDmeMeshA->GetName(), pDmeMeshA->BaseStateCount(), pDmeMeshB->GetName(), pDmeMeshB->BaseStateCount() );
return false;
}
CDmeVertexData *pDmeVertexDataA = pDmeMeshA->GetBindBaseState();
CDmeVertexData *pDmeVertexDataB = pDmeMeshB->GetBindBaseState();
if ( !pDmeVertexDataA && !pDmeVertexDataB )
return true; // No vertex data in bind base state... not really a good state but they are the same
if ( !pDmeVertexDataA || !pDmeVertexDataB )
{
AssertMsg( 0, "DmeMesh one NULL BindBaseState: %s:0x%p vs %s:0x%p\n", pDmeMeshA->GetName(), pDmeVertexDataA, pDmeMeshB->GetName(), pDmeVertexDataB );
return false;
}
pDmeVertexDataA->Resolve();
pDmeVertexDataB->Resolve();
const CUtlVector< Vector > &posDataA = pDmeVertexDataA->GetPositionData();
const CUtlVector< Vector > &posDataB = pDmeVertexDataB->GetPositionData();
if ( posDataA.Count() != posDataB.Count() )
{
AssertMsg( 0, "DmeMesh posData count mismatch: %s:%d vs %s:%d\n", pDmeMeshA->GetName(), posDataA.Count(), pDmeMeshB->GetName(), posDataB.Count() );
return false;
}
for ( int i = 0; i < posDataA.Count(); ++i )
{
if ( !VectorsAreEqual( posDataA[i], posDataB[i] ) )
{
AssertMsg( 0, "DmeMesh posData vector mismatch: %d %s:< %6.2f %6.2f %6.2f > vs %s:< %6.2f %6.2f %6.2f >\n",
i,
pDmeMeshA->GetName(),
posDataA[i].x,
posDataA[i].y,
posDataA[i].z,
pDmeMeshB->GetName(),
posDataB[i].x,
posDataB[i].y,
posDataB[i].z );
return false;
}
}
const CUtlVector< Vector > &normalDataA = pDmeVertexDataA->GetNormalData();
const CUtlVector< Vector > &normalDataB = pDmeVertexDataB->GetNormalData();
if ( normalDataA.Count() != normalDataB.Count() )
{
AssertMsg( 0, "DmeMesh normalData count mismatch: %s:%d vs %s:%d\n", pDmeMeshA->GetName(), normalDataA.Count(), pDmeMeshB->GetName(), normalDataB.Count() );
return false;
}
for ( int i = 0; i < normalDataA.Count(); ++i )
{
if ( !VectorsAreEqual( normalDataA[i], normalDataB[i] ) )
{
AssertMsg( 0, "DmeMesh normalData vector mismatch: %d %s:< %6.2f %6.2f %6.2f > vs %s:< %6.2f %6.2f %6.2f >\n",
i,
pDmeMeshA->GetName(),
normalDataA[i].x,
normalDataA[i].y,
normalDataA[i].z,
pDmeMeshB->GetName(),
normalDataB[i].x,
normalDataB[i].y,
normalDataB[i].z );
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// temp function for validation of code changes, used by CompareDmeDag_R
//-----------------------------------------------------------------------------
static bool CompareDmeDag_R( CDmeDag *pDmeDagA, CDmeDag *pDmeDagB )
{
// Both NULL, Ok
if ( !pDmeDagA && !pDmeDagB )
return true;
// Only one NULL, bad
if ( !pDmeDagA || !pDmeDagB )
{
AssertMsg( 0, "One Dag NULL, the other isn't: 0x%p vs 0x%p\n", pDmeDagA, pDmeDagB );
return false;
}
// Names don't match, bad
if ( V_strcmp( pDmeDagA->GetName(), pDmeDagB->GetName() ) )
{
AssertMsg( 0, "Shape name mismatch: %s vs %s\n", pDmeDagA->GetName(), pDmeDagB->GetName() );
return false;
}
// Transforms don't match, bad
CDmeTransform *pDmeTransformA = pDmeDagA->GetTransform();
CDmeTransform *pDmeTransformB = pDmeDagB->GetTransform();
if ( pDmeTransformA && pDmeTransformB )
{
matrix3x4a_t mA;
pDmeTransformA->GetTransform( mA );
matrix3x4a_t mB;
pDmeTransformB->GetTransform( mB );
if ( !MatricesAreEqual( mA, mB ) )
{
AssertMsg( 0, "Matrix mismatch" );
return false;
}
}
else if ( pDmeTransformA || pDmeTransformB )
{
AssertMsg( 0, "One DmeTransform NULL, the other isn't: %s 0x%p vs %s 0x%p \n", pDmeDagA->GetName(), pDmeTransformA, pDmeDagB->GetName(), pDmeTransformB );
return false;
}
// Compare shapes, if they exist
CDmeShape *pDmeShapeA = pDmeDagA->GetShape();
CDmeShape *pDmeShapeB = pDmeDagB->GetShape();
if ( pDmeShapeA && pDmeShapeB )
{
if ( pDmeShapeA->GetType() != pDmeShapeB->GetType() )
{
AssertMsg( 0, "Shape type mismatch: %s vs %s\n", pDmeShapeA->GetTypeString(), pDmeShapeB->GetTypeString() );
return false;
}
if ( pDmeShapeA->IsA( CDmeMesh::GetStaticTypeSymbol() ) )
{
if ( !CompareDmeMeshes( CastElement< CDmeMesh >( pDmeShapeA ), CastElement< CDmeMesh >( pDmeShapeB ) ) )
{
AssertMsg( 0, "Mesh Mismatch: %s vs %s\n", pDmeShapeA->GetName(), pDmeShapeB->GetName() );
return false;
}
}
}
else if ( pDmeShapeA || pDmeShapeB )
{
AssertMsg( 0, "One Shape NULL, the other isn't: 0x%p vs 0x%p\n", pDmeShapeA, pDmeShapeB );
return false;
}
// Child count don't match, bad
const int nChildCountA = pDmeDagA->GetChildCount();
const int nChildCountB = pDmeDagB->GetChildCount();
if ( nChildCountA != nChildCountB )
return false;
// Compare their children
for ( int i = 0; i < nChildCountA; ++i )
{
if ( !CompareDmeDag_R( pDmeDagA->GetChild( i ), pDmeDagB->GetChild( i ) ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// temp function for validation of code changes, used by CompareDmeDag_R
//-----------------------------------------------------------------------------
static void ResolveDmeDagHierarchy_R( CDmeDag *pDmeDag )
{
if ( !pDmeDag )
return;
pDmeDag->Resolve();
CDmeShape *pDmeShape = pDmeDag->GetShape();
if ( pDmeShape )
{
pDmeShape->Resolve();
CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeShape );
if ( pDmeMesh )
{
pDmeMesh->Resolve();
for ( int i = 0; i < pDmeMesh->BaseStateCount(); ++i )
{
CDmeVertexData *pDmeVertexData = pDmeMesh->GetBaseState( i );
if ( pDmeVertexData )
{
pDmeVertexData->Resolve();
}
}
}
}
for ( int i = 0; i < pDmeDag->GetChildCount(); ++i )
{
ResolveDmeDagHierarchy_R( pDmeDag->GetChild( i ) );
}
}
#endif // 0