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.

874 lines
32 KiB

  1. //====== Copyright c 1996-2007, 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. case MODE_PS3_FORMAT_BASIC:
  37. bufStorage.PutInt( m_lChecksumOld );
  38. bufStorage.PutInt( m_lChecksumNew );
  39. return true;
  40. case MODE_STRIP_LOD_1N:
  41. bufStorage.PutInt( m_lChecksumOld );
  42. bufStorage.PutInt( m_lChecksumNew );
  43. bufStorage.PutInt( m_vtxVerts.GetNumBits() );
  44. for ( uint32 const *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
  45. pdwBase < pdwEnd; ++ pdwBase )
  46. bufStorage.PutUnsignedInt( *pdwBase );
  47. bufStorage.PutInt( m_vtxIndices.Count() );
  48. for ( unsigned short const *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
  49. pusBase < pusEnd; ++ pusBase )
  50. bufStorage.PutUnsignedShort( *pusBase );
  51. bufStorage.PutInt( m_vtxMdlOffsets.Count() );
  52. for ( MdlRangeItem const *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
  53. pmri < pmriEnd; ++ pmri )
  54. bufStorage.PutInt( pmri->m_offOld ),
  55. bufStorage.PutInt( pmri->m_offNew ),
  56. bufStorage.PutInt( pmri->m_numOld ),
  57. bufStorage.PutInt( pmri->m_numNew );
  58. return true;
  59. case MODE_PS3_PARTITIONS:
  60. bufStorage.PutInt( m_lChecksumOld );
  61. bufStorage.PutInt( m_lChecksumNew );
  62. bufStorage.PutUnsignedInt( m_ps3studioBatches.Count() );
  63. for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
  64. {
  65. Ps3studioBatch_t &batch = *m_ps3studioBatches[k];
  66. bufStorage.PutUnsignedInt( batch.m_arrPartitions.Count() );
  67. for ( int j = 0; j < batch.m_arrPartitions.Count(); ++ j )
  68. {
  69. Ps3studioPartition_t &partition = *batch.m_arrPartitions[j];
  70. bufStorage.PutUnsignedInt( partition.m_arrLocalIndices.Count() );
  71. for ( int nn = 0; nn < partition.m_arrLocalIndices.Count(); ++ nn )
  72. {
  73. bufStorage.PutUnsignedShort( partition.m_arrLocalIndices[nn] );
  74. }
  75. bufStorage.PutUnsignedInt( partition.m_arrVertOriginalIndices.Count() );
  76. for ( int nn = 0; nn < partition.m_arrVertOriginalIndices.Count(); ++ nn )
  77. {
  78. bufStorage.PutUnsignedInt( partition.m_arrVertOriginalIndices[nn] );
  79. }
  80. bufStorage.PutUnsignedInt( partition.m_arrStripLocalOriginalIndices.Count() );
  81. for ( int nn = 0; nn < partition.m_arrStripLocalOriginalIndices.Count(); ++ nn )
  82. {
  83. bufStorage.PutUnsignedInt( partition.m_arrStripLocalOriginalIndices[nn] );
  84. }
  85. bufStorage.PutUnsignedInt( partition.m_nIoBufferSize );
  86. }
  87. bufStorage.PutUnsignedInt( batch.m_uiModelIndexOffset );
  88. bufStorage.PutUnsignedInt( batch.m_uiVhvIndexOffset );
  89. }
  90. bufStorage.PutUnsignedInt( m_ps3studioStripGroupHeaderBatchOffset.Count() );
  91. for ( int k = 0; k < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ k )
  92. {
  93. bufStorage.PutUnsignedInt( m_ps3studioStripGroupHeaderBatchOffset[k] );
  94. }
  95. return true;
  96. }
  97. }
  98. bool CMdlStripInfo::UnSerialize( CUtlBuffer &bufData )
  99. {
  100. char chHeader[ 4 ];
  101. bufData.Get( chHeader, sizeof( chHeader ) );
  102. if ( memcmp( chHeader, "MAP", 3 ) )
  103. return false;
  104. m_eMode = chHeader[3];
  105. switch ( chHeader[3] )
  106. {
  107. default:
  108. return false;
  109. case MODE_UNINITIALIZED:
  110. m_lChecksumOld = 0;
  111. m_lChecksumNew = 0;
  112. return true;
  113. case MODE_NO_CHANGE:
  114. case MODE_PS3_FORMAT_BASIC:
  115. m_lChecksumOld = bufData.GetInt();
  116. m_lChecksumNew = bufData.GetInt();
  117. return true;
  118. case MODE_STRIP_LOD_1N:
  119. m_lChecksumOld = bufData.GetInt();
  120. m_lChecksumNew = bufData.GetInt();
  121. m_vtxVerts.Resize( bufData.GetInt(), true );
  122. for ( uint32 *pdwBase = m_vtxVerts.Base(), *pdwEnd = pdwBase + m_vtxVerts.GetNumDWords();
  123. pdwBase < pdwEnd; ++ pdwBase )
  124. *pdwBase = bufData.GetUnsignedInt();
  125. m_vtxIndices.SetCount( bufData.GetInt() );
  126. for ( unsigned short *pusBase = m_vtxIndices.Base(), *pusEnd = pusBase + m_vtxIndices.Count();
  127. pusBase < pusEnd; ++ pusBase )
  128. *pusBase = bufData.GetUnsignedShort();
  129. m_vtxMdlOffsets.SetCount( bufData.GetInt() );
  130. for ( MdlRangeItem *pmri = m_vtxMdlOffsets.Base(), *pmriEnd = pmri + m_vtxMdlOffsets.Count();
  131. pmri < pmriEnd; ++ pmri )
  132. pmri->m_offOld = bufData.GetInt(),
  133. pmri->m_offNew = bufData.GetInt(),
  134. pmri->m_numOld = bufData.GetInt(),
  135. pmri->m_numNew = bufData.GetInt();
  136. return true;
  137. case MODE_PS3_PARTITIONS:
  138. m_lChecksumOld = bufData.GetInt();
  139. m_lChecksumNew = bufData.GetInt();
  140. m_ps3studioBatches.SetCount( bufData.GetUnsignedInt() );
  141. for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
  142. {
  143. m_ps3studioBatches[k] = new Ps3studioBatch_t;
  144. Ps3studioBatch_t &batch = *m_ps3studioBatches[k];
  145. batch.m_arrPartitions.SetCount( bufData.GetUnsignedInt() );
  146. for ( int j = 0; j < batch.m_arrPartitions.Count(); ++ j )
  147. {
  148. batch.m_arrPartitions[j] = new Ps3studioPartition_t;
  149. Ps3studioPartition_t &partition = *batch.m_arrPartitions[j];
  150. partition.m_arrLocalIndices.SetCount( bufData.GetUnsignedInt() );
  151. for ( int nn = 0; nn < partition.m_arrLocalIndices.Count(); ++ nn )
  152. {
  153. partition.m_arrLocalIndices[nn] = bufData.GetUnsignedShort();
  154. }
  155. partition.m_arrVertOriginalIndices.SetCount( bufData.GetUnsignedInt() );
  156. for ( int nn = 0; nn < partition.m_arrVertOriginalIndices.Count(); ++ nn )
  157. {
  158. partition.m_arrVertOriginalIndices[nn] = bufData.GetUnsignedInt();
  159. }
  160. partition.m_arrStripLocalOriginalIndices.SetCount( bufData.GetUnsignedInt() );
  161. for ( int nn = 0; nn < partition.m_arrStripLocalOriginalIndices.Count(); ++ nn )
  162. {
  163. partition.m_arrStripLocalOriginalIndices[nn] = bufData.GetUnsignedInt();
  164. }
  165. partition.m_nIoBufferSize = bufData.GetUnsignedInt();
  166. }
  167. batch.m_uiModelIndexOffset = bufData.GetUnsignedInt();
  168. batch.m_uiVhvIndexOffset = bufData.GetUnsignedInt();
  169. }
  170. m_ps3studioStripGroupHeaderBatchOffset.SetCount( bufData.GetUnsignedInt() );
  171. for ( int k = 0; k < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ k )
  172. {
  173. m_ps3studioStripGroupHeaderBatchOffset[k] = bufData.GetUnsignedInt();
  174. }
  175. return true;
  176. }
  177. }
  178. // Returns the checksums that the stripping info was generated for:
  179. // plChecksumOriginal if non-NULL will hold the checksum of the original model submitted for stripping
  180. // plChecksumStripped if non-NULL will hold the resulting checksum of the stripped model
  181. bool CMdlStripInfo::GetCheckSum( long *plChecksumOriginal, long *plChecksumStripped ) const
  182. {
  183. if ( m_eMode == MODE_UNINITIALIZED )
  184. return false;
  185. if ( plChecksumOriginal )
  186. *plChecksumOriginal = m_lChecksumOld;
  187. if ( plChecksumStripped )
  188. *plChecksumStripped = m_lChecksumNew;
  189. return true;
  190. }
  191. static inline uint32 Helper_SwapVhvColorForPs3( uint32 uiColor )
  192. {
  193. // Swapping R and B channels
  194. return
  195. ( ( ( uiColor >> 0 ) & 0xFF ) << 16 ) |
  196. ( ( ( uiColor >> 8 ) & 0xFF ) << 8 ) |
  197. ( ( ( uiColor >> 16 ) & 0xFF ) << 0 ) |
  198. ( ( ( uiColor >> 24 ) & 0xFF ) << 24 );
  199. }
  200. //
  201. // StripHardwareVertsBuffer
  202. // The main function that strips the vhv buffer
  203. // vhvBuffer - vhv buffer, updated, size reduced
  204. //
  205. bool CMdlStripInfo::StripHardwareVertsBuffer( CUtlBuffer &vhvBuffer )
  206. {
  207. if ( m_eMode == MODE_UNINITIALIZED )
  208. return false;
  209. //
  210. // Recover vhv header
  211. //
  212. DECLARE_PTR( HardwareVerts::FileHeader_t, vhvHdr, BYTE_OFF_PTR( vhvBuffer.Base(), vhvBuffer.TellGet() ) );
  213. int vhvLength = vhvBuffer.TellPut() - vhvBuffer.TellGet();
  214. if ( vhvHdr->m_nChecksum != m_lChecksumOld )
  215. {
  216. Log_Msg( LOG_ModelLib, "ERROR: [StripHardwareVertsBuffer] checksum mismatch!\n" );
  217. return false;
  218. }
  219. vhvHdr->m_nChecksum = m_lChecksumNew;
  220. // No remapping required
  221. if ( m_eMode == MODE_NO_CHANGE )
  222. return true;
  223. // Basic PS3 remapping required
  224. if ( m_eMode == MODE_PS3_FORMAT_BASIC )
  225. {
  226. DECLARE_PTR( uint32, pVertDataSrc, BYTE_OFF_PTR( vhvHdr, AlignValue( sizeof( *vhvHdr ) + vhvHdr->m_nMeshes * sizeof( HardwareVerts::MeshHeader_t ), 512 ) ) );
  227. DECLARE_PTR( uint32, pVertDataEnd, BYTE_OFF_PTR( vhvHdr, vhvLength ) );
  228. while ( pVertDataSrc + 1 <= pVertDataEnd )
  229. {
  230. * ( pVertDataSrc ++ ) = Helper_SwapVhvColorForPs3( *pVertDataSrc );
  231. }
  232. return true;
  233. }
  234. if ( m_eMode == MODE_STRIP_LOD_1N )
  235. {
  236. //
  237. // Now reconstruct the vhv structures to do the mapping
  238. //
  239. CMemoryMovingTracker vhvRemove( CMemoryMovingTracker::MEMORY_REMOVE );
  240. size_t vhvVertOffset = ~size_t( 0 ), vhvEndMeshOffset = sizeof( HardwareVerts::FileHeader_t );
  241. int numMeshesRemoved = 0, numVertsRemoved = 0;
  242. ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
  243. if ( vhvMesh->m_nOffset < vhvVertOffset )
  244. vhvVertOffset = vhvMesh->m_nOffset;
  245. if ( BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 ) > vhvEndMeshOffset )
  246. vhvEndMeshOffset = BYTE_DIFF_PTR( vhvHdr, vhvMesh + 1 );
  247. if ( !vhvMesh->m_nLod )
  248. continue;
  249. vhvRemove.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvMesh->m_nOffset ), vhvMesh->m_nVertexes * vhvHdr->m_nVertexSize );
  250. vhvRemove.RegisterElements( vhvMesh );
  251. numVertsRemoved += vhvMesh->m_nVertexes;
  252. ++ numMeshesRemoved;
  253. ITERATE_END
  254. vhvRemove.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvEndMeshOffset ), vhvVertOffset - vhvEndMeshOffset ); // Padding
  255. vhvRemove.RegisterBytes( BYTE_OFF_PTR( vhvHdr, vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ), vhvLength - ( vhvVertOffset + vhvHdr->m_nVertexes * vhvHdr->m_nVertexSize ) );
  256. vhvRemove.Finalize();
  257. Log_Msg( LOG_ModelLib, " Stripped %d vhv bytes.\n", vhvRemove.GetNumBytesRegistered() );
  258. // Verts must be aligned from hdr, length must be aligned from hdr
  259. size_t vhvNewVertOffset = vhvRemove.ComputeOffset( vhvHdr, vhvVertOffset );
  260. size_t vhvAlignedVertOffset = ALIGN_VALUE( vhvNewVertOffset, 4 );
  261. ITERATE_CHILDREN( HardwareVerts::MeshHeader_t, vhvMesh, vhvHdr, pMesh, m_nMeshes )
  262. vhvMesh->m_nOffset = vhvRemove.ComputeOffset( vhvHdr, vhvMesh->m_nOffset ) + vhvAlignedVertOffset - vhvNewVertOffset;
  263. ITERATE_END
  264. vhvHdr->m_nMeshes -= numMeshesRemoved;
  265. vhvHdr->m_nVertexes -= numVertsRemoved;
  266. // Remove the memory
  267. vhvRemove.MemMove( vhvHdr, vhvLength ); // All padding has been removed
  268. size_t numBytesNewLength = vhvLength + vhvAlignedVertOffset - vhvNewVertOffset;
  269. size_t numAlignedNewLength = ALIGN_VALUE( numBytesNewLength, 4 );
  270. // Now reinsert the padding
  271. CInsertionTracker vhvInsertPadding;
  272. vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvNewVertOffset ), vhvAlignedVertOffset - vhvNewVertOffset );
  273. vhvInsertPadding.InsertBytes( BYTE_OFF_PTR( vhvHdr, vhvLength ), numAlignedNewLength - numBytesNewLength );
  274. vhvInsertPadding.Finalize();
  275. Log_Msg( LOG_ModelLib, " Inserted %d alignment bytes.\n", vhvInsertPadding.GetNumBytesInserted() );
  276. vhvInsertPadding.MemMove( vhvHdr, vhvLength );
  277. // Update the buffer length
  278. vhvBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vhvBuffer.TellGet() + vhvLength - vhvBuffer.TellPut() );
  279. Log_Msg( LOG_ModelLib, " Reduced vhv buffer by %d bytes.\n", vhvRemove.GetNumBytesRegistered() - vhvInsertPadding.GetNumBytesInserted() );
  280. return true;
  281. }
  282. if ( m_eMode == MODE_PS3_PARTITIONS )
  283. {
  284. //
  285. // Complex partitions processing
  286. //
  287. // Expect number of meshes in VHV header to match
  288. if ( !vhvHdr->m_nMeshes || vhvHdr->m_nMeshes != m_ps3studioStripGroupHeaderBatchOffset.Count() )
  289. {
  290. Log_Msg( LOG_ModelLib, " Mismatching vhv buffer mesh count( vhv=%d, vsi=%d ).\n", vhvHdr->m_nMeshes, m_ps3studioStripGroupHeaderBatchOffset.Count() );
  291. return false;
  292. }
  293. // Count total number of vertices
  294. uint32 uiTotalVerts = 0;
  295. for ( int k = 0; k < m_ps3studioBatches.Count(); ++ k )
  296. for ( int j = 0; j < m_ps3studioBatches[k]->m_arrPartitions.Count(); ++ j )
  297. uiTotalVerts += m_ps3studioBatches[k]->m_arrPartitions[j]->m_arrVertOriginalIndices.Count();
  298. // Now allocate enough target buffer space to fit all the verts
  299. uint32 uiRequiredBufferSize = sizeof( HardwareVerts::FileHeader_t ) + vhvHdr->m_nMeshes*sizeof( HardwareVerts::MeshHeader_t );
  300. uiRequiredBufferSize = AlignValue( uiRequiredBufferSize, 512 ); // start actual data stream on 512-boundary
  301. uint32 uiTotalBufferSize = AlignValue( uiRequiredBufferSize + 4 * uiTotalVerts, 512 );
  302. // Copy off the source buffer
  303. CUtlBuffer bufSrcCopy;
  304. bufSrcCopy.EnsureCapacity( MAX( uiTotalBufferSize, vhvLength ) );
  305. V_memcpy( bufSrcCopy.Base(), vhvHdr, vhvLength );
  306. // We know where the first mesh's vertices should start
  307. if ( vhvHdr->pMesh(0)->m_nOffset != uiRequiredBufferSize || uiTotalBufferSize < vhvLength )
  308. {
  309. Log_Msg( LOG_ModelLib, " Unexpected vhv buffer mesh offset.\n" );
  310. return false;
  311. }
  312. vhvBuffer.EnsureCapacity( vhvBuffer.TellGet() + uiTotalBufferSize );
  313. vhvBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, uiTotalBufferSize - vhvLength );
  314. DECLARE_UPDATE_PTR( HardwareVerts::FileHeader_t, vhvHdr, BYTE_OFF_PTR( vhvBuffer.Base(), vhvBuffer.TellGet() ) );
  315. DECLARE_PTR( HardwareVerts::FileHeader_t, vhvHdrSrc, bufSrcCopy.Base() );
  316. //
  317. // === update the actual VHV vertices
  318. //
  319. DECLARE_PTR( uint32, pVertDataSrc, BYTE_OFF_PTR( vhvHdrSrc, uiRequiredBufferSize ) );
  320. DECLARE_PTR( uint32, pVertDataDst, BYTE_OFF_PTR( vhvHdr, uiRequiredBufferSize ) );
  321. #ifdef _DEBUG
  322. // Keep track of which verts got touched
  323. CGrowableBitVec arrTouchedOriginalVerts;
  324. uint32 uiDebugOriginalVertsPresent = 0;
  325. for ( uint32 iDebugMesh = 0; iDebugMesh < vhvHdr->m_nMeshes; ++ iDebugMesh )
  326. uiDebugOriginalVertsPresent += vhvHdr->pMesh(iDebugMesh)->m_nVertexes;
  327. #endif
  328. for ( uint32 iMesh = 0, iBatch = 0; iMesh < m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ iMesh )
  329. {
  330. uint32 numVerts = 0;
  331. vhvHdr->pMesh(iMesh)->m_nOffset = BYTE_DIFF_PTR( vhvHdr, pVertDataDst );
  332. uint32 iBatchEnd = ( iMesh < m_ps3studioStripGroupHeaderBatchOffset.Count() - 1 )
  333. ? m_ps3studioStripGroupHeaderBatchOffset[iMesh+1] : m_ps3studioBatches.Count();
  334. iBatchEnd = MIN( iBatchEnd, m_ps3studioBatches.Count() );
  335. for ( ; iBatch < iBatchEnd; ++ iBatch )
  336. {
  337. Ps3studioBatch_t &batch = *m_ps3studioBatches[iBatch];
  338. // uint32 arrForcedColors[] = { 0xFF200000, 0xFFFF0000, 0xFFFFFF00, 0xFF002000, 0xFF00FF00, 0xFF00FFFF, 0xFF000020, 0xFF0000FF, 0xFFFF00FF };
  339. for ( uint32 iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
  340. {
  341. Ps3studioPartition_t &partition = *batch.m_arrPartitions[iPartition];
  342. numVerts += partition.m_arrVertOriginalIndices.Count();
  343. for ( uint32 iVertIndex = 0; iVertIndex < partition.m_arrVertOriginalIndices.Count(); ++ iVertIndex )
  344. {
  345. // uint32 uiOrigVertIndex = partition.m_arrVertOriginalIndices[iVertIndex];
  346. uint32 uiOrigVertIndex = partition.m_arrStripLocalOriginalIndices[iVertIndex];
  347. uiOrigVertIndex += batch.m_uiVhvIndexOffset;
  348. uint32 uiColor = pVertDataSrc[uiOrigVertIndex];
  349. Assert( BYTE_DIFF_PTR( vhvHdrSrc, pVertDataSrc[uiOrigVertIndex] ) < vhvLength );
  350. // uiColor = arrForcedColors[iPartition%ARRAYSIZE(arrForcedColors)];
  351. *( pVertDataDst ++ ) = Helper_SwapVhvColorForPs3( uiColor );
  352. Assert( BYTE_DIFF_PTR( vhvHdr, pVertDataDst ) <= uiTotalBufferSize );
  353. #ifdef _DEBUG
  354. arrTouchedOriginalVerts.GrowSetBit( uiOrigVertIndex );
  355. #endif
  356. }
  357. }
  358. }
  359. vhvHdr->pMesh(iMesh)->m_nVertexes = numVerts;
  360. }
  361. #ifdef _DEBUG
  362. {
  363. uint32 uiDebugTouchedOriginalVerts = arrTouchedOriginalVerts.GetNumBits();
  364. for ( uint32 iDebugOrigVert = 0; iDebugOrigVert < uiDebugOriginalVertsPresent; ++ iDebugOrigVert )
  365. {
  366. Assert( arrTouchedOriginalVerts.IsBitSet( iDebugOrigVert ) );
  367. }
  368. Assert( uiDebugTouchedOriginalVerts == uiDebugOriginalVertsPresent );
  369. }
  370. #endif
  371. return true;
  372. }
  373. // Done
  374. return false;
  375. }
  376. //
  377. // StripModelBuffer
  378. // The main function that strips the mdl buffer
  379. // mdlBuffer - mdl buffer, updated
  380. //
  381. bool CMdlStripInfo::StripModelBuffer( CUtlBuffer &mdlBuffer )
  382. {
  383. if ( m_eMode == MODE_UNINITIALIZED )
  384. return false;
  385. //
  386. // Recover mdl header
  387. //
  388. DECLARE_PTR( studiohdr_t, mdlHdr, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
  389. if ( mdlHdr->checksum != m_lChecksumOld )
  390. {
  391. Log_Msg( LOG_ModelLib, "ERROR: [StripModelBuffer] checksum mismatch!\n" );
  392. return false;
  393. }
  394. mdlHdr->checksum = m_lChecksumNew;
  395. // No remapping required
  396. if ( m_eMode == MODE_NO_CHANGE )
  397. return true;
  398. if ( m_eMode != MODE_STRIP_LOD_1N )
  399. return false;
  400. //
  401. // Do the model buffer stripping
  402. //
  403. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  404. ITERATE_CHILDREN( mstudiobodyparts_t, mdlBodyPart, mdlHdr, pBodypart, numbodyparts )
  405. ITERATE_CHILDREN( mstudiomodel_t, mdlModel, mdlBodyPart, pModel, nummodels )
  406. Log_Msg( LOG_ModelLib, " Stripped %d vertexes (was: %d, now: %d).\n", mdlModel->numvertices - srcIndices.Count(), mdlModel->numvertices, srcIndices.Count() );
  407. mdlModel->numvertices = srcIndices.Count();
  408. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
  409. mdlMesh->numvertices = srcIndices.FindLess( mdlMesh->vertexoffset + mdlMesh->numvertices );
  410. mdlMesh->vertexoffset = srcIndices.FindLess( mdlMesh->vertexoffset ) + 1;
  411. mdlMesh->numvertices -= mdlMesh->vertexoffset - 1;
  412. // Truncate the number of vertexes
  413. for ( int k = 0; k < ARRAYSIZE( mdlMesh->vertexdata.numLODVertexes ); ++ k )
  414. mdlMesh->vertexdata.numLODVertexes[ k ] = mdlMesh->numvertices;
  415. ITERATE_END
  416. ITERATE_END
  417. ITERATE_END
  418. //
  419. // Update bones not to mention anything below LOD0
  420. //
  421. ITERATE_CHILDREN( const mstudiobone_t, mdlBone, mdlHdr, pBone, numbones )
  422. ((mstudiobone_t *)mdlBone)->flags &= ( BONE_USED_BY_VERTEX_LOD0 | ~BONE_USED_BY_VERTEX_MASK );
  423. ITERATE_END
  424. Log_Msg( LOG_ModelLib, " Updated %d bone(s).\n", mdlHdr->numbones );
  425. return true;
  426. }
  427. //
  428. // StripVertexDataBuffer
  429. // The main function that strips the vvd buffer
  430. // vvdBuffer - vvd buffer, updated, size reduced
  431. //
  432. bool CMdlStripInfo::StripVertexDataBuffer( CUtlBuffer &vvdBuffer )
  433. {
  434. if ( m_eMode == MODE_UNINITIALIZED )
  435. return false;
  436. //
  437. // Recover vvd header
  438. //
  439. DECLARE_PTR( vertexFileHeader_t, vvdHdr, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  440. int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
  441. if ( vvdHdr->checksum != m_lChecksumOld )
  442. {
  443. Log_Msg( LOG_ModelLib, "ERROR: [StripVertexDataBuffer] checksum mismatch!\n" );
  444. return false;
  445. }
  446. vvdHdr->checksum = m_lChecksumNew;
  447. // No remapping required
  448. if ( m_eMode == MODE_NO_CHANGE )
  449. return true;
  450. if ( m_eMode != MODE_STRIP_LOD_1N )
  451. return false;
  452. //
  453. // Do the vertex data buffer stripping
  454. //
  455. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  456. int mdlNumVerticesOld = vvdHdr->numLODVertexes[ 0 ];
  457. vvdHdr->numLODs = 1;
  458. for ( int k = 0; k < ARRAYSIZE( vvdHdr->numLODVertexes ); ++ k )
  459. vvdHdr->numLODVertexes[ k ] = srcIndices.Count();
  460. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  461. DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
  462. // Apply the fixups first of all
  463. if ( vvdHdr->numFixups )
  464. {
  465. CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
  466. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  467. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
  468. DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
  469. for ( int k = 0; k < vvdHdr->numFixups; ++ k )
  470. {
  471. memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
  472. vvdVertexNew += vvdFixup[ k ].numVertexes;
  473. if ( vvdTangentSrc )
  474. {
  475. memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
  476. vvdTangentNew += vvdFixup[ k ].numVertexes;
  477. }
  478. }
  479. // Move back the memory after fixups were applied
  480. vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), mdlNumVerticesOld * sizeof( *vvdVertexSrc ) ) : 0;
  481. vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), mdlNumVerticesOld * sizeof( *vvdTangentSrc ) ) : 0;
  482. }
  483. vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
  484. vvdHdr->numFixups = 0;
  485. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  486. for ( int k = 0; k < srcIndices.Count(); ++ k )
  487. vvdVertexNew[ k ] = vvdVertexSrc[ srcIndices[ k ] ];
  488. size_t newVertexDataSize = srcIndices.Count() * sizeof( mstudiovertex_t );
  489. int vvdLengthOld = vvdLength;
  490. vvdLength = vvdHdr->vertexDataStart + newVertexDataSize;
  491. if ( vvdTangentSrc )
  492. {
  493. // Move the tangents
  494. vvdHdr->tangentDataStart = vvdLength;
  495. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
  496. for ( int k = 0; k < srcIndices.Count(); ++ k )
  497. vvdTangentNew[ k ] = vvdTangentSrc[ srcIndices[ k ] ];
  498. vvdLength += srcIndices.Count() * sizeof( Vector4D );
  499. }
  500. vvdBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vvdBuffer.TellGet() + vvdLength - vvdBuffer.TellPut() );
  501. Log_Msg( LOG_ModelLib, " Stripped %d vvd bytes.\n", vvdLengthOld - vvdLength );
  502. return true;
  503. }
  504. //
  505. // StripOptimizedModelBuffer
  506. // The main function that strips the vtx buffer
  507. // vtxBuffer - vtx buffer, updated, size reduced
  508. //
  509. bool CMdlStripInfo::StripOptimizedModelBuffer( CUtlBuffer &vtxBuffer )
  510. {
  511. if ( m_eMode == MODE_UNINITIALIZED )
  512. return false;
  513. //
  514. // Recover vtx header
  515. //
  516. DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  517. int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
  518. if ( vtxHdr->checkSum != m_lChecksumOld )
  519. {
  520. Log_Msg( LOG_ModelLib, "ERROR: [StripOptimizedModelBuffer] checksum mismatch!\n" );
  521. return false;
  522. }
  523. vtxHdr->checkSum = m_lChecksumNew;
  524. // No remapping required
  525. if ( m_eMode == MODE_NO_CHANGE )
  526. return true;
  527. if ( m_eMode != MODE_STRIP_LOD_1N )
  528. return false;
  529. //
  530. // Do the optimized model buffer stripping
  531. //
  532. CUtlSortVector< unsigned short, CLessSimple< unsigned short > > &srcIndices = m_vtxIndices;
  533. CUtlSortVector< CMdlStripInfo::MdlRangeItem, CLessSimple< CMdlStripInfo::MdlRangeItem > > &arrMdlOffsets = m_vtxMdlOffsets;
  534. size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
  535. size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
  536. CMemoryMovingTracker vtxRemove( CMemoryMovingTracker::MEMORY_REMOVE );
  537. CUtlVector< size_t > vtxOffIndex;
  538. CUtlVector< size_t > vtxOffVertex;
  539. vtxRemove.RegisterElements( CHILD_AT( vtxHdr, pMaterialReplacementList, 1 ), vtxHdr->numLODs - 1 );
  540. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  541. if ( !vtxMatList_idx ) continue;
  542. vtxRemove.RegisterElements( CHILD_AT( vtxMatList, pMaterialReplacement, 0 ), vtxMatList->numReplacements );
  543. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  544. char const *szName = vtxMat->pMaterialReplacementName();
  545. vtxRemove.RegisterElements( szName, szName ? strlen( szName ) + 1 : 0 );
  546. ITERATE_END
  547. ITERATE_END
  548. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  549. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  550. vtxRemove.RegisterElements( CHILD_AT( vtxModel, pLOD, 1 ), vtxModel->numLODs - 1 );
  551. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  552. if ( !vtxLod_idx ) // Process only lod1-N
  553. continue;
  554. vtxRemove.RegisterElements( CHILD_AT( vtxLod, pMesh, 0 ), vtxLod->numMeshes );
  555. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  556. vtxRemove.RegisterElements( CHILD_AT( vtxMesh, pStripGroup, 0 ), vtxMesh->numStripGroups );
  557. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  558. vtxRemove.RegisterElements( CHILD_AT( vtxStripGroup, pStrip, 0 ), vtxStripGroup->numStrips );
  559. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  560. vtxRemove.RegisterElements( CHILD_AT( vtxStrip, pBoneStateChange, 0 ), vtxStrip->numBoneStateChanges );
  561. ITERATE_END
  562. ITERATE_END
  563. ITERATE_END
  564. ITERATE_END
  565. // Use all lods to determine the ranges of vertex and index buffers.
  566. // We rely on the fact that vertex and index buffers are laid out as one solid memory block for all lods.
  567. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  568. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  569. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  570. size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
  571. size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
  572. size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
  573. size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
  574. if ( offIndex < vtxOffIndexBuffer )
  575. vtxOffIndexBuffer = offIndex;
  576. if ( offIndexEnd > vtxOffIndexBufferEnd )
  577. vtxOffIndexBufferEnd = offIndexEnd;
  578. if ( offVertex < vtxOffVertexBuffer )
  579. vtxOffVertexBuffer = offVertex;
  580. if ( offVertexEnd > vtxOffVertexBufferEnd )
  581. vtxOffVertexBufferEnd = offVertexEnd;
  582. if ( !vtxLod_idx )
  583. {
  584. vtxOffIndex.AddToTail( offIndex );
  585. vtxOffIndex.AddToTail( offIndexEnd );
  586. vtxOffVertex.AddToTail( offVertex );
  587. vtxOffVertex.AddToTail( offVertexEnd );
  588. }
  589. ITERATE_END
  590. ITERATE_END
  591. ITERATE_END
  592. ITERATE_END
  593. ITERATE_END
  594. // Fixup the vertex buffer
  595. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBuffer ) );
  596. DECLARE_PTR( OptimizedModel::Vertex_t, vtxVertexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffVertexBufferEnd ) );
  597. CUtlVector< int > vtxIndexDeltas;
  598. vtxIndexDeltas.EnsureCapacity( vtxVertexBufferEnd - vtxVertexBuffer );
  599. int vtxNumVertexRemoved = 0;
  600. for ( OptimizedModel::Vertex_t *vtxVertexElement = vtxVertexBuffer; vtxVertexElement < vtxVertexBufferEnd; ++ vtxVertexElement )
  601. {
  602. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxVertexElement );
  603. bool bUsed = false;
  604. for ( int k = 0; k < vtxOffVertex.Count(); k += 2 )
  605. {
  606. if ( off >= vtxOffVertex[ k ] && off < vtxOffVertex[ k + 1 ] )
  607. {
  608. bUsed = true;
  609. break;
  610. }
  611. }
  612. if ( !bUsed )
  613. {
  614. // Index is not in use
  615. vtxRemove.RegisterElements( vtxVertexElement );
  616. vtxIndexDeltas.AddToTail( 0 );
  617. vtxNumVertexRemoved ++;
  618. }
  619. else
  620. { // Index is in use and must be remapped
  621. // Find the mesh where this index belongs
  622. int iMesh = arrMdlOffsets.FindLessOrEqual( MdlRangeItem( 0, 0, vtxVertexElement - vtxVertexBuffer ) );
  623. Assert( iMesh >= 0 && iMesh < arrMdlOffsets.Count() );
  624. MdlRangeItem &mri = arrMdlOffsets[ iMesh ];
  625. Assert( ( vtxVertexElement - vtxVertexBuffer >= mri.m_offNew ) && ( vtxVertexElement - vtxVertexBuffer < mri.m_offNew + mri.m_numNew ) );
  626. Assert( m_vtxVerts.IsBitSet( vtxVertexElement->origMeshVertID + mri.m_offOld ) );
  627. vtxVertexElement->origMeshVertID = srcIndices.Find( vtxVertexElement->origMeshVertID + mri.m_offOld ) - mri.m_offNew;
  628. Assert( vtxVertexElement->origMeshVertID < mri.m_numNew );
  629. vtxIndexDeltas.AddToTail( vtxNumVertexRemoved );
  630. }
  631. }
  632. // Fixup the index buffer
  633. DECLARE_PTR( unsigned short, vtxIndexBuffer, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBuffer ) );
  634. DECLARE_PTR( unsigned short, vtxIndexBufferEnd, BYTE_OFF_PTR( vtxHdr, vtxOffIndexBufferEnd ) );
  635. for ( unsigned short *vtxIndexElement = vtxIndexBuffer; vtxIndexElement < vtxIndexBufferEnd; ++ vtxIndexElement )
  636. {
  637. size_t const off = BYTE_DIFF_PTR( vtxHdr, vtxIndexElement );
  638. bool bUsed = false;
  639. for ( int k = 0; k < vtxOffIndex.Count(); k += 2 )
  640. {
  641. if ( off >= vtxOffIndex[ k ] && off < vtxOffIndex[ k + 1 ] )
  642. {
  643. bUsed = true;
  644. break;
  645. }
  646. }
  647. if ( !bUsed )
  648. {
  649. // Index is not in use
  650. vtxRemove.RegisterElements( vtxIndexElement );
  651. }
  652. else
  653. {
  654. // Index is in use and must be remapped
  655. *vtxIndexElement -= vtxIndexDeltas[ *vtxIndexElement ];
  656. }
  657. }
  658. // By now should have scheduled all removal information
  659. vtxRemove.Finalize();
  660. Log_Msg( LOG_ModelLib, " Stripped %d vtx bytes.\n", vtxRemove.GetNumBytesRegistered() );
  661. //
  662. // Fixup all the offsets
  663. //
  664. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  665. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  666. vtxMat->replacementMaterialNameOffset = vtxRemove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
  667. ITERATE_END
  668. vtxMatList->replacementOffset = vtxRemove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
  669. ITERATE_END
  670. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  671. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  672. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  673. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  674. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  675. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  676. vtxStrip->indexOffset =
  677. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
  678. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  679. vtxStrip->vertOffset =
  680. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
  681. vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  682. vtxStrip->boneStateChangeOffset = vtxRemove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
  683. ITERATE_END
  684. vtxStripGroup->vertOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  685. vtxStripGroup->indexOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  686. vtxStripGroup->stripOffset = vtxRemove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
  687. ITERATE_END
  688. vtxMesh->stripGroupHeaderOffset = vtxRemove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
  689. ITERATE_END
  690. vtxLod->meshOffset = vtxRemove.ComputeOffset( vtxLod, vtxLod->meshOffset );
  691. ITERATE_END
  692. vtxModel->lodOffset = vtxRemove.ComputeOffset( vtxModel, vtxModel->lodOffset );
  693. vtxModel->numLODs = 1;
  694. ITERATE_END
  695. vtxBodyPart->modelOffset = vtxRemove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
  696. ITERATE_END
  697. vtxHdr->materialReplacementListOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
  698. vtxHdr->bodyPartOffset = vtxRemove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
  699. vtxHdr->numLODs = 1;
  700. // Perform final memory move
  701. vtxRemove.MemMove( vtxHdr, vtxLength );
  702. vtxBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, vtxBuffer.TellGet() + vtxLength - vtxBuffer.TellPut() );
  703. return true;
  704. }
  705. //////////////////////////////////////////////////////////////////////////
  706. //
  707. // Auxilliary methods
  708. //
  709. //////////////////////////////////////////////////////////////////////////
  710. void CMdlStripInfo::DeleteThis()
  711. {
  712. delete this;
  713. }
  714. void CMdlStripInfo::Reset()
  715. {
  716. m_eMode = MODE_UNINITIALIZED;
  717. m_lChecksumOld = 0;
  718. m_lChecksumNew = 0;
  719. m_vtxVerts.Resize( 0 );
  720. m_vtxIndices.RemoveAll();
  721. m_ps3studioBatches.PurgeAndDeleteElements();
  722. }