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.

671 lines
23 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 "materialsystem/imaterial.h"
  12. #include "materialsystem/hardwareverts.h"
  13. #include "smartptr.h"
  14. //////////////////////////////////////////////////////////////////////////
  15. //
  16. // CMdlStripInfo implementation
  17. //
  18. //////////////////////////////////////////////////////////////////////////
  19. CMdlStripInfo::CMdlStripInfo() :
  20. m_eMode( MODE_UNINITIALIZED ),
  21. m_lChecksumOld( 0 ),
  22. m_lChecksumNew( 0 )
  23. {
  24. NULL;
  25. }
  26. bool CMdlStripInfo::Serialize( CUtlBuffer &bufStorage ) const
  27. {
  28. char chHeader[ 4 ] = { 'M', 'A', 'P', m_eMode };
  29. bufStorage.Put( chHeader, sizeof( chHeader ) );
  30. switch ( m_eMode )
  31. {
  32. default:
  33. case MODE_UNINITIALIZED:
  34. return true;
  35. case MODE_NO_CHANGE:
  36. bufStorage.PutInt( m_lChecksumOld );
  37. bufStorage.PutInt( m_lChecksumNew );
  38. return true;
  39. case MODE_STRIP_LOD_1N:
  40. bufStorage.PutInt( m_lChecksumOld );
  41. bufStorage.PutInt( m_lChecksumNew );
  42. bufStorage.PutInt( m_vtxVerts.GetNumBits() );
  43. for ( uint32 const *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
  44. pdwBase < pdwEnd; ++ pdwBase )
  45. bufStorage.PutUnsignedInt( *pdwBase );
  46. bufStorage.PutInt( m_vtxIndices.Count() );
  47. for ( unsigned short const *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
  48. pusBase < pusEnd; ++ pusBase )
  49. bufStorage.PutUnsignedShort( *pusBase );
  50. bufStorage.PutInt( m_vtxMdlOffsets.Count() );
  51. for ( MdlRangeItem const *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
  52. pmri < pmriEnd; ++ pmri )
  53. bufStorage.PutInt( pmri->m_offOld ),
  54. bufStorage.PutInt( pmri->m_offNew ),
  55. bufStorage.PutInt( pmri->m_numOld ),
  56. bufStorage.PutInt( pmri->m_numNew );
  57. return true;
  58. }
  59. }
  60. bool CMdlStripInfo::UnSerialize( CUtlBuffer &bufData )
  61. {
  62. char chHeader[ 4 ];
  63. bufData.Get( chHeader, sizeof( chHeader ) );
  64. if ( memcmp( chHeader, "MAP", 3 ) )
  65. return false;
  66. switch ( chHeader[3] )
  67. {
  68. default:
  69. return false;
  70. case MODE_UNINITIALIZED:
  71. m_eMode = MODE_UNINITIALIZED;
  72. m_lChecksumOld = 0;
  73. m_lChecksumNew = 0;
  74. return true;
  75. case MODE_NO_CHANGE:
  76. m_eMode = MODE_NO_CHANGE;
  77. m_lChecksumOld = bufData.GetInt();
  78. m_lChecksumNew = bufData.GetInt();
  79. return true;
  80. case MODE_STRIP_LOD_1N:
  81. m_eMode = MODE_STRIP_LOD_1N;
  82. m_lChecksumOld = bufData.GetInt();
  83. m_lChecksumNew = bufData.GetInt();
  84. m_vtxVerts.Resize( bufData.GetInt(), true );
  85. for ( uint32 *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
  86. pdwBase < pdwEnd; ++ pdwBase )
  87. *pdwBase = bufData.GetUnsignedInt();
  88. m_vtxIndices.SetCount( bufData.GetInt() );
  89. for ( unsigned short *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
  90. pusBase < pusEnd; ++ pusBase )
  91. *pusBase = bufData.GetUnsignedShort();
  92. m_vtxMdlOffsets.SetCount( bufData.GetInt() );
  93. for ( MdlRangeItem *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
  94. pmri < pmriEnd; ++ pmri )
  95. pmri->m_offOld = bufData.GetInt(),
  96. pmri->m_offNew = bufData.GetInt(),
  97. pmri->m_numOld = bufData.GetInt(),
  98. pmri->m_numNew = bufData.GetInt();
  99. return true;
  100. }
  101. }
  102. // Returns the checksums that the stripping info was generated for:
  103. // plChecksumOriginal if non-NULL will hold the checksum of the original model submitted for stripping
  104. // plChecksumStripped if non-NULL will hold the resulting checksum of the stripped model
  105. bool CMdlStripInfo::GetCheckSum( long *plChecksumOriginal, long *plChecksumStripped ) const
  106. {
  107. if ( m_eMode == MODE_UNINITIALIZED )
  108. return false;
  109. if ( plChecksumOriginal )
  110. *plChecksumOriginal = m_lChecksumOld;
  111. if ( plChecksumStripped )
  112. *plChecksumStripped = m_lChecksumNew;
  113. return true;
  114. }
  115. //
  116. // StripHardwareVertsBuffer
  117. // The main function that strips the vhv buffer
  118. // vhvBuffer - vhv buffer, updated, size reduced
  119. //
  120. bool CMdlStripInfo::StripHardwareVertsBuffer( CUtlBuffer &vhvBuffer )
  121. {
  122. if ( m_eMode == MODE_UNINITIALIZED )
  123. return false;
  124. //
  125. // Recover vhv header
  126. //
  127. DECLARE_PTR( HardwareVerts::FileHeader_t, vhvHdr, BYTE_OFF_PTR( vhvBuffer.Base(), vhvBuffer.TellGet() ) );
  128. int vhvLength = vhvBuffer.TellPut() - vhvBuffer.TellGet();
  129. if ( vhvHdr->m_nChecksum != m_lChecksumOld )
  130. {
  131. DLog( "mdllib", 1, "ERROR: [StripHardwareVertsBuffer] checksum mismatch!\n" );
  132. return false;
  133. }
  134. vhvHdr->m_nChecksum = m_lChecksumNew;
  135. // No remapping required
  136. if ( m_eMode == MODE_NO_CHANGE )
  137. return true;
  138. Assert( m_eMode == MODE_STRIP_LOD_1N );
  139. //
  140. // Now reconstruct the vhv structures to do the mapping
  141. //
  142. CRemoveTracker vhvRemove;
  143. size_t vhvVertOffset = ~size_t( 0 ), vhvEndMeshOffset = sizeof( HardwareVerts::FileHeader_t );
  144. int numMeshesRemoved = 0, numVertsRemoved = 0;
  145. ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
  146. if ( vhvMesh->m_nOffset < vhvVertOffset )
  147. vhvVertOffset = vhvMesh->m_nOffset;
  148. if ( BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 ) > vhvEndMeshOffset )
  149. vhvEndMeshOffset = BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 );
  150. if ( !vhvMesh->m_nLod )
  151. continue;
  152. vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvMesh->m_nOffset ), vhvMesh->m_nVertexes * vhvHdr->m_nVertexSize );
  153. vhvRemove.RemoveElements( vhvMesh );
  154. numVertsRemoved += vhvMesh->m_nVertexes;
  155. ++ numMeshesRemoved;
  156. ITERATE_END
  157. vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvEndMeshOffset ), vhvVertOffset - vhvEndMeshOffset ); // Padding
  158. vhvRemove.RemoveBytes( BYTE_OFF_PTR( vhvHdr, vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ), vhvLength - ( vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ) );
  159. vhvRemove.Finalize();
  160. DLog( "mdllib", 3, " Stripped %d vhv bytes.\n", vhvRemove.GetNumBytesRemoved() );
  161. // Verts must be aligned from hdr, length must be aligned from hdr
  162. size_t vhvNewVertOffset = vhvRemove.ComputeOffset( vhvHdr, vhvVertOffset );
  163. size_t vhvAlignedVertOffset = ALIGN_VALUE( vhvNewVertOffset, 4 );
  164. ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
  165. vhvMesh->m_nOffset = vhvRemove.ComputeOffset( vhvHdr, vhvMesh->m_nOffset ) + vhvAlignedVertOffset - vhvNewVertOffset;
  166. ITERATE_END
  167. vhvHdr->m_nMeshes -= numMeshesRemoved;
  168. vhvHdr->m_nVertexes -= numVertsRemoved;
  169. // Remove the memory
  170. vhvRemove.MemMove( vhvHdr, vhvLength ); // All padding has been removed
  171. size_t numBytesNewLength = vhvLength + vhvAlignedVertOffset - vhvNewVertOffset;
  172. size_t numAlignedNewLength = ALIGN_VALUE( numBytesNewLength, 4 );
  173. // Now reinsert the padding
  174. CInsertionTracker vhvInsertPadding;
  175. vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvNewVertOffset ), vhvAlignedVertOffset - vhvNewVertOffset );
  176. vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvLength ), numAlignedNewLength - numBytesNewLength );
  177. vhvInsertPadding.Finalize();
  178. DLog( "mdllib", 3, " Inserted %d alignment bytes.\n", vhvInsertPadding.GetNumBytesInserted() );
  179. vhvInsertPadding.MemMove( vhvHdr, vhvLength );
  180. // Update the buffer length
  181. vhvBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vhvBuffer.TellGet() + vhvLength - vhvBuffer.TellPut() );
  182. DLog( "mdllib", 2, " Reduced vhv buffer by %d bytes.\n", vhvRemove.GetNumBytesRemoved() - vhvInsertPadding.GetNumBytesInserted() );
  183. // Done
  184. return true;
  185. }
  186. //
  187. // StripModelBuffer
  188. // The main function that strips the mdl buffer
  189. // mdlBuffer - mdl buffer, updated
  190. //
  191. bool CMdlStripInfo::StripModelBuffer( CUtlBuffer &mdlBuffer )
  192. {
  193. if ( m_eMode == MODE_UNINITIALIZED )
  194. return false;
  195. //
  196. // Recover mdl header
  197. //
  198. DECLARE_PTR( studiohdr_t, mdlHdr, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
  199. if ( mdlHdr->checksum != m_lChecksumOld )
  200. {
  201. DLog( "mdllib", 1, "ERROR: [StripModelBuffer] checksum mismatch!\n" );
  202. return false;
  203. }
  204. mdlHdr->checksum = m_lChecksumNew;
  205. // No remapping required
  206. if ( m_eMode == MODE_NO_CHANGE )
  207. return true;
  208. Assert( m_eMode == MODE_STRIP_LOD_1N );
  209. //
  210. // Do the model buffer stripping
  211. //
  212. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  213. ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
  214. ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
  215. DLog( "mdllib", 3, " Stripped %d vertexes (was: %d, now: %d).\n", mdlModel->numvertices - srcIndices.Count(), mdlModel->numvertices, srcIndices.Count() );
  216. mdlModel->numvertices = srcIndices.Count();
  217. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
  218. mdlMesh->numvertices = srcIndices.FindLess( mdlMesh->vertexoffset + mdlMesh->numvertices );
  219. mdlMesh->vertexoffset = srcIndices.FindLess( mdlMesh->vertexoffset ) + 1;
  220. mdlMesh->numvertices -= mdlMesh->vertexoffset - 1;
  221. // Truncate the number of vertexes
  222. for ( int k = 0; k < ARRAYSIZE( mdlMesh->vertexdata.numLODVertexes ); ++ k )
  223. mdlMesh->vertexdata.numLODVertexes[ k ] = mdlMesh->numvertices;
  224. ITERATE_END
  225. ITERATE_END
  226. ITERATE_END
  227. //
  228. // Update bones not to mention anything below LOD0
  229. //
  230. ITERATE_CHILDREN( mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
  231. mdlBone->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
  232. ITERATE_END
  233. DLog( "mdllib", 3, " Updated %d bone(s).\n", mdlHdr->numbones );
  234. return true;
  235. }
  236. //
  237. // StripVertexDataBuffer
  238. // The main function that strips the vvd buffer
  239. // vvdBuffer - vvd buffer, updated, size reduced
  240. //
  241. bool CMdlStripInfo::StripVertexDataBuffer( CUtlBuffer &vvdBuffer )
  242. {
  243. if ( m_eMode == MODE_UNINITIALIZED )
  244. return false;
  245. //
  246. // Recover vvd header
  247. //
  248. DECLARE_PTR( vertexFileHeader_t, vvdHdr, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  249. int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
  250. if ( vvdHdr->checksum != m_lChecksumOld )
  251. {
  252. DLog( "mdllib", 1, "ERROR: [StripVertexDataBuffer] checksum mismatch!\n" );
  253. return false;
  254. }
  255. vvdHdr->checksum = m_lChecksumNew;
  256. // No remapping required
  257. if ( m_eMode == MODE_NO_CHANGE )
  258. return true;
  259. Assert( m_eMode == MODE_STRIP_LOD_1N );
  260. //
  261. // Do the vertex data buffer stripping
  262. //
  263. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  264. int mdlNumVerticesOld = vvdHdr->numLODVertexes[ 0 ];
  265. vvdHdr->numLODs = 1;
  266. for ( int k = 0; k < ARRAYSIZE( vvdHdr->numLODVertexes ); ++ k )
  267. vvdHdr->numLODVertexes[ k ] = srcIndices.Count();
  268. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  269. DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
  270. // Apply the fixups first of all
  271. if ( vvdHdr->numFixups )
  272. {
  273. CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
  274. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  275. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
  276. DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
  277. for ( int k = 0; k < vvdHdr->numFixups; ++ k )
  278. {
  279. memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
  280. vvdVertexNew += vvdFixup[ k ].numVertexes;
  281. if ( vvdTangentSrc )
  282. {
  283. memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
  284. vvdTangentNew += vvdFixup[ k ].numVertexes;
  285. }
  286. }
  287. // Move back the memory after fixups were applied
  288. vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVerticesOld * sizeof( *vvdVertexSrc ) ) : 0;
  289. vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVerticesOld * sizeof( *vvdTangentSrc ) ) : 0;
  290. }
  291. vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
  292. vvdHdr->numFixups = 0;
  293. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  294. for ( int k = 0; k < srcIndices.Count(); ++ k )
  295. vvdVertexNew[ k ] = vvdVertexSrc[ srcIndices[ k ] ];
  296. size_t newVertexDataSize = srcIndices.Count() * sizeof( mstudiovertex_t );
  297. int vvdLengthOld = vvdLength;
  298. vvdLength = vvdHdr->vertexDataStart + newVertexDataSize;
  299. if ( vvdTangentSrc )
  300. {
  301. // Move the tangents
  302. vvdHdr->tangentDataStart = vvdLength;
  303. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
  304. for ( int k = 0; k < srcIndices.Count(); ++ k )
  305. vvdTangentNew[ k ] = vvdTangentSrc[ srcIndices[ k ] ];
  306. vvdLength += srcIndices.Count() * sizeof( Vector4D );
  307. }
  308. vvdBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vvdBuffer.TellGet() + vvdLength - vvdBuffer.TellPut() );
  309. DLog( "mdllib", 3, " Stripped %d vvd bytes.\n", vvdLengthOld - vvdLength );
  310. return true;
  311. }
  312. //
  313. // StripOptimizedModelBuffer
  314. // The main function that strips the vtx buffer
  315. // vtxBuffer - vtx buffer, updated, size reduced
  316. //
  317. bool CMdlStripInfo::StripOptimizedModelBuffer( CUtlBuffer &vtxBuffer )
  318. {
  319. if ( m_eMode == MODE_UNINITIALIZED )
  320. return false;
  321. //
  322. // Recover vtx header
  323. //
  324. DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  325. int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
  326. if ( vtxHdr->checkSum != m_lChecksumOld )
  327. {
  328. DLog( "mdllib", 1, "ERROR: [StripOptimizedModelBuffer] checksum mismatch!\n" );
  329. return false;
  330. }
  331. vtxHdr->checkSum = m_lChecksumNew;
  332. // No remapping required
  333. if ( m_eMode == MODE_NO_CHANGE )
  334. return true;
  335. Assert( m_eMode == MODE_STRIP_LOD_1N );
  336. //
  337. // Do the optimized model buffer stripping
  338. //
  339. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  340. CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > &arrMdlOffsets = m_vtxMdlOffsets;
  341. size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
  342. size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
  343. CRemoveTracker vtxRemove;
  344. CUtlVector< size_t > vtxOffIndex;
  345. CUtlVector< size_t > vtxOffVertex;
  346. vtxRemove.RemoveElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
  347. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  348. if ( !vtxMatList_idx ) continue;
  349. vtxRemove.RemoveElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
  350. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  351. char const *szName = vtxMat->pMaterialReplacementName();
  352. vtxRemove.RemoveElements( szName, szName ? strlen( szName ) + 1 : 0 );
  353. ITERATE_END
  354. ITERATE_END
  355. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  356. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  357. vtxRemove.RemoveElements( CHILD_AT( vtxModel, pLOD, 1 ), vtxModel->numLODs - 1 );
  358. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  359. if ( !vtxLod_idx ) // Process only lod1-N
  360. continue;
  361. vtxRemove.RemoveElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
  362. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  363. vtxRemove.RemoveElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
  364. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  365. vtxRemove.RemoveElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
  366. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  367. vtxRemove.RemoveElements( CHILD_AT( vtxStrip, pBoneStateChange, 0 ), vtxStrip->numBoneStateChanges );
  368. ITERATE_END
  369. ITERATE_END
  370. ITERATE_END
  371. ITERATE_END
  372. // Use all lods to determine the ranges of vertex and index buffers.
  373. // We rely on the fact that vertex and index buffers are laid out as one solid memory block for all lods.
  374. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  375. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  376. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  377. size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
  378. size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
  379. size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
  380. size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
  381. if ( offIndex < vtxOffIndexBuffer )
  382. vtxOffIndexBuffer = offIndex;
  383. if ( offIndexEnd > vtxOffIndexBufferEnd )
  384. vtxOffIndexBufferEnd = offIndexEnd;
  385. if ( offVertex < vtxOffVertexBuffer )
  386. vtxOffVertexBuffer = offVertex;
  387. if ( offVertexEnd > vtxOffVertexBufferEnd )
  388. vtxOffVertexBufferEnd = offVertexEnd;
  389. if ( !vtxLod_idx )
  390. {
  391. vtxOffIndex.AddToTail( offIndex );
  392. vtxOffIndex.AddToTail( offIndexEnd );
  393. vtxOffVertex.AddToTail( offVertex );
  394. vtxOffVertex.AddToTail( offVertexEnd );
  395. }
  396. ITERATE_END
  397. ITERATE_END
  398. ITERATE_END
  399. ITERATE_END
  400. ITERATE_END
  401. // Fixup the vertex buffer
  402. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBuffer ) );
  403. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBufferEnd ) );
  404. CUtlVector< int > vtxIndexDeltas;
  405. vtxIndexDeltas.EnsureCapacity( vtxVertexBufferEnd - vtxVertexBuffer );
  406. int vtxNumVertexRemoved = 0;
  407. for ( OptimizedModel::Vertex_t *vtxVertexElement = vtxVertexBuffer; vtxVertexElement < vtxVertexBufferEnd; ++ vtxVertexElement )
  408. {
  409. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxVertexElement );
  410. bool bUsed = false;
  411. for ( int k = 0; k < vtxOffVertex.Count(); k += 2 )
  412. {
  413. if ( off >= vtxOffVertex[ k ] && off < vtxOffVertex[ k + 1 ] )
  414. {
  415. bUsed = true;
  416. break;
  417. }
  418. }
  419. if ( !bUsed )
  420. {
  421. // Index is not in use
  422. vtxRemove.RemoveElements( vtxVertexElement );
  423. vtxIndexDeltas.AddToTail( 0 );
  424. vtxNumVertexRemoved ++;
  425. }
  426. else
  427. { // Index is in use and must be remapped
  428. // Find the mesh where this index belongs
  429. int iMesh = arrMdlOffsets.FindLessOrEqual( MdlRangeItem( 0, 0, vtxVertexElement - vtxVertexBuffer ) );
  430. Assert( iMesh >= 0 && iMesh < arrMdlOffsets.Count() );
  431. MdlRangeItem &mri = arrMdlOffsets[ iMesh ];
  432. Assert( ( vtxVertexElement - vtxVertexBuffer >= mri.m_offNew ) && ( vtxVertexElement - vtxVertexBuffer < mri.m_offNew + mri.m_numNew ) );
  433. Assert( m_vtxVerts.IsBitSet( vtxVertexElement->origMeshVertID + mri.m_offOld ) );
  434. vtxVertexElement->origMeshVertID = srcIndices.Find( vtxVertexElement->origMeshVertID + mri.m_offOld ) - mri.m_offNew;
  435. Assert( vtxVertexElement->origMeshVertID < mri.m_numNew );
  436. vtxIndexDeltas.AddToTail( vtxNumVertexRemoved );
  437. }
  438. }
  439. // Fixup the index buffer
  440. DECLARE_PTR( unsigned short, vtxIndexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBuffer ) );
  441. DECLARE_PTR( unsigned short, vtxIndexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBufferEnd ) );
  442. for ( unsigned short *vtxIndexElement = vtxIndexBuffer; vtxIndexElement < vtxIndexBufferEnd; ++ vtxIndexElement )
  443. {
  444. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxIndexElement );
  445. bool bUsed = false;
  446. for ( int k = 0; k < vtxOffIndex.Count(); k += 2 )
  447. {
  448. if ( off >= vtxOffIndex[ k ] && off < vtxOffIndex[ k + 1 ] )
  449. {
  450. bUsed = true;
  451. break;
  452. }
  453. }
  454. if ( !bUsed )
  455. {
  456. // Index is not in use
  457. vtxRemove.RemoveElements( vtxIndexElement );
  458. }
  459. else
  460. {
  461. // Index is in use and must be remapped
  462. *vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
  463. }
  464. }
  465. // By now should have scheduled all removal information
  466. vtxRemove.Finalize();
  467. DLog( "mdllib", 3, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRemoved() );
  468. //
  469. // Fixup all the offsets
  470. //
  471. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  472. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  473. vtxMat->replacementMaterialNameOffset = vtxRemove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
  474. ITERATE_END
  475. vtxMatList->replacementOffset = vtxRemove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
  476. ITERATE_END
  477. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  478. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  479. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  480. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  481. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  482. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  483. vtxStrip->indexOffset =
  484. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
  485. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  486. vtxStrip->vertOffset =
  487. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
  488. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  489. vtxStrip->boneStateChangeOffset = vtxRemove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
  490. ITERATE_END
  491. vtxStripGroup->vertOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  492. vtxStripGroup->indexOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  493. vtxStripGroup->stripOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
  494. ITERATE_END
  495. vtxMesh->stripGroupHeaderOffset = vtxRemove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
  496. ITERATE_END
  497. vtxLod->meshOffset = vtxRemove.ComputeOffset( vtxLod, vtxLod->meshOffset );
  498. ITERATE_END
  499. vtxModel->lodOffset = vtxRemove.ComputeOffset( vtxModel, vtxModel->lodOffset );
  500. vtxModel->numLODs = 1;
  501. ITERATE_END
  502. vtxBodyPart->modelOffset = vtxRemove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
  503. ITERATE_END
  504. vtxHdr->materialReplacementListOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
  505. vtxHdr->bodyPartOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
  506. vtxHdr->numLODs = 1;
  507. // Perform final memory move
  508. vtxRemove.MemMove( vtxHdr, vtxLength );
  509. vtxBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vtxBuffer.TellGet() + vtxLength - vtxBuffer.TellPut() );
  510. return true;
  511. }
  512. //////////////////////////////////////////////////////////////////////////
  513. //
  514. // Auxilliary methods
  515. //
  516. //////////////////////////////////////////////////////////////////////////
  517. void CMdlStripInfo::DeleteThis()
  518. {
  519. delete this;
  520. }
  521. void CMdlStripInfo::Reset()
  522. {
  523. m_eMode = MODE_UNINITIALIZED;
  524. m_lChecksumOld = 0;
  525. m_lChecksumNew = 0;
  526. m_vtxVerts.Resize( 0 );
  527. m_vtxIndices.RemoveAll();
  528. }