Counter Strike : Global Offensive Source Code
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.

487 lines
16 KiB

  1. //=========== Copyright � Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Mesh class dmx loading functions
  4. //
  5. //===========================================================================//
  6. #include "movieobjects/dmemodel.h"
  7. #include "movieobjects/dmemesh.h"
  8. #include "movieobjects/dmefaceset.h"
  9. #include "movieobjects/dmematerial.h"
  10. #include "movieobjects/dmeclip.h"
  11. #include "movieobjects/dmechannel.h"
  12. #include "movieobjects/dmeattachment.h"
  13. #include "movieobjects/dmeanimationlist.h"
  14. #include "movieobjects/dmecombinationoperator.h"
  15. #include "mdlobjects/dmebbox.h"
  16. #include "mdlobjects/dmelod.h"
  17. #include "mdlobjects/dmelodlist.h"
  18. #include "mdlobjects/dmebodygroup.h"
  19. #include "mdlobjects/dmebodygrouplist.h"
  20. #include "mdlobjects/dmehitbox.h"
  21. #include "mdlobjects/dmehitboxset.h"
  22. #include "mdlobjects/dmehitboxsetlist.h"
  23. #include "mdlobjects/dmesequence.h"
  24. #include "mdlobjects/dmesequencelist.h"
  25. #include "mdlobjects/dmecollisionmodel.h"
  26. #include "mdlobjects/dmecollisionjoints.h"
  27. #include "mdlobjects/dmeincludemodellist.h"
  28. #include "mdlobjects/dmedefinebone.h"
  29. #include "mdlobjects/dmedefinebonelist.h"
  30. #include "mdlobjects/dmematerialgroup.h"
  31. #include "mdlobjects/dmematerialgrouplist.h"
  32. #include "mdlobjects/dmeeyeball.h"
  33. #include "mdlobjects/dmeeyeballglobals.h"
  34. #include "mdlobjects/dmeboneweight.h"
  35. #include "mdlobjects/dmebonemask.h"
  36. #include "mdlobjects/dmebonemasklist.h"
  37. #include "mdlobjects/dmeik.h"
  38. #include "mdlobjects/dmeanimcmd.h"
  39. #include "mdlobjects/dmemotioncontrol.h"
  40. #include "mdlobjects/dmeposeparameter.h"
  41. #include "mdlobjects/dmeposeparameterlist.h"
  42. #include "mdlobjects/dmeanimblocksize.h"
  43. #include "dmeutils/dmmeshutils.h"
  44. #include "meshutils/mesh.h"
  45. #define MAX_BIND_POSE_BONES 256
  46. struct LoadMeshInfo_t
  47. {
  48. CDmeModel *m_pModel;
  49. float m_flScale;
  50. int *m_pBoneRemap;
  51. matrix3x4_t m_pBindPose[MAX_BIND_POSE_BONES];
  52. };
  53. class CDMXLoader
  54. {
  55. public:
  56. bool LoadVertices( CDmeDag *pDmeDag, CDmeVertexData *pBindState, const matrix3x4_t& mat, float flScale, int nBoneAssign, int *pBoneRemap, int nStartingUniqueCount );
  57. bool LoadMesh( CDmeDag *pDmeDag, CDmeMesh *pMesh, CDmeVertexData *pBindState, const matrix3x4_t& mat, float flScale,
  58. int nBoneAssign, int *pBoneRemap );
  59. bool LoadMesh( CDmeMesh *pMesh, CDmeDag *pDag, const matrix3x4_t &dagToBindPose = g_MatrixIdentity, float flScale = 1.0f, int nBoneAssign = -1, int *pBoneRemap = NULL, const CUtlVector< CUtlString > *pDeltaNames = NULL );
  60. bool LoadMeshes( const LoadMeshInfo_t &info, CDmeDag *pDag, const matrix3x4_t &parentToBindPose, int nBoneAssign );
  61. bool LoadMeshes( CDmeModel *pModel, float flScale, int *pBoneRemap = NULL );
  62. bool LoadMaterialGroups( CDmeMaterialGroupList *pMaterialGroupList );
  63. bool LoadDMX( const char *pDMXFile );
  64. CUtlVector<CMesh*> &GetOutputMeshes() { return m_outputMeshes; }
  65. CUtlVector< CDmeDag* > &GetOutputDmeDags() { return m_OutputDmeDags; }
  66. private:
  67. CUtlVector<CMesh*> m_outputMeshes;
  68. CUtlVector< CDmeDag* > m_OutputDmeDags; // DAG per mesh, when not collapsing meshes
  69. };
  70. void GenerateAttributesFromVertexData( CMeshVertexAttribute *pAttributes, int &nAttributes, int &nVertexStrideFloats, CDmeVertexData *pBindState )
  71. {
  72. const CUtlVector<Vector> &positions = pBindState->GetPositionData( );
  73. const CUtlVector<Vector> &normals = pBindState->GetNormalData( );
  74. const CUtlVector<Vector2D> &texcoords = pBindState->GetTextureCoordData( );
  75. const CUtlVector<Vector4D> &tangents = pBindState->GetTangentData( );
  76. const CUtlVector<Color> &colors = pBindState->GetColorData();
  77. int nLocalAttributes = 0;
  78. nVertexStrideFloats = 0;
  79. if ( positions.Count() )
  80. {
  81. pAttributes[ nLocalAttributes ].m_nOffsetFloats = nVertexStrideFloats;
  82. pAttributes[ nLocalAttributes ].m_nType = VERTEX_ELEMENT_POSITION;
  83. nLocalAttributes ++;
  84. nVertexStrideFloats += 3;
  85. if ( nLocalAttributes > nAttributes )
  86. goto endGetAttributes;
  87. }
  88. if ( normals.Count() )
  89. {
  90. pAttributes[ nLocalAttributes ].m_nOffsetFloats = nVertexStrideFloats;
  91. pAttributes[ nLocalAttributes ].m_nType = VERTEX_ELEMENT_NORMAL;
  92. nLocalAttributes ++;
  93. nVertexStrideFloats += 3;
  94. if ( nLocalAttributes > nAttributes )
  95. goto endGetAttributes;
  96. }
  97. if ( texcoords.Count() )
  98. {
  99. pAttributes[ nLocalAttributes ].m_nOffsetFloats = nVertexStrideFloats;
  100. pAttributes[ nLocalAttributes ].m_nType = VERTEX_ELEMENT_TEXCOORD2D_0;
  101. nLocalAttributes ++;
  102. nVertexStrideFloats += 2;
  103. if ( nLocalAttributes > nAttributes )
  104. goto endGetAttributes;
  105. }
  106. if ( tangents.Count() )
  107. {
  108. pAttributes[ nLocalAttributes ].m_nOffsetFloats = nVertexStrideFloats;
  109. pAttributes[ nLocalAttributes ].m_nType = VERTEX_ELEMENT_TANGENT_WITH_FLIP;
  110. nLocalAttributes ++;
  111. nVertexStrideFloats += 4;
  112. if ( nLocalAttributes > nAttributes )
  113. goto endGetAttributes;
  114. }
  115. if ( colors.Count() )
  116. {
  117. pAttributes[ nLocalAttributes ].m_nOffsetFloats = nVertexStrideFloats;
  118. pAttributes[ nLocalAttributes ].m_nType = VERTEX_ELEMENT_COLOR;
  119. nLocalAttributes ++;
  120. nVertexStrideFloats += 1;
  121. if ( nLocalAttributes > nAttributes )
  122. goto endGetAttributes;
  123. }
  124. endGetAttributes:
  125. nAttributes = nLocalAttributes;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Convert a single CDmeMesh to a CMesh
  129. //-----------------------------------------------------------------------------
  130. bool ConvertMeshFromDMX( CMesh *pMeshOut, CDmeMesh *pDmeMesh )
  131. {
  132. if ( !pMeshOut || !pDmeMesh )
  133. return false;
  134. CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState();
  135. if ( !pDmeBindBaseState )
  136. return false;
  137. CDmeDag *pDmeDag = pDmeMesh->GetParent();
  138. if ( !pDmeDag )
  139. return false;
  140. matrix3x4_t mShapeToWorld;
  141. pDmeDag->GetShapeToWorldTransform( mShapeToWorld );
  142. CDMXLoader dmxLoader;
  143. if ( dmxLoader.LoadMesh( pDmeDag, pDmeMesh, pDmeBindBaseState, mShapeToWorld, 1.0f, 0, NULL ) )
  144. {
  145. CUtlVector< CMesh * > &outputMeshes = dmxLoader.GetOutputMeshes();
  146. if ( outputMeshes.Count() <= 0 )
  147. return false;
  148. DuplicateMesh( pMeshOut, *outputMeshes[0] );
  149. return true;
  150. }
  151. return false;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Reads the mesh data from the DMX data
  155. //-----------------------------------------------------------------------------
  156. bool CDMXLoader::LoadMesh( CDmeDag *pDmeDag, CDmeMesh *pMesh, CDmeVertexData *pBindState, const matrix3x4_t& mat, float flScale,
  157. int nBoneAssign, int *pBoneRemap )
  158. {
  159. matrix3x4_t normalMat;
  160. MatrixInverseTranspose( mat, normalMat );
  161. const CUtlVector<Vector> &positions = pBindState->GetPositionData( );
  162. const CUtlVector<Vector> &normals = pBindState->GetNormalData( );
  163. const CUtlVector<Vector2D> &texcoords = pBindState->GetTextureCoordData( );
  164. const CUtlVector<Vector4D> &tangents = pBindState->GetTangentData( );
  165. const CUtlVector<Color> &colors = pBindState->GetColorData();
  166. bool bHasPosition = ( positions.Count() > 0 );
  167. bool bHasNormal = ( normals.Count() > 0 );
  168. bool bHasTexcoord = ( texcoords.Count() > 0 );
  169. bool bHasTangent = ( tangents.Count() > 0 );
  170. bool bHasColor = ( colors.Count() > 0 );
  171. bool bFlipVCoordinate = pBindState->IsVCoordinateFlipped();
  172. int nAttributes = 32;
  173. int nVertexStrideFloats = 0;
  174. CMeshVertexAttribute attributes[ 32 ];
  175. GenerateAttributesFromVertexData( attributes, nAttributes, nVertexStrideFloats, pBindState );
  176. // Create a mesh per face set
  177. int nFaceSetCount = pMesh->FaceSetCount();
  178. for ( int i = 0; i < nFaceSetCount; ++i )
  179. {
  180. CDmeFaceSet *pFaceSet = pMesh->GetFaceSet( i );
  181. CDmeMaterial *pMaterial = pFaceSet->GetMaterial();
  182. int nIndexCount = pFaceSet->NumIndices();
  183. int nTrueIndexCount = 0;
  184. int nFirstIndex = 0;
  185. while( nFirstIndex < nIndexCount )
  186. {
  187. int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
  188. int nOutCount = ( nVertexCount - 2 ) * 3;
  189. nTrueIndexCount += nOutCount;
  190. nFirstIndex += nVertexCount + 1;
  191. }
  192. // Each face set is an individual mesh for now
  193. CMesh *pUtilMesh = new CMesh();
  194. // Allocate space for VB/IB/Attrib
  195. pUtilMesh->AllocateMesh( nTrueIndexCount, nTrueIndexCount, nVertexStrideFloats, attributes, nAttributes );
  196. uint32 *pUtilIndices = pUtilMesh->m_pIndices;
  197. int nUtilIndices = 0;
  198. // Set material name
  199. pUtilMesh->m_materialName = pMaterial->GetMaterialName();
  200. // Set vertices and indices
  201. nFirstIndex = 0;
  202. while( nFirstIndex < nIndexCount )
  203. {
  204. int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
  205. if ( nVertexCount >= 3 )
  206. {
  207. int nOutCount = ( nVertexCount - 2 ) * 3;
  208. int pIndices[ 128 ];// = ( int* )_alloca( nOutCount * sizeof( uint32 ) );
  209. Assert( nOutCount <= 128 );
  210. pMesh->ComputeTriangulatedIndices( pBindState, pFaceSet, nFirstIndex, pIndices, nOutCount );
  211. for ( int i=0; i<nOutCount; ++i )
  212. {
  213. float *pUtilVertex = pUtilMesh->GetVertex( nUtilIndices );
  214. int nVertexOffset = 0;
  215. int iVertIndex = pIndices[ i ];
  216. if ( bHasPosition )
  217. {
  218. int nI = pBindState->GetPositionIndex( iVertIndex );
  219. Vector vTrans;
  220. VectorTransform( positions[ nI ], mat, vTrans );
  221. vTrans *= flScale;
  222. Q_memcpy( pUtilVertex + nVertexOffset, &vTrans, sizeof( Vector ) );
  223. nVertexOffset += 3;
  224. }
  225. if ( bHasNormal )
  226. {
  227. int nI = pBindState->GetNormalIndex( iVertIndex );
  228. Vector vTrans;
  229. VectorRotate( normals[ nI ], normalMat, vTrans );
  230. VectorNormalize( vTrans );
  231. Q_memcpy( pUtilVertex + nVertexOffset, &vTrans, sizeof( Vector ) );
  232. nVertexOffset += 3;
  233. }
  234. if ( bHasTexcoord )
  235. {
  236. int nI = pBindState->GetTexCoordIndex( iVertIndex );
  237. Vector2D vTrans;
  238. vTrans = texcoords[ nI ];
  239. if ( bFlipVCoordinate )
  240. {
  241. vTrans.y = 1.0f - vTrans.y;
  242. }
  243. Q_memcpy( pUtilVertex + nVertexOffset, &vTrans, sizeof( Vector2D ) );
  244. nVertexOffset += 2;
  245. }
  246. if ( bHasTangent )
  247. {
  248. int nI = pBindState->GetTangentIndex( iVertIndex );
  249. Vector vTrans;
  250. VectorRotate( tangents[ nI ].AsVector3D(), normalMat, vTrans );
  251. VectorNormalize( vTrans );
  252. Vector4D vTrans4D( vTrans.x, vTrans.y, vTrans.z, tangents[ nI ].w );
  253. Q_memcpy( pUtilVertex + nVertexOffset, &vTrans4D, sizeof( Vector4D ) );
  254. nVertexOffset += 4;
  255. }
  256. if ( bHasColor )
  257. {
  258. int nI = pBindState->GetColorIndex( iVertIndex );
  259. Q_memcpy( pUtilVertex + nVertexOffset, &colors[ nI ], sizeof( uint32 ) );
  260. nVertexOffset += 1;
  261. }
  262. pUtilIndices[ nUtilIndices ] = nUtilIndices;
  263. nUtilIndices ++;
  264. }
  265. }
  266. nFirstIndex += nVertexCount + 1; // -1 between faces, to skip over it
  267. }
  268. // Clean and weld the mesh
  269. float flEpsilon = 1e-6;
  270. float *pEpsilons = new float[ pUtilMesh->m_nVertexStrideFloats ];
  271. for ( int e=0; e<pUtilMesh->m_nVertexStrideFloats; ++e )
  272. {
  273. pEpsilons[ e ] = flEpsilon;
  274. }
  275. CMesh tempMesh;
  276. WeldVertices( &tempMesh, *pUtilMesh, pEpsilons, pUtilMesh->m_nVertexStrideFloats );
  277. delete []pEpsilons;
  278. pUtilMesh->FreeAllMemory();
  279. CleanMesh( pUtilMesh, tempMesh );
  280. tempMesh.FreeAllMemory();
  281. m_OutputDmeDags.AddToTail( pDmeDag );
  282. m_outputMeshes.AddToTail( pUtilMesh );
  283. }
  284. return true;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Method used to add mesh data
  288. //-----------------------------------------------------------------------------
  289. bool CDMXLoader::LoadMeshes( const LoadMeshInfo_t &info, CDmeDag *pDag, const matrix3x4_t &parentToBindPose, int nBoneAssign )
  290. {
  291. // We want to create an aggregate matrix transforming from this dag to its closest
  292. // parent which actually is an animated joint. This is done so we can autoskin
  293. // meshes to their closest parents if they have not been skinned.
  294. matrix3x4_t dagToBindPose;
  295. int nFoundIndex = info.m_pModel->GetJointIndex( pDag );
  296. if ( nFoundIndex >= 0 /* && ( pDag == info.m_pModel || CastElement< CDmeJoint >( pDag ) ) */ )
  297. {
  298. nBoneAssign = nFoundIndex;
  299. }
  300. if ( nFoundIndex >= 0 )
  301. {
  302. ConcatTransforms( parentToBindPose, info.m_pBindPose[nFoundIndex], dagToBindPose );
  303. }
  304. else
  305. {
  306. // NOTE: This isn't particularly kosher; we're using the current pose instead of the bind pose
  307. // because there's no transform in the bind pose
  308. matrix3x4_t dagToParent;
  309. pDag->GetTransform()->GetTransform( dagToParent );
  310. ConcatTransforms( parentToBindPose, dagToParent, dagToBindPose );
  311. }
  312. CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
  313. if ( pMesh )
  314. {
  315. CDmeVertexData *pBindState = pMesh->FindBaseState( "bind" );
  316. if ( !pBindState )
  317. return false;
  318. if ( !LoadMesh( pDag, pMesh, pBindState, dagToBindPose, info.m_flScale, nBoneAssign, info.m_pBoneRemap ) )
  319. return false;
  320. }
  321. int nCount = pDag->GetChildCount();
  322. for ( int i = 0; i < nCount; ++i )
  323. {
  324. CDmeDag *pChild = pDag->GetChild( i );
  325. if ( !LoadMeshes( info, pChild, dagToBindPose, nBoneAssign ) )
  326. return false;
  327. }
  328. return true;
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Method used to add mesh data
  332. //-----------------------------------------------------------------------------
  333. bool CDMXLoader::LoadMeshes( CDmeModel *pModel, float flScale, int *pBoneRemap )
  334. {
  335. matrix3x4_t mat;
  336. SetIdentityMatrix( mat );
  337. LoadMeshInfo_t info;
  338. info.m_pModel = pModel;
  339. info.m_flScale = flScale;
  340. info.m_pBoneRemap = pBoneRemap;
  341. CDmeTransformList *pBindPose = pModel->FindBaseState( "bind" );
  342. int nCount = pBindPose ? pBindPose->GetTransformCount() : pModel->GetJointCount();
  343. for ( int i = 0; i < nCount; ++i )
  344. {
  345. CDmeTransform *pTransform = pBindPose ? pBindPose->GetTransform(i) : pModel->GetJointTransform(i);
  346. matrix3x4_t jointTransform;
  347. pTransform->GetTransform( info.m_pBindPose[i] );
  348. }
  349. int nChildCount = pModel->GetChildCount();
  350. for ( int i = 0; i < nChildCount; ++i )
  351. {
  352. CDmeDag *pChild = pModel->GetChild( i );
  353. if ( !LoadMeshes( info, pChild, mat, -1 ) )
  354. return false;
  355. }
  356. return true;
  357. }
  358. bool CDMXLoader::LoadDMX( const char *pDMXFile )
  359. {
  360. bool bRet = true;
  361. DmFileId_t fileId;
  362. // When reading, keep the CRLF; this will make ReadFile read it in binary format
  363. // and also append a couple 0s to the end of the buffer.
  364. CDmElement *pRoot;
  365. if ( g_pDataModel->RestoreFromFile( pDMXFile, NULL, NULL, &pRoot ) == DMFILEID_INVALID )
  366. return false;
  367. CDmeModel *pModel = pRoot->GetValueElement< CDmeModel >( "model" );
  368. if ( !LoadMeshes( pModel, 1.0f, NULL ) )
  369. return false;
  370. fileId = pRoot->GetFileId();
  371. g_pDataModel->RemoveFileId( fileId );
  372. return bRet;
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Main entry point for loading DMX files
  376. //-----------------------------------------------------------------------------
  377. bool LoadMeshesFromDMX( CUtlVector<CMesh*> &outputMeshes, const char *pDMXFile )
  378. {
  379. CDMXLoader loader;
  380. if ( !loader.LoadDMX( pDMXFile ) )
  381. return false;
  382. CUtlVector<CMesh*> &meshList = loader.GetOutputMeshes();
  383. outputMeshes.AddVectorToTail( meshList );
  384. return true;
  385. }
  386. bool LoadMeshes( CUtlVector<CMesh*> &outputMeshes, CDmeModel *pModel, float flScale, int *pBoneRemap )
  387. {
  388. CDMXLoader loader;
  389. if ( !loader.LoadMeshes( pModel, flScale, pBoneRemap ) )
  390. return false;
  391. CUtlVector<CMesh*> &meshList = loader.GetOutputMeshes();
  392. outputMeshes.AddVectorToTail( meshList );
  393. return true;
  394. }
  395. // A stub that loads mesh without splitting position stream by tangent/uv/etc. in source2; here it just loads the mesh as usual
  396. bool LoadCollisionMeshes( CUtlVector< CMesh* > &outputMeshes, CUtlVector< CDmeDag* > &outputDags, CDmeModel *pModel, float flScale )
  397. {
  398. CDMXLoader loader;//( OUTPUT_MESH_TRIANGLE_MESH );
  399. //loader.SetFieldFilter( nFieldMask );
  400. //loader.SetCollapseDeltaMeshes( true );
  401. //loader.SetKeepPositionConnectivity( true ); // this setting will make loader not merge/split vertices we don't, thus maintaining original connectivity of the mesh
  402. //loader.SetCollapseMeshesByMaterial( false );
  403. if ( !loader.LoadMeshes( pModel, flScale ) )
  404. {
  405. return false;
  406. }
  407. outputMeshes.AddVectorToTail( loader.GetOutputMeshes() );
  408. outputDags.AddVectorToTail( loader.GetOutputDmeDags() );
  409. return true;
  410. }