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.

649 lines
25 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "mdllib_common.h"
  7. #include "mdllib_stripinfo.h"
  8. #include "mdllib_utils.h"
  9. #include "studio.h"
  10. #include "optimize.h"
  11. #include "smartptr.h"
  12. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ModelLib, "ModelLib", 0, LS_ERROR );
  13. bool CMdlLib::CreateNewStripInfo( IMdlStripInfo **ppStripInfo )
  14. {
  15. if ( !ppStripInfo )
  16. return false;
  17. if ( *ppStripInfo )
  18. {
  19. CMdlStripInfo *pMdlStripInfo = ( CMdlStripInfo * ) ( *ppStripInfo );
  20. pMdlStripInfo->Reset();
  21. return true;
  22. }
  23. *ppStripInfo = new CMdlStripInfo;
  24. return ( NULL != *ppStripInfo );
  25. }
  26. //
  27. // StripModelBuffers
  28. // The main function that strips the model buffers
  29. // mdlBuffer - mdl buffer, updated, no size change
  30. // vvdBuffer - vvd buffer, updated, size reduced
  31. // vtxBuffer - vtx buffer, updated, size reduced
  32. // ppStripInfo - if nonzero on return will be filled with the stripping info
  33. //
  34. bool CMdlLib::StripModelBuffers( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo )
  35. {
  36. DECLARE_PTR( byte, mdl, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
  37. DECLARE_PTR( byte, vvd, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  38. DECLARE_PTR( byte, vtx, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  39. int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
  40. int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
  41. //
  42. // ===================
  43. // =================== Modify the checksum and check if further processing is needed
  44. // ===================
  45. //
  46. DECLARE_PTR( studiohdr_t, mdlHdr, mdl );
  47. DECLARE_PTR( vertexFileHeader_t, vvdHdr, vvd );
  48. DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
  49. long checksumOld = mdlHdr->checksum;
  50. // Don't do anything if the checksums don't match
  51. if ( ( mdlHdr->checksum != vvdHdr->checksum ) ||
  52. ( mdlHdr->checksum != vtxHdr->checkSum ) )
  53. {
  54. Log_Msg( LOG_ModelLib, "ERROR: [StripModelBuffers] checksum mismatch!\n" );
  55. return false;
  56. }
  57. // Modify the checksums
  58. mdlHdr->checksum ^= ( mdlHdr->checksum * 123457 );
  59. vvdHdr->checksum ^= ( vvdHdr->checksum * 123457 );
  60. vtxHdr->checkSum ^= ( vtxHdr->checkSum * 123457 );
  61. long checksumNew = mdlHdr->checksum;
  62. // Allocate the model stripping info
  63. CMdlStripInfo msi;
  64. CMdlStripInfo *pMsi;
  65. if ( ppStripInfo )
  66. {
  67. if ( *ppStripInfo )
  68. {
  69. pMsi = ( CMdlStripInfo * ) ( *ppStripInfo );
  70. pMsi->Reset();
  71. }
  72. else
  73. {
  74. *ppStripInfo = pMsi = new CMdlStripInfo;
  75. }
  76. }
  77. else
  78. {
  79. pMsi = &msi;
  80. }
  81. // Set the basic stripping info settings
  82. pMsi->m_lChecksumOld = checksumOld;
  83. pMsi->m_lChecksumNew = checksumNew;
  84. //
  85. // Early outs
  86. //
  87. if ( !( mdlHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP ) )
  88. {
  89. Log_Msg( LOG_ModelLib, "No special stripping - the model is not a static prop.\n" );
  90. pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
  91. return true;
  92. }
  93. if ( vvdHdr->numLODs <= 1 )
  94. {
  95. Log_Msg( LOG_ModelLib, "No special stripping - the model has only %d lod(s).\n", vvdHdr->numLODs );
  96. pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
  97. return true;
  98. }
  99. if ( mdlHdr->numbones != 1 )
  100. {
  101. Log_Msg( LOG_ModelLib, "No special stripping - the model has %d bone(s).\n", mdlHdr->numbones );
  102. pMsi->m_eMode = CMdlStripInfo::MODE_NO_CHANGE;
  103. return true;
  104. }
  105. // Otherwise do stripping
  106. pMsi->m_eMode = CMdlStripInfo::MODE_STRIP_LOD_1N;
  107. //
  108. // ===================
  109. // =================== Build out table of LOD0 vertexes
  110. // ===================
  111. //
  112. CGrowableBitVec &mapVtxIndex = pMsi->m_vtxVerts;
  113. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  114. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  115. OptimizedModel::ModelLODHeader_t *vtxLod = CHILD_AT( vtxModel, pLOD, 0 );
  116. ITERATE_CHILDREN2( OptimizedModel::MeshHeader_t, mstudiomesh_t, vtxMesh, mdlMesh, vtxLod, mdlModel, pMesh, pMesh, numMeshes )
  117. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  118. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  119. for ( int i = 0; i < vtxStrip->numIndices; ++ i )
  120. {
  121. unsigned short *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset + i );
  122. OptimizedModel::Vertex_t *vtxVertex = CHILD_AT( vtxStripGroup, pVertex, *vtxIdx );
  123. unsigned short usIdx = vtxVertex->origMeshVertID + mdlMesh->vertexoffset;
  124. mapVtxIndex.GrowSetBit( usIdx );
  125. }
  126. ITERATE_END
  127. ITERATE_END
  128. ITERATE_END
  129. ITERATE_END
  130. ITERATE_END
  131. //
  132. // Now having the table of which vertexes to keep we will construct a remapping table
  133. //
  134. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = pMsi->m_vtxIndices;
  135. srcIndices.EnsureCapacity( mapVtxIndex.GetNumBits() );
  136. for ( int iBit = -1; ( iBit = mapVtxIndex.FindNextSetBit( iBit + 1 ) ) >= 0; )
  137. srcIndices.InsertNoSort( ( unsigned short ) ( unsigned int ) iBit );
  138. srcIndices.RedoSort(); // - doesn't do anything, just validates the vector
  139. // Now we have the following questions answered:
  140. // - for every index we know if it belongs to lod0 "mapVtxIndex.IsBitSet( oldVertIdx )"
  141. // - for every new vertex we know its old index "srcIndices[ newVertIdx ]"
  142. // - for every old vertex if it's in lod0 we know its new index "srcIndices.Find( oldVertIdx )"
  143. //
  144. // ===================
  145. // =================== Process MDL file
  146. // ===================
  147. //
  148. //
  149. // Update vertex counts
  150. //
  151. int mdlNumVerticesOld = 0;
  152. CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > &arrMdlOffsets = pMsi->m_vtxMdlOffsets;
  153. ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
  154. ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
  155. Log_Msg( LOG_ModelLib, " Stripped %d lod(s).\n", vvdHdr->numLODs - 1 );
  156. Log_Msg( LOG_ModelLib, " Stripped %d vertexes (was: %d, now: %d).\n", mdlModel->numvertices - srcIndices.Count(), mdlModel->numvertices, srcIndices.Count() );
  157. mdlNumVerticesOld = mdlModel->numvertices;
  158. mdlModel->numvertices = srcIndices.Count();
  159. mdlModel->vertexdata.pVertexData = BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart );
  160. mdlModel->vertexdata.pTangentData = BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart );
  161. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
  162. CMdlStripInfo::MdlRangeItem mdlRangeItem( mdlMesh->vertexoffset, mdlMesh->numvertices );
  163. mdlMesh->vertexdata.modelvertexdata = &mdlModel->vertexdata;
  164. mdlMesh->numvertices = srcIndices.FindLess( mdlMesh->vertexoffset + mdlMesh->numvertices );
  165. mdlMesh->vertexoffset = srcIndices.FindLess( mdlMesh->vertexoffset ) + 1;
  166. mdlMesh->numvertices -= mdlMesh->vertexoffset - 1;
  167. mdlRangeItem.m_offNew = mdlMesh->vertexoffset;
  168. mdlRangeItem.m_numNew = mdlMesh->numvertices;
  169. arrMdlOffsets.Insert( mdlRangeItem );
  170. // Truncate the number of vertexes
  171. for ( int k = 0; k < ARRAYSIZE( mdlMesh->vertexdata.numLODVertexes ); ++ k )
  172. mdlMesh->vertexdata.numLODVertexes[ k ] = mdlMesh->numvertices;
  173. ITERATE_END
  174. ITERATE_END
  175. ITERATE_END
  176. //
  177. // Update bones not to mention anything below LOD0
  178. //
  179. ITERATE_CHILDREN( const mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
  180. ((mstudiobone_t *)mdlBone)->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
  181. ITERATE_END
  182. Log_Msg( LOG_ModelLib, " Updated %d bone(s).\n", mdlHdr->numbones );
  183. //
  184. // ===================
  185. // =================== Process VVD file
  186. // ===================
  187. //
  188. vvdHdr->numLODs = 1;
  189. for ( int k = 0; k < ARRAYSIZE( vvdHdr->numLODVertexes ); ++ k )
  190. vvdHdr->numLODVertexes[ k ] = srcIndices.Count();
  191. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  192. DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
  193. // Apply the fixups first of all
  194. if ( vvdHdr->numFixups )
  195. {
  196. CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
  197. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  198. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
  199. DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
  200. for ( int k = 0; k < vvdHdr->numFixups; ++ k )
  201. {
  202. memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
  203. vvdVertexNew += vvdFixup[ k ].numVertexes;
  204. if ( vvdTangentSrc )
  205. {
  206. memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
  207. vvdTangentNew += vvdFixup[ k ].numVertexes;
  208. }
  209. }
  210. // Move back the memory after fixups were applied
  211. vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVerticesOld * sizeof( *vvdVertexSrc ) ) : 0;
  212. vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVerticesOld * sizeof( *vvdTangentSrc ) ) : 0;
  213. }
  214. vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
  215. vvdHdr->numFixups = 0;
  216. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  217. for ( int k = 0; k < srcIndices.Count(); ++ k )
  218. vvdVertexNew[ k ] = vvdVertexSrc[ srcIndices[ k ] ];
  219. size_t newVertexDataSize = srcIndices.Count() * sizeof( mstudiovertex_t );
  220. int vvdLengthOld = vvdLength;
  221. vvdLength = vvdHdr->vertexDataStart + newVertexDataSize;
  222. if ( vvdTangentSrc )
  223. {
  224. // Move the tangents
  225. vvdHdr->tangentDataStart = vvdLength;
  226. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
  227. for ( int k = 0; k < srcIndices.Count(); ++ k )
  228. vvdTangentNew[ k ] = vvdTangentSrc[ srcIndices[ k ] ];
  229. vvdLength += srcIndices.Count() * sizeof( Vector4D );
  230. }
  231. Log_Msg( LOG_ModelLib, " Stripped %d vvd bytes.\n", vvdLengthOld - vvdLength );
  232. //
  233. // ===================
  234. // =================== Process VTX file
  235. // ===================
  236. //
  237. size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
  238. size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
  239. CMemoryMovingTracker vtxRemove( CMemoryMovingTracker::MEMORY_REMOVE );
  240. CUtlVector< size_t > vtxOffIndex;
  241. CUtlVector< size_t > vtxOffVertex;
  242. vtxRemove.RegisterElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
  243. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  244. if ( !vtxMatList_idx ) continue;
  245. vtxRemove.RegisterElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
  246. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  247. char const *szName = vtxMat->pMaterialReplacementName();
  248. vtxRemove.RegisterElements( szName, szName ? strlen( szName ) + 1 : 0 );
  249. ITERATE_END
  250. ITERATE_END
  251. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  252. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  253. vtxRemove.RegisterElements( CHILD_AT( vtxModel, pLOD, 1 ), vtxModel->numLODs - 1 );
  254. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  255. if ( !vtxLod_idx ) // Process only lod1-N
  256. continue;
  257. vtxRemove.RegisterElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
  258. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  259. vtxRemove.RegisterElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
  260. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  261. vtxRemove.RegisterElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
  262. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  263. vtxRemove.RegisterElements( CHILD_AT( vtxStrip, pBoneStateChange, 0 ), vtxStrip->numBoneStateChanges );
  264. ITERATE_END
  265. ITERATE_END
  266. ITERATE_END
  267. ITERATE_END
  268. // Use all lods to determine the ranges of vertex and index buffers.
  269. // We rely on the fact that vertex and index buffers are laid out as one solid memory block for all lods.
  270. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  271. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  272. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  273. size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
  274. size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
  275. size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
  276. size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
  277. if ( offIndex < vtxOffIndexBuffer )
  278. vtxOffIndexBuffer = offIndex;
  279. if ( offIndexEnd > vtxOffIndexBufferEnd )
  280. vtxOffIndexBufferEnd = offIndexEnd;
  281. if ( offVertex < vtxOffVertexBuffer )
  282. vtxOffVertexBuffer = offVertex;
  283. if ( offVertexEnd > vtxOffVertexBufferEnd )
  284. vtxOffVertexBufferEnd = offVertexEnd;
  285. if ( !vtxLod_idx )
  286. {
  287. vtxOffIndex.AddToTail( offIndex );
  288. vtxOffIndex.AddToTail( offIndexEnd );
  289. vtxOffVertex.AddToTail( offVertex );
  290. vtxOffVertex.AddToTail( offVertexEnd );
  291. }
  292. ITERATE_END
  293. ITERATE_END
  294. ITERATE_END
  295. ITERATE_END
  296. ITERATE_END
  297. // Fixup the vertex buffer
  298. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBuffer ) );
  299. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBufferEnd ) );
  300. CUtlVector< int > vtxIndexDeltas;
  301. vtxIndexDeltas.EnsureCapacity( vtxVertexBufferEnd - vtxVertexBuffer );
  302. int vtxNumVertexRemoved = 0;
  303. for ( OptimizedModel::Vertex_t *vtxVertexElement = vtxVertexBuffer; vtxVertexElement < vtxVertexBufferEnd; ++ vtxVertexElement )
  304. {
  305. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxVertexElement );
  306. bool bUsed = false;
  307. for ( int k = 0; k < vtxOffVertex.Count(); k += 2 )
  308. {
  309. if ( off >= vtxOffVertex[ k ] && off < vtxOffVertex[ k + 1 ] )
  310. {
  311. bUsed = true;
  312. break;
  313. }
  314. }
  315. if ( !bUsed )
  316. {
  317. // Index is not in use
  318. vtxRemove.RegisterElements( vtxVertexElement );
  319. vtxIndexDeltas.AddToTail( 0 );
  320. vtxNumVertexRemoved ++;
  321. }
  322. else
  323. { // Index is in use and must be remapped
  324. // Find the mesh where this index belongs
  325. int iMesh = arrMdlOffsets.FindLessOrEqual( CMdlStripInfo::MdlRangeItem( 0, 0, vtxVertexElement - vtxVertexBuffer ) );
  326. Assert( iMesh >= 0 && iMesh < arrMdlOffsets.Count() );
  327. CMdlStripInfo::MdlRangeItem &mri = arrMdlOffsets[ iMesh ];
  328. Assert( ( vtxVertexElement - vtxVertexBuffer >= mri.m_offNew ) && ( vtxVertexElement - vtxVertexBuffer < mri.m_offNew + mri.m_numNew ) );
  329. Assert( mapVtxIndex.IsBitSet( vtxVertexElement->origMeshVertID + mri.m_offOld ) );
  330. vtxVertexElement->origMeshVertID = srcIndices.Find( vtxVertexElement->origMeshVertID + mri.m_offOld ) - mri.m_offNew;
  331. Assert( vtxVertexElement->origMeshVertID < mri.m_numNew );
  332. vtxIndexDeltas.AddToTail( vtxNumVertexRemoved );
  333. }
  334. }
  335. // Fixup the index buffer
  336. DECLARE_PTR( unsigned short, vtxIndexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBuffer ) );
  337. DECLARE_PTR( unsigned short, vtxIndexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBufferEnd ) );
  338. for ( unsigned short *vtxIndexElement = vtxIndexBuffer; vtxIndexElement < vtxIndexBufferEnd; ++ vtxIndexElement )
  339. {
  340. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxIndexElement );
  341. bool bUsed = false;
  342. for ( int k = 0; k < vtxOffIndex.Count(); k += 2 )
  343. {
  344. if ( off >= vtxOffIndex[ k ] && off < vtxOffIndex[ k + 1 ] )
  345. {
  346. bUsed = true;
  347. break;
  348. }
  349. }
  350. if ( !bUsed )
  351. {
  352. // Index is not in use
  353. vtxRemove.RegisterElements( vtxIndexElement );
  354. }
  355. else
  356. {
  357. // Index is in use and must be remapped
  358. *vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
  359. }
  360. }
  361. // By now should have scheduled all removal information
  362. vtxRemove.Finalize();
  363. Log_Msg( LOG_ModelLib, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRegistered() );
  364. //
  365. // Fixup all the offsets
  366. //
  367. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  368. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  369. vtxMat->replacementMaterialNameOffset = vtxRemove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
  370. ITERATE_END
  371. vtxMatList->replacementOffset = vtxRemove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
  372. ITERATE_END
  373. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  374. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  375. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  376. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  377. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  378. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  379. vtxStrip->indexOffset =
  380. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
  381. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  382. vtxStrip->vertOffset =
  383. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
  384. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  385. vtxStrip->boneStateChangeOffset = vtxRemove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
  386. ITERATE_END
  387. vtxStripGroup->vertOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  388. vtxStripGroup->indexOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  389. vtxStripGroup->stripOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
  390. ITERATE_END
  391. vtxMesh->stripGroupHeaderOffset = vtxRemove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
  392. ITERATE_END
  393. vtxLod->meshOffset = vtxRemove.ComputeOffset( vtxLod, vtxLod->meshOffset );
  394. ITERATE_END
  395. vtxModel->lodOffset = vtxRemove.ComputeOffset( vtxModel, vtxModel->lodOffset );
  396. vtxModel->numLODs = 1;
  397. ITERATE_END
  398. vtxBodyPart->modelOffset = vtxRemove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
  399. ITERATE_END
  400. vtxHdr->materialReplacementListOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
  401. vtxHdr->bodyPartOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
  402. vtxHdr->numLODs = 1;
  403. // Perform final memory move
  404. vtxRemove.MemMove( vtxHdr, vtxLength );
  405. //
  406. // ===================
  407. // =================== Truncate buffer sizes
  408. // ===================
  409. //
  410. vvdBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vvdBuffer.TellGet() + vvdLength - vvdBuffer.TellPut() );
  411. vtxBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vtxBuffer.TellGet() + vtxLength - vtxBuffer.TellPut() );
  412. Log_Msg( LOG_ModelLib, " Reduced model buffers by %d bytes.\n", vtxRemove.GetNumBytesRegistered() + ( vvdLengthOld - vvdLength ) );
  413. // Done
  414. return true;
  415. }
  416. //
  417. // ParseMdlMesh
  418. // The main function that parses the mesh buffers
  419. // mdlBuffer - mdl buffer
  420. // vvdBuffer - vvd buffer
  421. // vtxBuffer - vtx buffer
  422. // mesh - on return will be filled with the mesh info
  423. //
  424. bool CMdlLib::ParseMdlMesh( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, MdlLib::MdlMesh &mesh )
  425. {
  426. DECLARE_PTR( byte, mdl, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
  427. DECLARE_PTR( byte, vvd, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  428. DECLARE_PTR( byte, vtx, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  429. int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
  430. // int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
  431. DECLARE_PTR( studiohdr_t, mdlHdr, mdl );
  432. DECLARE_PTR( vertexFileHeader_t, vvdHdr, vvd );
  433. DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
  434. // Don't do anything if the checksums don't match
  435. if ( ( mdlHdr->checksum != vvdHdr->checksum ) ||
  436. ( mdlHdr->checksum != vtxHdr->checkSum ) )
  437. {
  438. Log_Msg( LOG_ModelLib, "ERROR: [ParseMdlMesh] checksum mismatch!\n" );
  439. return false;
  440. }
  441. //
  442. // Early outs
  443. //
  444. if ( vvdHdr->numLODs != 1 )
  445. {
  446. Log_Msg( LOG_ModelLib, "ERROR: [ParseMdlMesh] the model has %d lod(s).\n", vvdHdr->numLODs );
  447. return false;
  448. }
  449. //
  450. // ===================
  451. // =================== Process MDL file
  452. // ===================
  453. //
  454. mesh.checksum = mdlHdr->checksum;
  455. int mdlNumVertices = 0;
  456. ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
  457. ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
  458. mdlNumVertices = mdlModel->numvertices;
  459. ITERATE_END
  460. ITERATE_END
  461. //
  462. // ===================
  463. // =================== Build out table of indices
  464. // ===================
  465. //
  466. mesh.ib.RemoveAll();
  467. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  468. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  469. OptimizedModel::ModelLODHeader_t *vtxLod = CHILD_AT( vtxModel, pLOD, 0 );
  470. ITERATE_CHILDREN2( OptimizedModel::MeshHeader_t, mstudiomesh_t, vtxMesh, mdlMesh, vtxLod, mdlModel, pMesh, pMesh, numMeshes )
  471. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  472. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  473. for ( int i = 0; i < vtxStrip->numIndices; ++ i )
  474. {
  475. unsigned short *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset + i );
  476. OptimizedModel::Vertex_t *vtxVertex = CHILD_AT( vtxStripGroup, pVertex, *vtxIdx );
  477. unsigned short usIdx = vtxVertex->origMeshVertID + mdlMesh->vertexoffset;
  478. mesh.ib.AddToTail( usIdx );
  479. }
  480. ITERATE_END
  481. ITERATE_END
  482. ITERATE_END
  483. ITERATE_END
  484. ITERATE_END
  485. //
  486. // ===================
  487. // =================== Build out table of vertices
  488. // ===================
  489. //
  490. mesh.vb.RemoveAll();
  491. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  492. DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
  493. // Apply the fixups first of all
  494. if ( vvdHdr->numFixups )
  495. {
  496. CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
  497. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  498. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
  499. DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
  500. for ( int k = 0; k < vvdHdr->numFixups; ++ k )
  501. {
  502. memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
  503. vvdVertexNew += vvdFixup[ k ].numVertexes;
  504. if ( vvdTangentSrc )
  505. {
  506. memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
  507. vvdTangentNew += vvdFixup[ k ].numVertexes;
  508. }
  509. }
  510. // Move back the memory after fixups were applied
  511. vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVertices * sizeof( *vvdVertexSrc ) ) : 0;
  512. vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVertices * sizeof( *vvdTangentSrc ) ) : 0;
  513. }
  514. for ( mstudiovertex_t *pSrc = vvdVertexSrc, *pEnd = pSrc + mdlNumVertices;
  515. pSrc < pEnd; ++ pSrc )
  516. {
  517. MdlLib::MdlVertex vert = {0};
  518. vert.position[0] = pSrc->m_vecPosition.x;
  519. vert.position[1] = pSrc->m_vecPosition.y;
  520. vert.position[2] = pSrc->m_vecPosition.z;
  521. vert.normal[0] = pSrc->m_vecNormal.x;
  522. vert.normal[1] = pSrc->m_vecNormal.y;
  523. vert.normal[2] = pSrc->m_vecNormal.z;
  524. vert.texcoord[0] = pSrc->m_vecTexCoord.x;
  525. vert.texcoord[1] = pSrc->m_vecTexCoord.y;
  526. mesh.vb.AddToTail( vert );
  527. }
  528. return true;
  529. }