Team Fortress 2 Source Code as on 22/4/2020
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.

504 lines
20 KiB

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