summaryrefslogtreecommitdiff
path: root/utils/studiomdl/dmxsupport.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/studiomdl/dmxsupport.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/studiomdl/dmxsupport.cpp')
-rw-r--r--utils/studiomdl/dmxsupport.cpp1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/utils/studiomdl/dmxsupport.cpp b/utils/studiomdl/dmxsupport.cpp
new file mode 100644
index 0000000..2e83255
--- /dev/null
+++ b/utils/studiomdl/dmxsupport.cpp
@@ -0,0 +1,1213 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Loads mesh data from dmx files
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "studiomdl.h"
+#include "movieobjects/dmemodel.h"
+#include "movieobjects/dmemesh.h"
+#include "movieobjects/dmefaceset.h"
+#include "movieobjects/dmematerial.h"
+#include "movieobjects/dmeclip.h"
+#include "movieobjects/dmechannel.h"
+#include "movieobjects/dmeattachment.h"
+#include "movieobjects/dmeanimationlist.h"
+#include "movieobjects/dmecombinationoperator.h"
+
+
+void UnifyIndices( s_source_t *psource );
+
+
+//-----------------------------------------------------------------------------
+// Mapping of bone transforms
+//-----------------------------------------------------------------------------
+struct BoneTransformMap_t
+{
+ // Number of bones
+ int m_nBoneCount;
+
+ // The order in which transforms appear in this list specifies their bone indices
+ CDmeTransform *m_ppTransforms[MAXSTUDIOSRCBONES];
+
+ // BoneRemap[bone index in file] == bone index in studiomdl
+ int m_pBoneRemap[MAXSTUDIOSRCBONES];
+};
+
+
+//-----------------------------------------------------------------------------
+// Index into an s_node_t array for the default root node
+//-----------------------------------------------------------------------------
+static int s_nDefaultRootNode;
+
+
+//-----------------------------------------------------------------------------
+// Balance/speed data
+//-----------------------------------------------------------------------------
+static CUtlVector<float> s_Balance;
+static CUtlVector<float> s_Speed;
+
+
+//-----------------------------------------------------------------------------
+// List of unique vertices
+//-----------------------------------------------------------------------------
+struct VertIndices_t
+{
+ int v;
+ int n;
+ int t;
+ int balance;
+ int speed;
+};
+
+static CUtlVector< VertIndices_t > s_UniqueVertices; // A list of the unique vertices in the mesh
+
+// Given the non-unique vertex index, return the unique vertex index
+// The indices are absolute indices into s_UniqueVertices
+// But as both arrays contain information for all meshes in the DMX
+// The proper offset for the desired mesh must be added to the lookup
+// into the map but the value returned has the offset already built in
+static CUtlVector< int > s_UniqueVerticesMap;
+
+
+//-----------------------------------------------------------------------------
+// Delta state intermediate data [used for positions, normals, etc.]
+//-----------------------------------------------------------------------------
+struct DeltaIndex_t
+{
+ DeltaIndex_t() : m_nPositionIndex(-1), m_nNormalIndex(-1), m_nNextDelta(-1), m_nWrinkleIndex(-1), m_bInList(false) {}
+ int m_nPositionIndex; // Index into DeltaState_t::m_PositionDeltas
+ int m_nNormalIndex; // Index into DeltaState_t::m_NormalDeltas
+ int m_nWrinkleIndex; // Index into DeltaState_t::m_WrinkleDeltas
+ int m_nNextDelta; // Index into DeltaState_t::m_DeltaIndices;
+ bool m_bInList;
+};
+
+struct DeltaState_t
+{
+ DeltaState_t() : m_nDeltaCount( 0 ), m_nFirstDelta( -1 ) {}
+
+ CUtlString m_Name;
+ CUtlVector< Vector > m_PositionDeltas;
+ CUtlVector< Vector > m_NormalDeltas;
+ CUtlVector< float > m_WrinkleDeltas;
+ CUtlVector< DeltaIndex_t > m_DeltaIndices;
+ int m_nDeltaCount;
+ int m_nFirstDelta;
+};
+
+
+// NOTE: This is a temporary which loses its state once Load_DMX is exited.
+static CUtlVector<DeltaState_t> s_DeltaStates;
+
+
+//-----------------------------------------------------------------------------
+// Finds or adds delta states. These pointers are invalidated by calling FindOrAddDeltaState again
+//-----------------------------------------------------------------------------
+static DeltaState_t* FindOrAddDeltaState( const char *pDeltaStateName, int nBaseStateVertexCount )
+{
+ int nCount = s_DeltaStates.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( !Q_stricmp( s_DeltaStates[i].m_Name, pDeltaStateName ) )
+ {
+ MdlWarning( "Unsupported duplicate delta state named \"%s\" in DMX file\n", pDeltaStateName );
+
+ s_DeltaStates[i].m_DeltaIndices.EnsureCount( nBaseStateVertexCount );
+ return &s_DeltaStates[i];
+ }
+ }
+
+ int j = s_DeltaStates.AddToTail();
+ s_DeltaStates[j].m_Name = pDeltaStateName;
+ s_DeltaStates[j].m_DeltaIndices.SetCount( nBaseStateVertexCount );
+ return &s_DeltaStates[j];
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the vertices from the model
+//-----------------------------------------------------------------------------
+static bool DefineUniqueVertices( CDmeVertexData *pBindState, int nStartingUniqueCount )
+{
+ const CUtlVector<int> &positionIndices = pBindState->GetVertexIndexData( CDmeVertexData::FIELD_POSITION );
+ const CUtlVector<int> &normalIndices = pBindState->GetVertexIndexData( CDmeVertexData::FIELD_NORMAL );
+ const CUtlVector<int> &texcoordIndices = pBindState->GetVertexIndexData( CDmeVertexData::FIELD_TEXCOORD );
+ const CUtlVector<int> &balanceIndices = pBindState->GetVertexIndexData( CDmeVertexData::FIELD_BALANCE );
+ const CUtlVector<int> &speedIndices = pBindState->GetVertexIndexData( CDmeVertexData::FIELD_MORPH_SPEED );
+
+ int nPositionCount = positionIndices.Count();
+ int nNormalCount = normalIndices.Count();
+ int nTexcoordCount = texcoordIndices.Count();
+ int nBalanceCount = balanceIndices.Count();
+ int nSpeedCount = speedIndices.Count();
+ if ( nNormalCount && nPositionCount != nNormalCount )
+ {
+ MdlError( "Encountered a mesh with invalid geometry (different number of indices for various data fields)\n" );
+ return false;
+ }
+ if ( nTexcoordCount && nPositionCount != nTexcoordCount )
+ {
+ MdlError( "Encountered a mesh with invalid geometry (different number of indices for various data fields)\n" );
+ return false;
+ }
+ if ( nBalanceCount && nPositionCount != nBalanceCount )
+ {
+ MdlError( "Encountered a mesh with invalid geometry (different number of indices for various data fields)\n" );
+ return false;
+ }
+ if ( nSpeedCount && nPositionCount != nSpeedCount )
+ {
+ MdlError( "Encountered a mesh with invalid geometry (different number of indices for various data fields)\n" );
+ return false;
+ }
+
+ // Only add unique vertices to the list as in UnifyIndices
+
+ for ( int i = 0; i < nPositionCount; ++i )
+ {
+ VertIndices_t vert;
+ vert.v = g_numverts + positionIndices[i];
+ vert.n = ( nNormalCount > 0 ) ? g_numnormals + normalIndices[i] : -1;
+ vert.t = ( nTexcoordCount > 0 ) ? g_numtexcoords + texcoordIndices[i] : -1;
+ vert.balance = s_Balance.Count() + ( ( nBalanceCount > 0 ) ? balanceIndices[i] : 0 );
+ vert.speed = s_Speed.Count() + ( ( nSpeedCount > 0 ) ? speedIndices[i] : 0 );
+
+ bool unique( true );
+ for ( int j = nStartingUniqueCount; j < s_UniqueVertices.Count(); ++j )
+ {
+ const VertIndices_t &tmpVert( s_UniqueVertices[j] );
+
+ if ( vert.v != tmpVert.v )
+ continue;
+ if ( vert.n != tmpVert.n )
+ continue;
+ if ( vert.t != tmpVert.t )
+ continue;
+
+ unique = false;
+ s_UniqueVerticesMap.AddToTail( j );
+ break;
+ }
+
+ if ( !unique )
+ continue;
+
+ int k = s_UniqueVertices.AddToTail();
+ s_UniqueVertices[k] = vert;
+ s_UniqueVerticesMap.AddToTail( k );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the vertices from the model
+//-----------------------------------------------------------------------------
+static bool LoadVertices( CDmeVertexData *pBindState, const matrix3x4_t& mat, float flScale, int nBoneAssign, int *pBoneRemap, int nStartingUniqueCount )
+{
+ if ( nBoneAssign < 0 )
+ {
+ nBoneAssign = s_nDefaultRootNode;
+ }
+
+ // Used by the morphing system to set up delta states
+ DefineUniqueVertices( pBindState, nStartingUniqueCount );
+
+ matrix3x4_t normalMat;
+ MatrixInverseTranspose( mat, normalMat );
+
+ const CUtlVector<Vector> &positions = pBindState->GetPositionData( );
+ const CUtlVector<Vector> &normals = pBindState->GetNormalData( );
+ const CUtlVector<Vector2D> &texcoords = pBindState->GetTextureCoordData( );
+ const CUtlVector<float> &balances = pBindState->GetBalanceData( );
+ const CUtlVector<float> &speeds = pBindState->GetMorphSpeedData( );
+
+ int nCount = positions.Count();
+ int nJointCount = pBindState->HasSkinningData() ? pBindState->JointCount() : 0;
+ if ( nJointCount > MAXSTUDIOBONEWEIGHTS )
+ {
+ MdlError( "Too many bone influences per vertex!\n" );
+ return false;
+ }
+
+ // Copy positions + bone info
+ for ( int i = 0; i < nCount; ++i )
+ {
+ // NOTE: The transform transforms the positions into the bind space
+ VectorTransform( positions[i], mat, g_vertex[g_numverts] );
+ g_vertex[g_numverts] *= flScale;
+ if ( nJointCount == 0 )
+ {
+ g_bone[g_numverts].numbones = 1;
+ g_bone[g_numverts].bone[0] = pBoneRemap[ nBoneAssign ];
+ g_bone[g_numverts].weight[0] = 1.0;
+ }
+ else
+ {
+ const float *pJointWeights = pBindState->GetJointWeightData( i );
+ const int *pJointIndices = pBindState->GetJointIndexData( i );
+
+ float *pWeightBuf = (float*)_alloca( nJointCount * sizeof(float) );
+ int *pIndexBuf = (int*)_alloca( nJointCount * sizeof(int) );
+ memcpy( pWeightBuf, pJointWeights, nJointCount * sizeof(float) );
+ memcpy( pIndexBuf, pJointIndices, nJointCount * sizeof(int) );
+
+ int nBoneCount = SortAndBalanceBones( nJointCount, MAXSTUDIOBONEWEIGHTS, pIndexBuf, pWeightBuf );
+
+ g_bone[g_numverts].numbones = nBoneCount;
+ for ( int j = 0; j < nBoneCount; ++j )
+ {
+ g_bone[g_numverts].bone[j] = pBoneRemap[ pIndexBuf[j] ];
+ g_bone[g_numverts].weight[j] = pWeightBuf[j];
+ }
+ }
+ ++g_numverts;
+ }
+
+ // Copy normals
+ nCount = normals.Count();
+ if ( nCount + g_numnormals > MAXSTUDIOVERTS )
+ {
+ MdlError( "Too many normals in model!\n" );
+ return false;
+ }
+ for ( int i = 0; i < nCount; ++i )
+ {
+ VectorRotate( normals[i], normalMat, g_normal[g_numnormals] );
+ VectorNormalize( g_normal[g_numnormals] );
+ ++g_numnormals;
+ }
+
+ // Copy texcoords
+ nCount = texcoords.Count();
+ if ( nCount + g_numtexcoords > MAXSTUDIOVERTS )
+ {
+ MdlError( "Too many texture coordinates in model!\n" );
+ return false;
+ }
+ bool bFlipVCoordinate = pBindState->IsVCoordinateFlipped();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ g_texcoord[g_numtexcoords].x = texcoords[i].x;
+ g_texcoord[g_numtexcoords].y = bFlipVCoordinate ? 1.0f - texcoords[i].y : texcoords[i].y;
+ ++g_numtexcoords;
+ }
+
+ // In the event of no speed or balance map, use the same value of 1 for all vertices
+ if ( balances.Count() )
+ {
+ s_Balance.AddMultipleToTail( balances.Count(), balances.Base() );
+ }
+ else
+ {
+ s_Balance.AddToTail( 1.0f );
+ }
+
+ if ( speeds.Count() )
+ {
+ s_Speed.AddMultipleToTail( speeds.Count(), speeds.Base() );
+ }
+ else
+ {
+ s_Speed.AddToTail( 1.0f );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Hook delta into delta list
+//-----------------------------------------------------------------------------
+static void AddToDeltaList( DeltaState_t *pDeltaStateData, int nUniqueVertex )
+{
+ DeltaIndex_t &index = pDeltaStateData->m_DeltaIndices[ nUniqueVertex ];
+ if ( !index.m_bInList )
+ {
+ index.m_nNextDelta = pDeltaStateData->m_nFirstDelta;
+ pDeltaStateData->m_nFirstDelta = nUniqueVertex;
+ pDeltaStateData->m_nDeltaCount++;
+ index.m_bInList = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the vertices from the delta state
+//-----------------------------------------------------------------------------
+
+static bool LoadDeltaState(
+ CDmeVertexDeltaData *pDeltaState,
+ CDmeVertexData *pBindState,
+ const matrix3x4_t& mat,
+ float flScale,
+ int nStartingUniqueVertex,
+ int nStartingUniqueVertexMap )
+{
+ DeltaState_t *pDeltaStateData = FindOrAddDeltaState( pDeltaState->GetName(), nStartingUniqueVertex + pBindState->VertexCount() );
+
+ matrix3x4_t normalMat;
+ MatrixInverseTranspose( mat, normalMat );
+
+ const CUtlVector<Vector> &positions = pDeltaState->GetPositionData( );
+ const CUtlVector<int> &positionIndices = pDeltaState->GetVertexIndexData( CDmeVertexDataBase::FIELD_POSITION );
+ const CUtlVector<Vector> &normals = pDeltaState->GetNormalData( );
+ const CUtlVector<int> &normalIndices = pDeltaState->GetVertexIndexData( CDmeVertexDataBase::FIELD_NORMAL );
+ const CUtlVector<float> &wrinkle = pDeltaState->GetWrinkleData( );
+ const CUtlVector<int> &wrinkleIndices = pDeltaState->GetVertexIndexData( CDmeVertexDataBase::FIELD_WRINKLE );
+
+ if ( positions.Count() != positionIndices.Count() )
+ {
+ MdlError( "DeltaState %s contains a different number of positions + position indices!\n", pDeltaState->GetName() );
+ return false;
+ }
+
+ if ( normals.Count() != normalIndices.Count() )
+ {
+ MdlError( "DeltaState %s contains a different number of normals + normal indices!\n", pDeltaState->GetName() );
+ return false;
+ }
+
+ if ( wrinkle.Count() != wrinkleIndices.Count() )
+ {
+ MdlError( "DeltaState %s contains a different number of wrinkles + wrinkle indices!\n", pDeltaState->GetName() );
+ return false;
+ }
+
+ // Copy position delta
+ int nCount = positions.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ Vector vecDelta;
+
+ // NOTE NOTE!!: This is VectorRotate, *not* VectorTransform. This is because
+ // we're transforming a delta, which is basically a direction vector. To
+ // move it into the new space, we must rotate it
+ VectorRotate( positions[i], mat, vecDelta );
+ vecDelta *= flScale;
+
+ int nPositionIndex = pDeltaStateData->m_PositionDeltas.AddToTail( vecDelta );
+
+ // Indices
+ const CUtlVector< int > &baseVerts = pBindState->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_POSITION, positionIndices[i] );
+ int nBaseVertCount = baseVerts.Count();
+ for ( int k = 0; k < nBaseVertCount; ++k )
+ {
+ int nUniqueVertexIndex = s_UniqueVerticesMap[ nStartingUniqueVertexMap + baseVerts[k] ];
+ AddToDeltaList( pDeltaStateData, nUniqueVertexIndex );
+ DeltaIndex_t &index = pDeltaStateData->m_DeltaIndices[ nUniqueVertexIndex ];
+ index.m_nPositionIndex = nPositionIndex;
+ }
+ }
+
+ // Copy normals
+ nCount = normals.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ Vector vecDelta;
+ VectorRotate( normals[i], normalMat, vecDelta );
+ int nNormalIndex = pDeltaStateData->m_NormalDeltas.AddToTail( vecDelta );
+
+ // Indices
+ const CUtlVector< int > &baseVerts = pBindState->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_NORMAL, normalIndices[i] );
+ int nBaseVertCount = baseVerts.Count();
+ for ( int k = 0; k < nBaseVertCount; ++k )
+ {
+ int nUniqueVertexIndex = s_UniqueVerticesMap[ nStartingUniqueVertexMap + baseVerts[k] ];
+ AddToDeltaList( pDeltaStateData, nUniqueVertexIndex );
+ DeltaIndex_t &index = pDeltaStateData->m_DeltaIndices[ nUniqueVertexIndex ];
+ index.m_nNormalIndex = nNormalIndex;
+ }
+ }
+
+ // Copy wrinkle
+ nCount = wrinkle.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ int nWrinkleIndex = pDeltaStateData->m_WrinkleDeltas.AddToTail( wrinkle[i] );
+
+ // Indices
+ const CUtlVector< int > &baseVerts = pBindState->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_WRINKLE, wrinkleIndices[i] );
+ int nBaseVertCount = baseVerts.Count();
+ for ( int k = 0; k < nBaseVertCount; ++k )
+ {
+ int nUniqueVertexIndex = s_UniqueVerticesMap[ nStartingUniqueVertexMap + baseVerts[k] ];
+ AddToDeltaList( pDeltaStateData, nUniqueVertexIndex );
+ DeltaIndex_t &index = pDeltaStateData->m_DeltaIndices[ nUniqueVertexIndex ];
+ index.m_nWrinkleIndex = nWrinkleIndex;
+ }
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads the face data from the DMX data
+//-----------------------------------------------------------------------------
+static void ParseFaceData( CDmeVertexData *pVertexData, int material, int v1, int v2, int v3, int vi, int ni, int ti )
+{
+ s_tmpface_t f;
+ f.material = material;
+
+ int p, n, t;
+ p = pVertexData->GetPositionIndex(v1); n = pVertexData->GetNormalIndex(v1); t = pVertexData->GetTexCoordIndex(v1);
+ f.a = ( p >= 0 ) ? vi + p : 0; f.na = ( n >= 0 ) ? ni + n : 0; f.ta = ( t >= 0 ) ? ti + t : 0;
+ p = pVertexData->GetPositionIndex(v2); n = pVertexData->GetNormalIndex(v2); t = pVertexData->GetTexCoordIndex(v2);
+ f.b = ( p >= 0 ) ? vi + p : 0; f.nb = ( n >= 0 ) ? ni + n : 0; f.tb = ( t >= 0 ) ? ti + t : 0;
+ p = pVertexData->GetPositionIndex(v3); n = pVertexData->GetNormalIndex(v3); t = pVertexData->GetTexCoordIndex(v3);
+ f.c = ( p >= 0 ) ? vi + p : 0; f.nc = ( n >= 0 ) ? ni + n : 0; f.tc = ( t >= 0 ) ? ti + t : 0;
+
+ Assert( f.a <= (unsigned long)g_numverts && f.b <= (unsigned long)g_numverts && f.c <= (unsigned long)g_numverts );
+ Assert( f.na <= (unsigned long)g_numnormals && f.nb <= (unsigned long)g_numnormals && f.nc <= (unsigned long)g_numnormals );
+ Assert( f.ta <= (unsigned long)g_numtexcoords && f.tb <= (unsigned long)g_numtexcoords && f.tc <= (unsigned long)g_numtexcoords );
+
+ Assert( g_numfaces < MAXSTUDIOTRIANGLES-1 );
+ if ( g_numfaces >= MAXSTUDIOTRIANGLES-1 )
+ return;
+
+ int i = g_numfaces++;
+ g_face[i] = f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads the mesh data from the DMX data
+//-----------------------------------------------------------------------------
+static bool LoadMesh( CDmeMesh *pMesh, CDmeVertexData *pBindState, const matrix3x4_t& mat, float flScale,
+ int nBoneAssign, int *pBoneRemap, s_source_t *pSource )
+{
+ pMesh->CollapseRedundantNormals( normal_blend );
+
+ // Load the vertices
+ int nStartingVertex = g_numverts;
+ int nStartingNormal = g_numnormals;
+ int nStartingTexCoord = g_numtexcoords;
+ int nStartingUniqueCount = s_UniqueVertices.Count();
+ int nStartingUniqueMapCount = s_UniqueVerticesMap.Count();
+
+ // This defines s_UniqueVertices & s_UniqueVerticesMap
+ LoadVertices( pBindState, mat, flScale, nBoneAssign, pBoneRemap, nStartingUniqueCount );
+
+ // Load the deltas
+ int nDeltaStateCount = pMesh->DeltaStateCount();
+ for ( int i = 0; i < nDeltaStateCount; ++i )
+ {
+ CDmeVertexDeltaData *pDeltaState = pMesh->GetDeltaState( i );
+ if ( !LoadDeltaState( pDeltaState, pBindState, mat, flScale, nStartingUniqueCount, nStartingUniqueMapCount ) )
+ return false;
+ }
+
+ // load the base triangles
+ int texture;
+ int material;
+ char pTextureName[MAX_PATH];
+
+ int nFaceSetCount = pMesh->FaceSetCount();
+ for ( int i = 0; i < nFaceSetCount; ++i )
+ {
+ CDmeFaceSet *pFaceSet = pMesh->GetFaceSet( i );
+ CDmeMaterial *pMaterial = pFaceSet->GetMaterial();
+
+ // Get the material name
+ Q_strncpy( pTextureName, pMaterial->GetMaterialName(), sizeof(pTextureName) );
+
+ // funky texture overrides (specified with the -t command-line argument)
+ for ( int j = 0; j < numrep; j++ )
+ {
+ if ( sourcetexture[j][0] == '\0' )
+ {
+ Q_strncpy( pTextureName, defaulttexture[j], sizeof(pTextureName) );
+ break;
+ }
+ if ( Q_stricmp( pTextureName, sourcetexture[j]) == 0 )
+ {
+ Q_strncpy( pTextureName, defaulttexture[j], sizeof(pTextureName) );
+ break;
+ }
+ }
+
+ // skip all faces with the null texture on them.
+ char pPathNoExt[MAX_PATH];
+ Q_StripExtension( pTextureName, pPathNoExt, sizeof(pPathNoExt) );
+ if ( !Q_stricmp( pPathNoExt, "null" ) )
+ continue;
+
+ texture = LookupTexture( pTextureName, true );
+ pSource->texmap[texture] = texture; // hack, make it 1:1
+ material = UseTextureAsMaterial( texture );
+
+ // prepare indices
+ int nFirstIndex = 0;
+ int nIndexCount = pFaceSet->NumIndices();
+ while ( nFirstIndex < nIndexCount )
+ {
+ int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
+ if ( nVertexCount >= 3 )
+ {
+ int nOutCount = (nVertexCount-2) * 3;
+ int *pIndices = (int*)_alloca( nOutCount * sizeof(int) );
+ pMesh->ComputeTriangulatedIndices( pBindState, pFaceSet, nFirstIndex, pIndices, nOutCount );
+ for ( int ii = 0; ii < nOutCount; ii +=3 )
+ {
+ ParseFaceData( pBindState, material, pIndices[ii], pIndices[ii+2], pIndices[ii+1], nStartingVertex, nStartingNormal, nStartingTexCoord );
+ }
+ }
+ nFirstIndex += nVertexCount + 1;
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Method used to add mesh data
+//-----------------------------------------------------------------------------
+struct LoadMeshInfo_t
+{
+ s_source_t *m_pSource;
+ CDmeModel *m_pModel;
+ float m_flScale;
+ int *m_pBoneRemap;
+ matrix3x4_t m_pBindPose[MAXSTUDIOSRCBONES];
+};
+
+static bool LoadMeshes( const LoadMeshInfo_t &info, CDmeDag *pDag, const matrix3x4_t &parentToBindPose, int nBoneAssign )
+{
+ // We want to create an aggregate matrix transforming from this dag to its closest
+ // parent which actually is an animated joint. This is done so we can autoskin
+ // meshes to their closest parents if they have not been skinned.
+ matrix3x4_t dagToBindPose;
+ CDmeTransform *pDagTransform = pDag->GetTransform();
+ int nFoundIndex = info.m_pModel->GetJointTransformIndex( pDagTransform );
+
+ // Update autoskin to autoskin to non-DmeJoint's if they are children of the DmeModel (i.e. they have no parent bone)
+ if ( nFoundIndex >= 0 )
+ {
+ if ( pDag == info.m_pModel || CastElement< CDmeJoint >( pDag ) )
+ {
+ nBoneAssign = nFoundIndex;
+ }
+ else
+ {
+ for ( int i = 0; i < info.m_pModel->GetChildCount(); ++i )
+ {
+ if ( info.m_pModel->GetChild( i ) == pDag )
+ {
+ nBoneAssign = nFoundIndex;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( nFoundIndex >= 0 )
+ {
+ ConcatTransforms( parentToBindPose, info.m_pBindPose[nFoundIndex], dagToBindPose );
+ }
+ else
+ {
+ // NOTE: This isn't particularly kosher; we're using the current pose instead of the bind pose
+ // because there's no transform in the bind pose
+ matrix3x4_t dagToParent;
+ pDagTransform->GetTransform( dagToParent );
+ ConcatTransforms( parentToBindPose, dagToParent, dagToBindPose );
+ }
+
+ CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
+ if ( pMesh )
+ {
+ CDmeVertexData *pBindState = pMesh->FindBaseState( "bind" );
+ if ( !pBindState )
+ return false;
+
+ if ( !LoadMesh( pMesh, pBindState, dagToBindPose, info.m_flScale, nBoneAssign, info.m_pBoneRemap, info.m_pSource ) )
+ return false;
+ }
+
+ int nCount = pDag->GetChildCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeDag *pChild = pDag->GetChild( i );
+ if ( !LoadMeshes( info, pChild, dagToBindPose, nBoneAssign ) )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Method used to add mesh data
+//-----------------------------------------------------------------------------
+static bool LoadMeshes( CDmeModel *pModel, float flScale, int *pBoneRemap, s_source_t *pSource )
+{
+ matrix3x4_t mat;
+ SetIdentityMatrix( mat );
+
+ LoadMeshInfo_t info;
+ info.m_pModel = pModel;
+ info.m_flScale = flScale;
+ info.m_pBoneRemap = pBoneRemap;
+ info.m_pSource = pSource;
+
+ CDmeTransformList *pBindPose = pModel->FindBaseState( "bind" );
+ int nCount = pBindPose ? pBindPose->GetTransformCount() : pModel->GetJointTransformCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeTransform *pTransform = pBindPose ? pBindPose->GetTransform(i) : pModel->GetJointTransform(i);
+
+ matrix3x4_t jointTransform;
+ pTransform->GetTransform( info.m_pBindPose[i] );
+ }
+
+ int nChildCount = pModel->GetChildCount();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeDag *pChild = pModel->GetChild( i );
+ if ( !LoadMeshes( info, pChild, mat, -1 ) )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Builds s_vertanim_ts
+//-----------------------------------------------------------------------------
+static void BuildVertexAnimations( s_source_t *pSource )
+{
+ int nCount = s_DeltaStates.Count();
+ if ( nCount == 0 )
+ return;
+
+ Assert( s_Speed.Count() > 0 );
+ Assert( s_Balance.Count() > 0 );
+
+ Assert( s_UniqueVertices.Count() == numvlist );
+ s_vertanim_t *pVertAnim = (s_vertanim_t *)_alloca( numvlist * sizeof( s_vertanim_t ) );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ DeltaState_t &state = s_DeltaStates[i];
+
+ s_sourceanim_t *pSourceAnim = FindOrAddSourceAnim( pSource, state.m_Name );
+ pSourceAnim->numframes = 1;
+ pSourceAnim->startframe = 0;
+ pSourceAnim->endframe = 0;
+ pSourceAnim->newStyleVertexAnimations = true;
+
+ // Traverse the linked list of unique vertex indices j that has a delta
+ int nVertAnimCount = 0;
+ for ( int j = state.m_nFirstDelta; j >= 0; j = state.m_DeltaIndices[j].m_nNextDelta )
+ {
+ // The Delta Indices array is a parallel array to s_UniqueVertices
+ // j is used to index into both
+ DeltaIndex_t &delta = state.m_DeltaIndices[j];
+ Assert( delta.m_nPositionIndex >= 0 || delta.m_nNormalIndex >= 0 || delta.m_nWrinkleIndex >= 0 );
+
+ VertIndices_t &uniqueVert = s_UniqueVertices[j];
+
+ const v_unify_t *pList = v_list[uniqueVert.v];
+ for( ; pList; pList = pList->next )
+ {
+ if ( pList->n != uniqueVert.n || pList->t != uniqueVert.t )
+ continue;
+
+ s_vertanim_t& vertanim = pVertAnim[nVertAnimCount++];
+ vertanim.vertex = pList - v_listdata;
+ vertanim.speed = s_Speed[ s_UniqueVertices[j].speed ];
+ vertanim.side = s_Balance[ s_UniqueVertices[j].balance ];
+ if ( delta.m_nPositionIndex >= 0 )
+ {
+ vertanim.pos = state.m_PositionDeltas[ delta.m_nPositionIndex ];
+ }
+ else
+ {
+ vertanim.pos = vec3_origin;
+ }
+ if ( delta.m_nNormalIndex >= 0 )
+ {
+ vertanim.normal = state.m_NormalDeltas[ delta.m_nNormalIndex ];
+ }
+ else
+ {
+ vertanim.normal = vec3_origin;
+ }
+
+ if ( delta.m_nWrinkleIndex >= 0 )
+ {
+ vertanim.wrinkle = state.m_WrinkleDeltas[ delta.m_nWrinkleIndex ];
+ }
+ else
+ {
+ vertanim.wrinkle = 0.0f;
+ }
+ }
+ }
+ pSourceAnim->numvanims[0] = nVertAnimCount;
+ pSourceAnim->vanim[0] = (s_vertanim_t *)kalloc( nVertAnimCount, sizeof( s_vertanim_t ) );
+ memcpy( pSourceAnim->vanim[0], pVertAnim, nVertAnimCount * sizeof( s_vertanim_t ) );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the skeletal hierarchy from the game model, returns bone count
+//-----------------------------------------------------------------------------
+static bool AddDagJoint( CDmeModel *pModel, CDmeDag *pDag, s_node_t *pNodes, int nParentIndex, BoneTransformMap_t &boneMap )
+{
+ CDmeTransform *pDmeTransform = pDag->GetTransform();
+ const char *pTransformName = pDmeTransform->GetName();
+ int nJointIndex = boneMap.m_nBoneCount++;
+ if ( nJointIndex >= MAXSTUDIOSRCBONES )
+ {
+ MdlWarning( "DMX Model has too many bones [%d, max can be %d]!\n", boneMap.m_nBoneCount, MAXSTUDIOSRCBONES );
+ return false;
+ }
+
+ boneMap.m_ppTransforms[ nJointIndex ] = pDmeTransform;
+ int nFoundIndex = 0;
+ if ( pModel )
+ {
+ nFoundIndex = pModel->GetJointTransformIndex( pDmeTransform );
+ if ( nFoundIndex >= 0 )
+ {
+ boneMap.m_pBoneRemap[nFoundIndex] = nJointIndex;
+ }
+ }
+
+ Q_strncpy( pNodes[ nJointIndex ].name, pTransformName, sizeof( pNodes[ nJointIndex ].name ) );
+ pNodes[ nJointIndex ].parent = nParentIndex;
+
+ // Now deal with children
+ int nChildCount = pDag->GetChildCount();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeDag *pChild = pDag->GetChild( i );
+ if ( !pChild )
+ continue;
+
+ int nCurrentBoneCount = boneMap.m_nBoneCount;
+ if ( !AddDagJoint( pModel, pChild, pNodes, nJointIndex, boneMap ) )
+ return false;
+
+ if ( ( nCurrentBoneCount != boneMap.m_nBoneCount ) && ( nFoundIndex < 0 ) )
+ {
+ MdlWarning( "DMX Model has a joint \"%s\" which is not in its joint transform list.\n"
+ "This joint has children which are in the joint transform list, which is illegal.\n",
+ pDag->GetName() );
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point for loading the skeleton
+//-----------------------------------------------------------------------------
+static int LoadSkeleton( CDmeDag *pRoot, CDmeModel *pModel, s_node_t *pNodes, BoneTransformMap_t &map )
+{
+ // Initialize bone indices
+ map.m_nBoneCount = 0;
+ for ( int i = 0; i < MAXSTUDIOSRCBONES; ++i )
+ {
+ pNodes[i].name[0] = 0;
+ pNodes[i].parent = -1;
+ map.m_pBoneRemap[i] = -1;
+ map.m_ppTransforms[i] = NULL;
+ }
+
+ // Don't create joints for the the root dag ever.. just deal with the children
+ int nChildCount = pRoot->GetChildCount();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeDag *pChild = pRoot->GetChild( i );
+ if ( !pChild )
+ continue;
+
+ if ( !AddDagJoint( pModel, pChild, pNodes, -1, map ) )
+ return 0;
+ }
+
+ // Add a default identity bone used for autoskinning if no joints are specified
+ s_nDefaultRootNode = map.m_nBoneCount;
+ Q_strncpy( pNodes[s_nDefaultRootNode].name, "defaultRoot", sizeof( pNodes[ s_nDefaultRootNode ].name ) );
+ pNodes[s_nDefaultRootNode].parent = -1;
+
+ if ( !pModel )
+ return map.m_nBoneCount + 1;
+
+ // Look for joints listed in the transform list which aren't in the hierarchy
+ int nInitialBoneCount = pModel->GetJointTransformCount();
+ for ( int i = 0; i < nInitialBoneCount; ++i )
+ {
+ int nIndex = map.m_pBoneRemap[i];
+ if ( nIndex < 0 )
+ {
+ map.m_pBoneRemap[i] = map.m_nBoneCount++;
+ nIndex = map.m_pBoneRemap[i];
+ }
+ if ( pNodes[nIndex].name[0] == 0 )
+ {
+ CDmeTransform *pTransform = pModel->GetJointTransform( i );
+ Q_strncpy( pNodes[ nIndex ].name, pTransform->GetName(), sizeof( pNodes[ nIndex ].name ) );
+ MdlWarning( "Joint %s specified in the joint transform list but doesn't appear in the dag hierarchy!\n", pTransform->GetName() );
+ }
+ }
+ return map.m_nBoneCount + 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the skeletal hierarchy from the game model, returns bone count
+//-----------------------------------------------------------------------------
+static void LoadAttachments( CDmeDag *pRoot, CDmeDag *pDag, s_source_t *pSource )
+{
+ CDmeAttachment *pAttachment = CastElement< CDmeAttachment >( pDag->GetShape() );
+ if ( pAttachment && ( pDag != pRoot ) )
+ {
+ int i = pSource->m_Attachments.AddToTail();
+ s_attachment_t &attachment = pSource->m_Attachments[i];
+ memset( &attachment, 0, sizeof(s_attachment_t) );
+ Q_strncpy( attachment.name, pAttachment->GetName(), sizeof( attachment.name ) );
+ Q_strncpy( attachment.bonename, pDag->GetName(), sizeof( attachment.bonename ) );
+ SetIdentityMatrix( attachment.local );
+ if ( pAttachment->m_bIsRigid )
+ {
+ attachment.type |= IS_RIGID;
+ }
+ if ( pAttachment->m_bIsWorldAligned )
+ {
+ attachment.flags |= ATTACHMENT_FLAG_WORLD_ALIGN;
+ }
+ }
+
+ // Don't create joints for the the root dag ever.. just deal with the children
+ int nChildCount = pDag->GetChildCount();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeDag *pChild = pDag->GetChild( i );
+ if ( !pChild )
+ continue;
+
+ LoadAttachments( pRoot, pChild, pSource );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the bind pose
+//-----------------------------------------------------------------------------
+static void LoadBindPose( CDmeModel *pModel, float flScale, int *pBoneRemap, s_source_t *pSource )
+{
+ s_sourceanim_t *pSourceAnim = FindOrAddSourceAnim( pSource, "BindPose" );
+ pSourceAnim->startframe = 0;
+ pSourceAnim->endframe = 0;
+ pSourceAnim->numframes = 1;
+
+ // Default all transforms to identity
+ pSourceAnim->rawanim[0] = (s_bone_t *)kalloc( pSource->numbones, sizeof(s_bone_t) );
+ for ( int i = 0; i < pSource->numbones; ++i )
+ {
+ pSourceAnim->rawanim[0][i].pos.Init();
+ pSourceAnim->rawanim[0][i].rot.Init();
+ }
+
+ // Override those bones in the bind pose with the real values
+ // NOTE: This means that bones that are not in the bind pose are set to identity!
+ // Is this correct? I think it shouldn't matter, but we may need to fix this.
+ CDmeTransformList *pBindPose = pModel->FindBaseState( "bind" );
+ int nCount = pBindPose ? pBindPose->GetTransformCount() : pModel->GetJointTransformCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeTransform *pTransform = pBindPose ? pBindPose->GetTransform(i) : pModel->GetJointTransform(i);
+
+ matrix3x4_t jointTransform;
+ pTransform->GetTransform( jointTransform );
+
+ int nActualBoneIndex = pBoneRemap[i];
+ s_bone_t &bone = pSourceAnim->rawanim[0][nActualBoneIndex];
+ MatrixAngles( jointTransform, bone.rot, bone.pos );
+ bone.pos *= flScale;
+ }
+
+ Build_Reference( pSource, "BindPose" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point for loading DMX files
+//-----------------------------------------------------------------------------
+static void PrepareChannels( CDmeChannelsClip *pAnimation )
+{
+ int nChannelsCount = pAnimation->m_Channels.Count();
+ for ( int i = 0; i < nChannelsCount; ++i )
+ {
+ pAnimation->m_Channels[i]->SetMode( CM_PLAY );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Update channels so they are in position for the next frame
+//-----------------------------------------------------------------------------
+static void UpdateChannels( CDmeChannelsClip *pAnimation, DmeTime_t clipTime )
+{
+ int nChannelsCount = pAnimation->m_Channels.Count();
+ DmeTime_t channelTime = pAnimation->ToChildMediaTime( clipTime );
+ CUtlVector< IDmeOperator* > operators( 0, nChannelsCount );
+ for ( int i = 0; i < nChannelsCount; ++i )
+ {
+ pAnimation->m_Channels[i]->SetCurrentTime( channelTime );
+ operators.AddToTail( pAnimation->m_Channels[i] );
+ }
+
+ // Recompute the position of the joints
+ {
+ CDisableUndoScopeGuard guard;
+ g_pDmElementFramework->SetOperators( operators );
+ g_pDmElementFramework->Operate( true );
+ }
+ g_pDmElementFramework->BeginEdit();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize the pose for this frame
+//-----------------------------------------------------------------------------
+static void ComputeFramePose( s_sourceanim_t *pSourceAnim, int nFrame, float flScale, BoneTransformMap_t& boneMap )
+{
+ pSourceAnim->rawanim[nFrame] = (s_bone_t *)kalloc( boneMap.m_nBoneCount, sizeof( s_bone_t ) );
+
+ for ( int i = 0; i < boneMap.m_nBoneCount; ++i )
+ {
+ matrix3x4_t jointTransform;
+ boneMap.m_ppTransforms[i]->GetTransform( jointTransform );
+ MatrixAngles( jointTransform, pSourceAnim->rawanim[nFrame][i].rot, pSourceAnim->rawanim[nFrame][i].pos );
+ pSourceAnim->rawanim[nFrame][i].pos *= flScale;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point for loading animations
+//-----------------------------------------------------------------------------
+static void LoadAnimations( s_source_t *pSource, CDmeAnimationList *pAnimationList, float flScale, BoneTransformMap_t &boneMap )
+{
+ int nAnimationCount = pAnimationList->GetAnimationCount();
+ for ( int i = 0; i < nAnimationCount; ++i )
+ {
+ CDmeChannelsClip *pAnimation = pAnimationList->GetAnimation( i );
+
+ if ( !Q_stricmp( pAnimationList->GetName(), "BindPose" ) )
+ {
+ MdlError( "Error: Cannot use \"BindPose\" as an animation name!\n" );
+ break;
+ }
+
+ s_sourceanim_t *pSourceAnim = FindOrAddSourceAnim( pSource, pAnimation->GetName() );
+
+ DmeTime_t nStartTime = pAnimation->GetStartTime();
+ DmeTime_t nEndTime = pAnimation->GetEndTime();
+ int nFrameRateVal = pAnimation->GetValue<int>( "frameRate" );
+ if ( nFrameRateVal <= 0 )
+ {
+ nFrameRateVal = 30;
+ }
+ DmeFramerate_t nFrameRate = nFrameRateVal;
+ pSourceAnim->startframe = nStartTime.CurrentFrame( nFrameRate );
+ pSourceAnim->endframe = nEndTime.CurrentFrame( nFrameRate );
+ pSourceAnim->numframes = pSourceAnim->endframe - pSourceAnim->startframe + 1;
+
+ // Prepare channels for playback
+ PrepareChannels( pAnimation );
+
+ float flOOFrameRate = 1.0f / (float)nFrameRateVal;
+ DmeTime_t nTime = nStartTime;
+ int nFrame = 0;
+ while ( nFrame < pSourceAnim->numframes )
+ {
+ int nSecond = nFrame / nFrameRateVal;
+ int nFraction = nFrame - nSecond * nFrameRateVal;
+ DmeTime_t t = nStartTime + DmeTime_t( nSecond * 10000 ) + DmeTime_t( (float)nFraction * flOOFrameRate );
+
+ // Update the current time
+ UpdateChannels( pAnimation, t );
+
+ // Initialize the pose for this frame
+ ComputeFramePose( pSourceAnim, nFrame, flScale, boneMap );
+
+ ++nFrame;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the skeletal hierarchy from the game model, returns bone count
+//-----------------------------------------------------------------------------
+static void AddFlexKeys( CDmeDag *pRoot, CDmeDag *pDag, CDmeCombinationOperator *pComboOp, s_source_t *pSource )
+{
+ CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
+ if ( pMesh && ( pDag != pRoot ) )
+ {
+ int nDeltaStateCount = pMesh->DeltaStateCount();
+ for ( int i = 0; i < nDeltaStateCount; ++i )
+ {
+ CDmeVertexDeltaData *pDeltaState = pMesh->GetDeltaState( i );
+ AddFlexKey( pSource, pComboOp, pDeltaState->GetName() );
+ }
+ }
+
+ // Don't create joints for the the root dag ever.. just deal with the children
+ int nChildCount = pDag->GetChildCount();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeDag *pChild = pDag->GetChild( i );
+ if ( !pChild )
+ continue;
+
+ AddFlexKeys( pRoot, pChild, pComboOp, pSource );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Loads all auxilliary model info:
+//
+// * Determine original source files used to generate
+// the current DMX file and schedule them for processing.
+//-----------------------------------------------------------------------------
+void LoadModelInfo( CDmElement *pRoot, char const *pFullPath )
+{
+ // Determine original source files and schedule them for processing
+ if ( CDmElement *pMakeFile = pRoot->GetValueElement< CDmElement >( "makefile" ) )
+ {
+ if ( CDmAttribute *pSources = pMakeFile->GetAttribute( "sources" ) )
+ {
+ CDmrElementArray< CDmElement > arrSources( pSources );
+ for ( int kk = 0; kk < arrSources.Count(); ++ kk )
+ {
+ if ( CDmElement *pModelSource = arrSources.Element( kk ) )
+ {
+ if ( char const *szName = pModelSource->GetName() )
+ {
+ ProcessOriginalContentFile( pFullPath, szName );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point for loading DMX files
+//-----------------------------------------------------------------------------
+int Load_DMX( s_source_t *pSource )
+{
+ DmFileId_t fileId;
+ s_DeltaStates.RemoveAll();
+ s_Balance.RemoveAll();
+ s_Speed.RemoveAll();
+ s_UniqueVertices.RemoveAll();
+ s_UniqueVerticesMap.RemoveAll();
+
+ // use the full search tree, including mod hierarchy to find the file
+ char pFullPath[MAX_PATH];
+ if ( !GetGlobalFilePath( pSource->filename, pFullPath, sizeof(pFullPath) ) )
+ return 0;
+
+ // When reading, keep the CRLF; this will make ReadFile read it in binary format
+ // and also append a couple 0s to the end of the buffer.
+ CDmElement *pRoot;
+ if ( g_pDataModel->RestoreFromFile( pFullPath, NULL, NULL, &pRoot ) == DMFILEID_INVALID )
+ return 0;
+
+ if ( !g_quiet )
+ {
+ Msg( "DMX Model %s\n", pFullPath );
+ }
+
+ // Load model info
+ LoadModelInfo( pRoot, pFullPath );
+
+ // Extract out the skeleton
+ CDmeDag *pSkeleton = pRoot->GetValueElement< CDmeDag >( "skeleton" );
+ CDmeModel *pModel = pRoot->GetValueElement< CDmeModel >( "model" );
+ CDmeCombinationOperator *pCombinationOperator = pRoot->GetValueElement< CDmeCombinationOperator >( "combinationOperator" );
+ if ( !pSkeleton )
+ goto dmxError;
+
+ // BoneRemap[bone index in file] == bone index in studiomdl
+ BoneTransformMap_t boneMap;
+ pSource->numbones = LoadSkeleton( pSkeleton, pModel, pSource->localBone, boneMap );
+ if ( pSource->numbones == 0 )
+ goto dmxError;
+
+ LoadAttachments( pSkeleton, pSkeleton, pSource );
+
+ g_numfaces = 0;
+ if ( pModel )
+ {
+ if ( pCombinationOperator )
+ {
+ pCombinationOperator->GenerateWrinkleDeltas( false );
+ }
+ LoadBindPose( pModel, g_currentscale, boneMap.m_pBoneRemap, pSource );
+ if ( !LoadMeshes( pModel, g_currentscale, boneMap.m_pBoneRemap, pSource ) )
+ goto dmxError;
+
+ UnifyIndices( pSource );
+ BuildVertexAnimations( pSource );
+ BuildIndividualMeshes( pSource );
+ }
+
+ if ( pCombinationOperator )
+ {
+ AddFlexKeys( pModel, pModel, pCombinationOperator, pSource );
+ AddCombination( pSource, pCombinationOperator );
+ }
+
+ CDmeAnimationList *pAnimationList = pRoot->GetValueElement< CDmeAnimationList >( "animationList" );
+ if ( pAnimationList )
+ {
+ LoadAnimations( pSource, pAnimationList, g_currentscale, boneMap );
+ }
+
+ fileId = pRoot->GetFileId();
+ g_pDataModel->RemoveFileId( fileId );
+ return 1;
+
+dmxError:
+ fileId = pRoot->GetFileId();
+ g_pDataModel->RemoveFileId( fileId );
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+