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.

1013 lines
46 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. #include "edge/libedgegeomtool/libedgegeomtool.h"
  13. #include "vjobs/ibmarkup_shared.h"
  14. DECLARE_LOGGING_CHANNEL( LOG_ModelLib );
  15. #define DmaTagsListSize2(var) ( (var)[0] + (var)[1] )
  16. #define DmaTagsListSize3(var) ( DmaTagsListSize2(var) + (var)[2] )
  17. static void Helper_SwapInsideIndexBuffer_forPs3( void *pvMemory, uint32 uiSize )
  18. {
  19. uint16 *puiMemory = reinterpret_cast< uint16 * >( pvMemory );
  20. uiSize /= 2;
  21. for ( uint32 j = 0; j < uiSize/2; ++ j )
  22. {
  23. uint16 uiTemp = puiMemory[j];
  24. puiMemory[j] = puiMemory[ uiSize - j - 1 ];
  25. puiMemory[ uiSize - j - 1 ] = uiTemp;
  26. }
  27. }
  28. static void Helper_SwapOptimizedIndexBufferMarkup_forPs3( OptimizedModel::OptimizedIndexBufferMarkupPs3_t *pMarkup )
  29. {
  30. for ( int j = 0; j < pMarkup->m_numPartitions; ++ j )
  31. {
  32. OptimizedModel::OptimizedIndexBufferMarkupPs3_t::Partition_t &partition = pMarkup->m_partitions[j];
  33. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_numIndicesToSkipInIBs, sizeof( partition.m_numIndicesToSkipInIBs ) );
  34. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_numVerticesToSkipInVBs, sizeof( partition.m_numVerticesToSkipInVBs ) );
  35. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_nIoBufferSize, sizeof( partition.m_nIoBufferSize ) );
  36. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_numIndices, sizeof( partition.m_numIndices ) );
  37. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_numVertices, sizeof( partition.m_numVertices ) );
  38. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_nEdgeDmaInputIdx, sizeof( partition.m_nEdgeDmaInputIdx ) );
  39. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_nEdgeDmaInputVtx, sizeof( partition.m_nEdgeDmaInputVtx ) );
  40. Helper_SwapInsideIndexBuffer_forPs3( &partition.m_nEdgeDmaInputEnd, sizeof( partition.m_nEdgeDmaInputEnd ) );
  41. }
  42. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_uiHeaderCookie, sizeof( pMarkup->m_uiHeaderCookie ) );
  43. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_uiVersionFlags, sizeof( pMarkup->m_uiVersionFlags ) );
  44. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_numBytesMarkup, sizeof( pMarkup->m_numBytesMarkup ) );
  45. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_numPartitions, sizeof( pMarkup->m_numPartitions ) );
  46. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_numIndicesTotal, sizeof( pMarkup->m_numIndicesTotal ) );
  47. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_numVerticesTotal, sizeof( pMarkup->m_numVerticesTotal ) );
  48. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_nEdgeDmaInputOffsetPerStripGroup, sizeof( pMarkup->m_nEdgeDmaInputOffsetPerStripGroup ) );
  49. Helper_SwapInsideIndexBuffer_forPs3( &pMarkup->m_nEdgeDmaInputSizePerStripGroup, sizeof( pMarkup->m_nEdgeDmaInputSizePerStripGroup ) );
  50. }
  51. struct ModelBatchKey_t
  52. {
  53. ModelBatchKey_t() { V_memset( this, 0, sizeof( *this ) ); }
  54. ModelBatchKey_t( int bp, int mdl, int lod, int mesh, int sgroup, int strip) { V_memset( this, 0, sizeof( *this ) ); iBodyPart = bp; iModel = mdl; iLod = lod; iMesh = mesh; iStripGroup = sgroup; iStrip = strip; }
  55. ModelBatchKey_t( ModelBatchKey_t const & x ) { V_memcpy( this, &x, sizeof( *this ) ); }
  56. ModelBatchKey_t& operator=( ModelBatchKey_t const &x ) { if ( &x != this ) V_memcpy( this, &x, sizeof( *this ) ); return *this; }
  57. int iBodyPart;
  58. int iModel;
  59. int iLod;
  60. int iMesh;
  61. int iStripGroup;
  62. int iStrip;
  63. bool operator <( ModelBatchKey_t const &x ) const { return V_memcmp( this, &x, sizeof( *this ) ) < 0; }
  64. };
  65. //
  66. // StripModelBuffers
  67. // The main function that strips the model buffers
  68. // mdlBuffer - mdl buffer, updated, no size change
  69. // vvdBuffer - vvd buffer, updated, size reduced
  70. // vtxBuffer - vtx buffer, updated, size reduced
  71. // ppStripInfo - if nonzero on return will be filled with the stripping info
  72. //
  73. bool CMdlLib::PrepareModelForPs3( CUtlBuffer &mdlBuffer, CUtlBuffer &vvdBuffer, CUtlBuffer &vtxBuffer, IMdlStripInfo **ppStripInfo )
  74. {
  75. DECLARE_PTR( byte, mdl, BYTE_OFF_PTR( mdlBuffer.Base(), mdlBuffer.TellGet() ) );
  76. DECLARE_PTR( byte, vvd, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  77. DECLARE_PTR( byte, vtx, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  78. int vvdLength = vvdBuffer.TellPut() - vvdBuffer.TellGet();
  79. int vtxLength = vtxBuffer.TellPut() - vtxBuffer.TellGet();
  80. //
  81. // ===================
  82. // =================== Modify the checksum and check if further processing is needed
  83. // ===================
  84. //
  85. DECLARE_PTR( studiohdr_t, mdlHdr, mdl );
  86. DECLARE_PTR( vertexFileHeader_t, vvdHdr, vvd );
  87. DECLARE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
  88. long checksumOld = mdlHdr->checksum;
  89. // Don't do anything if the checksums don't match
  90. if ( ( mdlHdr->checksum != vvdHdr->checksum ) ||
  91. ( mdlHdr->checksum != vtxHdr->checkSum ) )
  92. {
  93. Log_Msg( LOG_ModelLib, "ERROR: [PrepareModelForPs3] checksum mismatch!\n" );
  94. return false;
  95. }
  96. // Modify the checksums
  97. mdlHdr->checksum ^= ( mdlHdr->checksum * 123333 );
  98. vvdHdr->checksum ^= ( vvdHdr->checksum * 123333 );
  99. vtxHdr->checkSum ^= ( vtxHdr->checkSum * 123333 );
  100. long checksumNew = mdlHdr->checksum;
  101. // Allocate the model stripping info
  102. CMdlStripInfo msi;
  103. CMdlStripInfo *pMsi;
  104. if ( ppStripInfo )
  105. {
  106. if ( *ppStripInfo )
  107. {
  108. pMsi = ( CMdlStripInfo * ) ( *ppStripInfo );
  109. pMsi->Reset();
  110. }
  111. else
  112. {
  113. *ppStripInfo = pMsi = new CMdlStripInfo;
  114. }
  115. }
  116. else
  117. {
  118. pMsi = &msi;
  119. }
  120. // Set the basic stripping info settings
  121. pMsi->m_lChecksumOld = checksumOld;
  122. pMsi->m_lChecksumNew = checksumNew;
  123. mdlHdr->flags &= ~STUDIOHDR_FLAGS_PS3_EDGE_FORMAT;
  124. if ( !vvdHdr->numFixups )
  125. vvdHdr->fixupTableStart = 0;
  126. //
  127. // Early outs
  128. //
  129. if ( mdlHdr->numbones != 1 )
  130. {
  131. Log_Msg( LOG_ModelLib, "No special stripping - the model has %d bone(s).\n", mdlHdr->numbones );
  132. pMsi->m_eMode = CMdlStripInfo::MODE_PS3_FORMAT_BASIC;
  133. return true;
  134. }
  135. if ( CommandLine()->FindParm( "-mdllib_ps3_noedge" ) )
  136. {
  137. pMsi->m_eMode = CMdlStripInfo::MODE_PS3_FORMAT_BASIC;
  138. return true;
  139. }
  140. bool const bEmitIndices = !!CommandLine()->FindParm( "-mdllib_ps3_edgeidxbuf" );
  141. bool const bUncompressedIndices = !!CommandLine()->FindParm( "-mdllib_ps3_edgeidxbufUncompressed" );
  142. bool const bUncompressedVertices = true || !!CommandLine()->FindParm( "-mdllib_ps3_edgevtxbufUncompressed" );
  143. struct EdgeGeomFreeMemoryTracker_t : public CUtlVector< void * >
  144. {
  145. ~EdgeGeomFreeMemoryTracker_t() { for ( int k = 0; k < Count(); ++ k ) if ( void *p = Element( k ) ) edgeGeomFree( p ); }
  146. } ps3edgeGeomFreeMemoryTracker;
  147. // Otherwise do stripping
  148. pMsi->m_eMode = CMdlStripInfo::MODE_PS3_PARTITIONS;
  149. mdlHdr->flags |= STUDIOHDR_FLAGS_PS3_EDGE_FORMAT;
  150. CByteswap ps3byteswap;
  151. ps3byteswap.SetTargetBigEndian( true ); // PS3 target is big-endian
  152. //
  153. // ===================
  154. // =================== Build out table of LODx vertexes
  155. // ===================
  156. //
  157. CUtlVector< CMdlStripInfo::Ps3studioBatch_t * > &ps3studioBatches = pMsi->m_ps3studioBatches;
  158. typedef CUtlMap< ModelBatchKey_t, int > ModelBatch2idx;
  159. ModelBatch2idx mapMBI( DefLessFunc( ModelBatchKey_t ) );
  160. uint32 numVhvOriginalModelVertices = 0;
  161. {
  162. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  163. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  164. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  165. if ( ( mdlModel->vertexindex%sizeof( mstudiovertex_t ) ) ||
  166. ( mdlModel->tangentsindex%sizeof( Vector4D ) ) ||
  167. ( (mdlModel->vertexindex/sizeof( mstudiovertex_t )) != (mdlModel->tangentsindex/sizeof( Vector4D )) ) )
  168. {
  169. Error( "PrepareModelForPs3: invalid model setup [mdlModel_idx=%d]!\n", vtxModel_idx );
  170. }
  171. uint32 uiModelIndexOffset = (mdlModel->vertexindex/sizeof( mstudiovertex_t ));
  172. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  173. ITERATE_CHILDREN2( OptimizedModel::MeshHeader_t, mstudiomesh_t, vtxMesh, mdlMesh, vtxLod, mdlModel, pMesh, pMesh, numMeshes )
  174. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  175. pMsi->m_ps3studioStripGroupHeaderBatchOffset.AddToTail( ps3studioBatches.Count() );
  176. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  177. //
  178. // Compute triangle indices list for edge
  179. //
  180. if( ( vtxStrip->numIndices % 3 ) != 0 )
  181. {
  182. Error( "PrepareModelForPs3: invalid number of indices/3! [%d]\n", vtxStrip->numIndices );
  183. }
  184. CUtlVector< uint32 > arrEdgeInputIndices;
  185. CUtlVector< uint32 > arrStripLocalEdgeInputIndex;
  186. arrEdgeInputIndices.SetCount( vtxStrip->numIndices );
  187. arrStripLocalEdgeInputIndex.EnsureCapacity( vtxStrip->numIndices );
  188. for ( int i = 0; i < vtxStrip->numIndices; ++ i )
  189. {
  190. unsigned short *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset + i );
  191. OptimizedModel::Vertex_t *vtxVertex = CHILD_AT( vtxStripGroup, pVertex, *vtxIdx );
  192. uint32 uiInputIdx = vtxVertex->origMeshVertID + mdlMesh->vertexoffset;
  193. arrEdgeInputIndices[i] = uiInputIdx;
  194. if ( arrStripLocalEdgeInputIndex.Count() <= uiInputIdx )
  195. arrStripLocalEdgeInputIndex.SetCountNonDestructively( uiInputIdx + 1 );
  196. arrStripLocalEdgeInputIndex[uiInputIdx] = *vtxIdx;
  197. }
  198. //
  199. // Compute triangle centroids for the batch
  200. //
  201. float *pEdgeTriangleCentroids = NULL;
  202. float *flModelSourceVertices = reinterpret_cast< float * >( vvdVertexSrc ) + uiModelIndexOffset;
  203. uint16 uiModelSourceVerticesPositionIdx = reinterpret_cast< float * >( &vvdVertexSrc->m_vecPosition.x ) - reinterpret_cast< float * >( vvdVertexSrc );
  204. edgeGeomComputeTriangleCentroids(
  205. flModelSourceVertices, sizeof( mstudiovertex_t ) / sizeof( float ),
  206. uiModelSourceVerticesPositionIdx,
  207. arrEdgeInputIndices.Base(),
  208. vtxStrip->numIndices / 3,
  209. &pEdgeTriangleCentroids
  210. );
  211. //
  212. // Let EDGE tool framework perform partitioning of our studio batch
  213. //
  214. EdgeGeomPartitionerInput egpi;
  215. egpi.m_numTriangles = vtxStrip->numIndices / 3;
  216. egpi.m_triangleList = arrEdgeInputIndices.Base();
  217. egpi.m_numInputAttributes = 1;
  218. egpi.m_numOutputAttributes = 0;
  219. egpi.m_inputVertexStride[0] = 12;
  220. egpi.m_inputVertexStride[1] = 0;
  221. egpi.m_outputVertexStride = 0;
  222. egpi.m_skinningFlavor = kSkinNone;
  223. egpi.m_indexListFlavor = kIndexesU16TriangleListCW;
  224. egpi.m_skinningMatrixFormat = kMatrix4x4RowMajor;
  225. egpi.m_cacheOptimizerCallback = CommandLine()->FindParm( "-mdllib_ps3_edgenokcache" ) ? 0 : edgeGeomKCacheOptimizerHillclimber;
  226. EdgeGeomKCacheOptimizerHillclimberUserData edgeCacheOptimizerUserData =
  227. {
  228. 400, // iterations (100 iterations give about 1% improvement)
  229. kIndexesU16TriangleListCW, // indexes type
  230. 1, 0 // RSX input and output attributes count
  231. };
  232. egpi.m_cacheOptimizerUserData = &edgeCacheOptimizerUserData;
  233. egpi.m_customDataSizeCallback = NULL;
  234. egpi.m_triangleCentroids = pEdgeTriangleCentroids;
  235. egpi.m_skinningMatrixIndexesPerVertex = NULL; // no skinning
  236. egpi.m_deltaStreamVertexStride = 0; // no blendshapes
  237. egpi.m_blendedVertexIndexes = NULL; // no skinning
  238. egpi.m_numBlendedVertexes = 0; // no blendshapes
  239. egpi.m_customCommandBufferHoleSizeCallback = 0; // no custom data
  240. // Partition our geometry
  241. EdgeGeomPartitionerOutput egpo;
  242. edgeGeomPartitioner( egpi, &egpo );
  243. //
  244. // Represent partitioned geometry as mdllib batch description
  245. //
  246. CMdlStripInfo::Ps3studioBatch_t *ps3studioBatch = new CMdlStripInfo::Ps3studioBatch_t;
  247. ps3studioBatch->m_uiModelIndexOffset = uiModelIndexOffset;
  248. ps3studioBatch->m_uiVhvIndexOffset = numVhvOriginalModelVertices;
  249. int iBatchIdx = ps3studioBatches.AddToTail( ps3studioBatch );
  250. ModelBatchKey_t mbk( vtxBodyPart_idx, vtxModel_idx, vtxLod_idx, vtxMesh_idx, vtxStripGroup_idx, vtxStrip_idx );
  251. Assert( mapMBI.Find( mbk ) == mapMBI.InvalidIndex() );
  252. mapMBI.Insert( mbk, iBatchIdx );
  253. EdgeGeomPartitionerOutput egpoConsumable = egpo;
  254. while ( egpoConsumable.m_numPartitions -- > 0 )
  255. {
  256. CMdlStripInfo::Ps3studioPartition_t *ps3partition = new CMdlStripInfo::Ps3studioPartition_t;
  257. ps3studioBatch->m_arrPartitions.AddToTail( ps3partition );
  258. ps3partition->m_nIoBufferSize = * ( egpoConsumable.m_ioBufferSizePerPartition ++ );
  259. ps3partition->m_arrLocalIndices.EnsureCapacity( *egpoConsumable.m_numTrianglesPerPartition );
  260. // Compress index information
  261. edgeGeomMakeIndexBuffer( egpoConsumable.m_triangleListOut, *egpoConsumable.m_numTrianglesPerPartition,
  262. kIndexesCompressedTriangleListCW,
  263. &ps3partition->m_pEdgeCompressedIdx, ps3partition->m_uiEdgeCompressedIdxDmaTagSize );
  264. ps3edgeGeomFreeMemoryTracker.AddToTail( ps3partition->m_pEdgeCompressedIdx );
  265. // Compress vertex information
  266. EdgeGeomAttributeId edgeGeomAttributeIdSpuVB[1] = { EDGE_GEOM_ATTRIBUTE_ID_POSITION };
  267. uint16 edgeGeomAttributeIndexSpuVB[1] = { uiModelSourceVerticesPositionIdx };
  268. EdgeGeomSpuVertexFormat edgeGeomSpuVertexFmt;
  269. V_memset( &edgeGeomSpuVertexFmt, 0, sizeof( edgeGeomSpuVertexFmt ) );
  270. edgeGeomSpuVertexFmt.m_numAttributes = 1;
  271. edgeGeomSpuVertexFmt.m_vertexStride = 3 * 16 / 8; // compressing to 16-bit
  272. {
  273. EdgeGeomSpuVertexAttributeDefinition &attr = edgeGeomSpuVertexFmt.m_attributeDefinition[0];
  274. attr.m_type = kSpuAttr_FixedPoint;
  275. attr.m_count = 3;
  276. attr.m_attributeId = EDGE_GEOM_ATTRIBUTE_ID_POSITION;
  277. attr.m_byteOffset = 0;
  278. attr.m_fixedPointBitDepthInteger[0] = 0;
  279. attr.m_fixedPointBitDepthInteger[1] = 0;
  280. attr.m_fixedPointBitDepthInteger[2] = 0;
  281. attr.m_fixedPointBitDepthFractional[0] = 16;
  282. attr.m_fixedPointBitDepthFractional[1] = 16;
  283. attr.m_fixedPointBitDepthFractional[2] = 16;
  284. }
  285. edgeGeomMakeSpuVertexBuffer( flModelSourceVertices, sizeof( mstudiovertex_t ) / sizeof( float ),
  286. edgeGeomAttributeIndexSpuVB, edgeGeomAttributeIdSpuVB, 1,
  287. egpoConsumable.m_originalVertexIndexesPerPartition, *egpoConsumable.m_numUniqueVertexesPerPartition,
  288. edgeGeomSpuVertexFmt, &ps3partition->m_pEdgeCompressedVtx, ps3partition->m_uiEdgeCompressedVtxDmaTagSize,
  289. &ps3partition->m_pEdgeCompressedVtxFixedOffsets, &ps3partition->m_uiEdgeCompressedVtxFixedOffsetsSize );
  290. ps3edgeGeomFreeMemoryTracker.AddToTail( ps3partition->m_pEdgeCompressedVtx );
  291. ps3edgeGeomFreeMemoryTracker.AddToTail( ps3partition->m_pEdgeCompressedVtxFixedOffsets );
  292. // Copy index buffer to partition data
  293. while ( ( *egpoConsumable.m_numTrianglesPerPartition ) -- > 0 )
  294. {
  295. for ( int kTriangleIndex = 0; kTriangleIndex < 3; ++ kTriangleIndex )
  296. {
  297. uint32 uiEgpoIndex = * ( egpoConsumable.m_triangleListOut ++ );
  298. if ( uiEgpoIndex > 0xFFFE )
  299. {
  300. Error( "PrepareModelForPs3: index in partition exceeding 0xFFFE! [%u]\n", uiEgpoIndex );
  301. }
  302. ps3partition->m_arrLocalIndices.AddToTail( uiEgpoIndex );
  303. }
  304. }
  305. egpoConsumable.m_numTrianglesPerPartition ++;
  306. ps3partition->m_arrVertOriginalIndices.EnsureCapacity( *egpoConsumable.m_numUniqueVertexesPerPartition );
  307. while ( ( *egpoConsumable.m_numUniqueVertexesPerPartition ) -- > 0 )
  308. {
  309. uint32 uiEgpoIndex = * ( egpoConsumable.m_originalVertexIndexesPerPartition ++ );
  310. ps3partition->m_arrVertOriginalIndices.AddToTail( uiEgpoIndex );
  311. ps3partition->m_arrStripLocalOriginalIndices.AddToTail( arrStripLocalEdgeInputIndex[uiEgpoIndex] );
  312. }
  313. egpoConsumable.m_numUniqueVertexesPerPartition ++;
  314. }
  315. //
  316. // Free EDGE memory
  317. //
  318. edgeGeomFree( pEdgeTriangleCentroids );
  319. edgeGeomFree( egpo.m_numTrianglesPerPartition );
  320. edgeGeomFree( egpo.m_triangleListOut );
  321. edgeGeomFree( egpo.m_originalVertexIndexesPerPartition );
  322. edgeGeomFree( egpo.m_numUniqueVertexesPerPartition );
  323. edgeGeomFree( egpo.m_ioBufferSizePerPartition );
  324. ITERATE_END
  325. numVhvOriginalModelVertices += vtxStripGroup->numVerts;
  326. ITERATE_END
  327. ITERATE_END
  328. ITERATE_END
  329. ITERATE_END
  330. ITERATE_END
  331. }
  332. //
  333. // Now that we have partitions we need to extend index layouts of every strip
  334. // to account for special markup data describing the partitions layout.
  335. //
  336. uint32 numPartitions = 0, numVertices = 0, numEdgeDmaInputBytesTotal = 0;
  337. enum {
  338. kToolEdgeDmaAlignIdx = 16,
  339. kToolEdgeDmaAlignVtx = 16,
  340. kToolEdgeDmaAlignXfr = 16,
  341. kToolEdgeDmaAlignGlobal = (1<<8),
  342. };
  343. for ( int iBatch = 0; iBatch < ps3studioBatches.Count(); ++ iBatch )
  344. {
  345. CMdlStripInfo::Ps3studioBatch_t &batch = *ps3studioBatches[iBatch];
  346. numPartitions += batch.m_arrPartitions.Count();
  347. for ( int iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
  348. {
  349. CMdlStripInfo::Ps3studioPartition_t &partition = *batch.m_arrPartitions[iPartition];
  350. numVertices += partition.m_arrVertOriginalIndices.Count();
  351. // Must be IDX-aligned
  352. numEdgeDmaInputBytesTotal = AlignValue( numEdgeDmaInputBytesTotal, kToolEdgeDmaAlignIdx );
  353. // Edge will need all indices
  354. uint32 numBytesIndexStream = bUncompressedIndices ? ( sizeof( uint16 ) * partition.m_arrLocalIndices.Count() ) : DmaTagsListSize2( partition.m_uiEdgeCompressedIdxDmaTagSize );
  355. numEdgeDmaInputBytesTotal += numBytesIndexStream;
  356. if ( !bUncompressedVertices && partition.m_pEdgeCompressedVtxFixedOffsets && partition.m_uiEdgeCompressedVtxFixedOffsetsSize )
  357. {
  358. // Must be VTX-aligned
  359. numEdgeDmaInputBytesTotal = AlignValue( numEdgeDmaInputBytesTotal, kToolEdgeDmaAlignVtx );
  360. numEdgeDmaInputBytesTotal += partition.m_uiEdgeCompressedVtxFixedOffsetsSize;
  361. }
  362. // Must be VTX-aligned
  363. numEdgeDmaInputBytesTotal = AlignValue( numEdgeDmaInputBytesTotal, kToolEdgeDmaAlignVtx );
  364. // Edge will need all positions
  365. uint32 numBytesVertexStream = bUncompressedVertices ? 3 * sizeof( float ) * partition.m_arrVertOriginalIndices.Count() : DmaTagsListSize3( partition.m_uiEdgeCompressedVtxDmaTagSize );
  366. numEdgeDmaInputBytesTotal += numBytesVertexStream;
  367. // Must be XFR-aligned
  368. numEdgeDmaInputBytesTotal = AlignValue( numEdgeDmaInputBytesTotal, kToolEdgeDmaAlignXfr );
  369. }
  370. }
  371. // Must be 256-byte aligned
  372. numEdgeDmaInputBytesTotal = AlignValue( numEdgeDmaInputBytesTotal, kToolEdgeDmaAlignGlobal );
  373. //
  374. // ===================
  375. // =================== Process MDL file
  376. // ===================
  377. //
  378. {
  379. int numCumulativeMeshVertices = 0;
  380. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  381. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  382. // need to update numvertices
  383. int update_studiomodel_numvertices = 0;
  384. mdlModel->vertexindex = numCumulativeMeshVertices * sizeof( mstudiovertex_t );
  385. mdlModel->tangentsindex = numCumulativeMeshVertices * sizeof( Vector4D );
  386. // Process each mesh separately (NOTE: loop reversed: MESH, then LOD)
  387. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
  388. // need to update numvertices
  389. int update_studiomesh_numvertices = 0;
  390. V_memset( mdlMesh->vertexdata.numLODVertexes, 0, sizeof( mdlMesh->vertexdata.numLODVertexes ) );
  391. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  392. if ( vtxLod->numMeshes <= mdlMesh_idx ) continue;
  393. OptimizedModel::MeshHeader_t *vtxMesh = vtxLod->pMesh( mdlMesh_idx );
  394. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  395. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips ) vtxStrip;
  396. CMdlStripInfo::Ps3studioBatch_t &batch = *ps3studioBatches[ mapMBI[ mapMBI.Find( ModelBatchKey_t( vtxBodyPart_idx, vtxModel_idx, vtxLod_idx, mdlMesh_idx, vtxStripGroup_idx, vtxStrip_idx ) ) ] ];
  397. int numBatchVertices = 0;
  398. for( int iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
  399. {
  400. numBatchVertices += batch.m_arrPartitions[iPartition]->m_arrVertOriginalIndices.Count();
  401. }
  402. update_studiomesh_numvertices += numBatchVertices;
  403. mdlMesh->vertexdata.numLODVertexes[ vtxLod_idx ] += numBatchVertices;
  404. ITERATE_END
  405. ITERATE_END
  406. ITERATE_END
  407. mdlMesh->numvertices = update_studiomesh_numvertices;
  408. numCumulativeMeshVertices += update_studiomesh_numvertices;
  409. mdlMesh->vertexoffset = update_studiomodel_numvertices;
  410. update_studiomodel_numvertices += update_studiomesh_numvertices;
  411. // Adjust LOD vertex counts
  412. for ( int iRootLodVertexes = MAX_NUM_LODS; iRootLodVertexes -- > 1; )
  413. {
  414. mdlMesh->vertexdata.numLODVertexes[iRootLodVertexes-1] += mdlMesh->vertexdata.numLODVertexes[iRootLodVertexes];
  415. }
  416. for ( int iRootLodVertexes = 0; iRootLodVertexes < MAX_NUM_LODS; ++ iRootLodVertexes )
  417. {
  418. if ( !mdlMesh->vertexdata.numLODVertexes[iRootLodVertexes] && iRootLodVertexes )
  419. mdlMesh->vertexdata.numLODVertexes[iRootLodVertexes] = mdlMesh->vertexdata.numLODVertexes[iRootLodVertexes-1];
  420. }
  421. ITERATE_END
  422. mdlModel->numvertices = update_studiomodel_numvertices;
  423. ITERATE_END
  424. ITERATE_END
  425. }
  426. //
  427. // ===================
  428. // =================== Process VVD file
  429. // ===================
  430. //
  431. DECLARE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  432. DECLARE_PTR( Vector4D, vvdTangentSrc, vvdHdr->tangentDataStart ? BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) : NULL );
  433. // Apply the fixups first of all
  434. if ( vvdHdr->numFixups )
  435. {
  436. CArrayAutoPtr< byte > memTempVVD( new byte[ vvdLength ] );
  437. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  438. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ) );
  439. DECLARE_PTR( vertexFileFixup_t, vvdFixup, BYTE_OFF_PTR( vvdHdr, vvdHdr->fixupTableStart ) );
  440. for ( int k = 0; k < vvdHdr->numFixups; ++ k )
  441. {
  442. memcpy( vvdVertexNew, vvdVertexSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdVertexNew ) );
  443. vvdVertexNew += vvdFixup[ k ].numVertexes;
  444. if ( vvdTangentSrc )
  445. {
  446. memcpy( vvdTangentNew, vvdTangentSrc + vvdFixup[ k ].sourceVertexID, vvdFixup[ k ].numVertexes * sizeof( *vvdTangentNew ) );
  447. vvdTangentNew += vvdFixup[ k ].numVertexes;
  448. }
  449. }
  450. // Move back the memory after fixups were applied
  451. vvdVertexSrc ? memcpy( vvdVertexSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ), vvdHdr->numLODVertexes[0] * sizeof( *vvdVertexSrc ) ) : 0;
  452. vvdTangentSrc ? memcpy( vvdTangentSrc, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->tangentDataStart ), vvdHdr->numLODVertexes[0] * sizeof( *vvdTangentSrc ) ) : 0;
  453. }
  454. vvdHdr->vertexDataStart -= ALIGN_VALUE( sizeof( vertexFileFixup_t ) * vvdHdr->numFixups, 16 );
  455. vvdHdr->numFixups = 0;
  456. if ( vvdHdr->id != MODEL_VERTEX_FILE_ID )
  457. Error( "PrepareModelForPs3: unsupported VVD structure!\n" );
  458. //
  459. // Now loop through batches and reorder vertices
  460. //
  461. {
  462. uint32 numNewVvdBufferBytesBase = vvdHdr->vertexDataStart + numVertices * sizeof( *vvdVertexSrc ) + ( vvdTangentSrc ? ( numVertices * sizeof( *vvdTangentSrc ) ) : 0 );
  463. numNewVvdBufferBytesBase = AlignValue( numNewVvdBufferBytesBase, 1 << 8 );
  464. uint32 numNewVvdBufferBytes = numNewVvdBufferBytesBase + numEdgeDmaInputBytesTotal;
  465. if ( ( numNewVvdBufferBytesBase >> 8 ) & ~0xFFFF )
  466. Error( "PrepareModelForPs3: VVD buffer DMA offset too large!\n" );
  467. if ( ( numEdgeDmaInputBytesTotal >> 8 ) & ~0x7FFF )
  468. Error( "PrepareModelForPs3: VVD buffer DMA size too large!\n" );
  469. if ( numEdgeDmaInputBytesTotal & 0xFF )
  470. Error( "PrepareModelForPs3: VVD buffer DMA size incorrect!\n" );
  471. vvdHdr->fixupTableStart = ( numNewVvdBufferBytesBase >> 8 ) | ( numEdgeDmaInputBytesTotal << 8 ) | 0x80000000;
  472. CArrayAutoPtr< byte > memTempVVD( new byte[ numNewVvdBufferBytes ] );
  473. for ( int k = 0; k < MAX_NUM_LODS; ++ k )
  474. vvdHdr->numLODVertexes[k] = numVertices; // Root LOD unsupported
  475. V_memcpy( memTempVVD.Get(), vvdHdr, vvdHdr->vertexDataStart );
  476. DECLARE_PTR( mstudiovertex_t, vvdVertexNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart ) );
  477. DECLARE_PTR( Vector4D, vvdTangentNew, BYTE_OFF_PTR( memTempVVD.Get(), vvdHdr->vertexDataStart + numVertices * sizeof( *vvdVertexSrc ) ) );
  478. DECLARE_PTR( uint8, vvdEdgeDmaInputNew, BYTE_OFF_PTR( memTempVVD.Get(), numNewVvdBufferBytesBase ) );
  479. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  480. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  481. // Process each mesh separately (NOTE: loop reversed: MESH, then LOD)
  482. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes ) mdlMesh;
  483. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  484. if ( vtxLod->numMeshes <= mdlMesh_idx ) continue;
  485. OptimizedModel::MeshHeader_t *vtxMesh = vtxLod->pMesh( mdlMesh_idx );
  486. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  487. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips ) vtxStrip;
  488. CMdlStripInfo::Ps3studioBatch_t &batch = *ps3studioBatches[ mapMBI[ mapMBI.Find( ModelBatchKey_t( vtxBodyPart_idx, vtxModel_idx, vtxLod_idx, mdlMesh_idx, vtxStripGroup_idx, vtxStrip_idx ) ) ] ];
  489. for( int iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
  490. {
  491. CMdlStripInfo::Ps3studioPartition_t &partition = *batch.m_arrPartitions[iPartition];
  492. // Must be IDX-aligned
  493. DECLARE_UPDATE_PTR( uint8, vvdEdgeDmaInputNew, BYTE_OFF_PTR( memTempVVD.Get(), AlignValue( BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ), kToolEdgeDmaAlignIdx ) ) );
  494. partition.m_nEdgeDmaInputIdx = BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ) - numNewVvdBufferBytesBase;
  495. // EDGE DMA INDEX DATA
  496. if ( bUncompressedIndices )
  497. {
  498. ps3byteswap.SwapBufferToTargetEndian<uint16>( (uint16*) vvdEdgeDmaInputNew,
  499. partition.m_arrLocalIndices.Base(), partition.m_arrLocalIndices.Count() );
  500. vvdEdgeDmaInputNew += partition.m_arrLocalIndices.Count() * sizeof( uint16 );
  501. }
  502. else
  503. {
  504. V_memcpy( vvdEdgeDmaInputNew, partition.m_pEdgeCompressedIdx, DmaTagsListSize2( partition.m_uiEdgeCompressedIdxDmaTagSize ) );
  505. vvdEdgeDmaInputNew += DmaTagsListSize2( partition.m_uiEdgeCompressedIdxDmaTagSize );
  506. }
  507. // Must be VTX-aligned
  508. DECLARE_UPDATE_PTR( uint8, vvdEdgeDmaInputNew, BYTE_OFF_PTR( memTempVVD.Get(), AlignValue( BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ), kToolEdgeDmaAlignVtx ) ) );
  509. partition.m_nEdgeDmaInputVtx = BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ) - numNewVvdBufferBytesBase;
  510. for ( int iOrigVert = 0; iOrigVert < partition.m_arrVertOriginalIndices.Count(); ++ iOrigVert )
  511. {
  512. uint32 uiOrigVertIdx = partition.m_arrVertOriginalIndices[iOrigVert];
  513. uiOrigVertIdx += batch.m_uiModelIndexOffset;
  514. memcpy( vvdVertexNew, vvdVertexSrc + uiOrigVertIdx, sizeof( *vvdVertexNew ) );
  515. ++ vvdVertexNew;
  516. if ( vvdTangentSrc )
  517. {
  518. memcpy( vvdTangentNew, vvdTangentSrc + uiOrigVertIdx, sizeof( *vvdTangentNew ) );
  519. ++ vvdTangentNew;
  520. }
  521. // EDGE DMA VERTEX DATA
  522. if ( bUncompressedVertices )
  523. {
  524. ps3byteswap.SwapBufferToTargetEndian<float>( (float*) vvdEdgeDmaInputNew,
  525. (float*) &vvdVertexSrc[uiOrigVertIdx].m_vecPosition.x, 3 );
  526. vvdEdgeDmaInputNew += 3 * sizeof( float );
  527. }
  528. }
  529. // EDGE DMA VERTEX DATA
  530. if ( !bUncompressedVertices )
  531. {
  532. if ( partition.m_pEdgeCompressedVtxFixedOffsets && partition.m_uiEdgeCompressedVtxFixedOffsetsSize )
  533. {
  534. V_memcpy( vvdEdgeDmaInputNew, partition.m_pEdgeCompressedVtxFixedOffsets, partition.m_uiEdgeCompressedVtxFixedOffsetsSize );
  535. vvdEdgeDmaInputNew += partition.m_uiEdgeCompressedVtxFixedOffsetsSize;
  536. DECLARE_UPDATE_PTR( uint8, vvdEdgeDmaInputNew, BYTE_OFF_PTR( memTempVVD.Get(), AlignValue( BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ), kToolEdgeDmaAlignVtx ) ) );
  537. }
  538. V_memcpy( vvdEdgeDmaInputNew, partition.m_pEdgeCompressedVtx, DmaTagsListSize3( partition.m_uiEdgeCompressedVtxDmaTagSize ) );
  539. vvdEdgeDmaInputNew += DmaTagsListSize3( partition.m_uiEdgeCompressedVtxDmaTagSize );
  540. }
  541. // Must be XFR-aligned
  542. DECLARE_UPDATE_PTR( uint8, vvdEdgeDmaInputNew, BYTE_OFF_PTR( memTempVVD.Get(), AlignValue( BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ), kToolEdgeDmaAlignXfr ) ) );
  543. partition.m_nEdgeDmaInputEnd = BYTE_DIFF_PTR( memTempVVD.Get(), vvdEdgeDmaInputNew ) - numNewVvdBufferBytesBase;
  544. Assert( vvdEdgeDmaInputNew <= BYTE_OFF_PTR( memTempVVD.Get(), numNewVvdBufferBytes ) );
  545. }
  546. ITERATE_END
  547. ITERATE_END
  548. ITERATE_END
  549. ITERATE_END
  550. ITERATE_END
  551. ITERATE_END
  552. //
  553. // Copy back the newly created VVD buffer
  554. //
  555. vvdBuffer.EnsureCapacity( numNewVvdBufferBytes + vvdBuffer.TellGet() );
  556. V_memcpy( BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ), memTempVVD.Get(), numNewVvdBufferBytes );
  557. vvdBuffer.SeekPut( vvdBuffer.SEEK_HEAD, vvdBuffer.TellGet() + numNewVvdBufferBytes );
  558. Log_Msg( LOG_ModelLib, " Increased VVD size by %d bytes.\n", numNewVvdBufferBytes - vvdLength );
  559. // Since we could have caused a buffer reallocation, update cached pointers and values
  560. DECLARE_UPDATE_PTR( byte, vvd, BYTE_OFF_PTR( vvdBuffer.Base(), vvdBuffer.TellGet() ) );
  561. DECLARE_UPDATE_PTR( vertexFileHeader_t, vvdHdr, vvd );
  562. DECLARE_UPDATE_PTR( mstudiovertex_t, vvdVertexSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->vertexDataStart ) );
  563. if ( vvdTangentSrc )
  564. {
  565. vvdHdr->tangentDataStart = vvdHdr->vertexDataStart + numVertices * sizeof( *vvdVertexSrc );
  566. DECLARE_UPDATE_PTR( Vector4D, vvdTangentSrc, BYTE_OFF_PTR( vvdHdr, vvdHdr->tangentDataStart ) );
  567. }
  568. vvdLength = numNewVvdBufferBytes;
  569. }
  570. //
  571. // ===================
  572. // =================== Process VTX file
  573. // ===================
  574. //
  575. size_t vtxOffIndexBuffer = ~size_t(0), vtxOffIndexBufferEnd = 0;
  576. size_t vtxOffVertexBuffer = ~size_t(0), vtxOffVertexBufferEnd = 0;
  577. CMemoryMovingTracker vtxMemMove( CMemoryMovingTracker::MEMORY_MODIFY );
  578. {
  579. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  580. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  581. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  582. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  583. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  584. size_t offIndex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, 0 ) );
  585. size_t offIndexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pIndex, vtxStripGroup->numIndices ) );
  586. size_t offVertex = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, 0 ) );
  587. size_t offVertexEnd = BYTE_DIFF_PTR( vtxHdr, CHILD_AT( vtxStripGroup, pVertex, vtxStripGroup->numVerts ) );
  588. if ( offIndex < vtxOffIndexBuffer )
  589. vtxOffIndexBuffer = offIndex;
  590. if ( offIndexEnd > vtxOffIndexBufferEnd )
  591. vtxOffIndexBufferEnd = offIndexEnd;
  592. if ( offVertex < vtxOffVertexBuffer )
  593. vtxOffVertexBuffer = offVertex;
  594. if ( offVertexEnd > vtxOffVertexBufferEnd )
  595. vtxOffVertexBufferEnd = offVertexEnd;
  596. uint32 uiNumVertsInStripGroupUpdate = 0;
  597. uint32 uiNumIndicesInStripGroupUpdate = 0;
  598. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  599. CMdlStripInfo::Ps3studioBatch_t &batch = *ps3studioBatches[ mapMBI[ mapMBI.Find( ModelBatchKey_t( vtxBodyPart_idx, vtxModel_idx, vtxLod_idx, vtxMesh_idx, vtxStripGroup_idx, vtxStrip_idx ) ) ] ];
  600. uint16 *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset );
  601. uint32 uiNumExtraBytes = sizeof( OptimizedModel::OptimizedIndexBufferMarkupPs3_t ) +
  602. batch.m_arrPartitions.Count() * sizeof( OptimizedModel::OptimizedIndexBufferMarkupPs3_t::Partition_t );
  603. uiNumExtraBytes = ( ( uiNumExtraBytes + 5 ) / 6 ) * 6; // make it even number of 3 indices
  604. vtxStrip->numVerts = 0; // Since we are not adjusting the verts here properly, zero them out
  605. uint32 uiNumIndicesInPartitions = 0;
  606. for ( int k = 0; k < batch.m_arrPartitions.Count(); ++ k )
  607. {
  608. uiNumIndicesInPartitions += batch.m_arrPartitions[k]->m_arrLocalIndices.Count();
  609. uiNumVertsInStripGroupUpdate += batch.m_arrPartitions[k]->m_arrVertOriginalIndices.Count();
  610. }
  611. uiNumIndicesInStripGroupUpdate += uiNumExtraBytes / sizeof( uint16 ) + ( bEmitIndices ? uiNumIndicesInPartitions : 0 );
  612. vtxMemMove.RegisterBytes( vtxIdx, uiNumExtraBytes - ( bEmitIndices ? 0 : ( uiNumIndicesInPartitions * sizeof( uint16 ) ) ) );
  613. ITERATE_END
  614. vtxMemMove.RegisterBytes( vtxStripGroup->pVertex(0), ( uiNumVertsInStripGroupUpdate - vtxStripGroup->numVerts ) * sizeof( *vtxStripGroup->pVertex(0) ) );
  615. vtxStripGroup->numIndices = uiNumIndicesInStripGroupUpdate;
  616. vtxStripGroup->numVerts = uiNumVertsInStripGroupUpdate;
  617. ITERATE_END
  618. ITERATE_END
  619. ITERATE_END
  620. ITERATE_END
  621. ITERATE_END
  622. }
  623. //
  624. // Now enlarge the VTX buffer
  625. //
  626. vtxBuffer.EnsureCapacity( vtxBuffer.TellGet() + vtxLength + vtxMemMove.GetNumBytesRegistered() );
  627. vtxBuffer.SeekPut( vtxBuffer.SEEK_HEAD, vtxBuffer.TellGet() + vtxLength + vtxMemMove.GetNumBytesRegistered() );
  628. DECLARE_UPDATE_PTR( byte, vtx, BYTE_OFF_PTR( vtxBuffer.Base(), vtxBuffer.TellGet() ) );
  629. vtxMemMove.RegisterBaseDelta( vtxHdr, vtx );
  630. DECLARE_UPDATE_PTR( OptimizedModel::FileHeader_t, vtxHdr, vtx );
  631. vtxMemMove.Finalize();
  632. // By now should have scheduled all memmove information
  633. Log_Msg( LOG_ModelLib, " Increased VTX size by %d bytes.\n", vtxMemMove.GetNumBytesRegistered() );
  634. //
  635. // Fixup all the offsets
  636. //
  637. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementListHeader_t, vtxMatList, vtxHdr, pMaterialReplacementList, numLODs )
  638. ITERATE_CHILDREN( OptimizedModel::MaterialReplacementHeader_t, vtxMat, vtxMatList, pMaterialReplacement, numReplacements )
  639. vtxMat->replacementMaterialNameOffset = vtxMemMove.ComputeOffset( vtxMat, vtxMat->replacementMaterialNameOffset );
  640. ITERATE_END
  641. vtxMatList->replacementOffset = vtxMemMove.ComputeOffset( vtxMatList, vtxMatList->replacementOffset );
  642. ITERATE_END
  643. ITERATE_CHILDREN( OptimizedModel::BodyPartHeader_t, vtxBodyPart, vtxHdr, pBodyPart, numBodyParts )
  644. ITERATE_CHILDREN( OptimizedModel::ModelHeader_t, vtxModel, vtxBodyPart, pModel, numModels )
  645. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  646. ITERATE_CHILDREN( OptimizedModel::MeshHeader_t, vtxMesh, vtxLod, pMesh, numMeshes )
  647. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  648. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  649. vtxStrip->indexOffset =
  650. vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset + vtxStrip->indexOffset ) -
  651. vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  652. vtxStrip->vertOffset =
  653. vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset + vtxStrip->vertOffset ) -
  654. vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  655. vtxStrip->boneStateChangeOffset = vtxMemMove.ComputeOffset( vtxStrip, vtxStrip->boneStateChangeOffset );
  656. ITERATE_END
  657. vtxStripGroup->vertOffset = vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->vertOffset );
  658. vtxStripGroup->indexOffset = vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->indexOffset );
  659. vtxStripGroup->stripOffset = vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->stripOffset );
  660. vtxStripGroup->topologyOffset = vtxMemMove.ComputeOffset( vtxStripGroup, vtxStripGroup->topologyOffset );
  661. ITERATE_END
  662. vtxMesh->stripGroupHeaderOffset = vtxMemMove.ComputeOffset( vtxMesh, vtxMesh->stripGroupHeaderOffset );
  663. ITERATE_END
  664. vtxLod->meshOffset = vtxMemMove.ComputeOffset( vtxLod, vtxLod->meshOffset );
  665. ITERATE_END
  666. vtxModel->lodOffset = vtxMemMove.ComputeOffset( vtxModel, vtxModel->lodOffset );
  667. ITERATE_END
  668. vtxBodyPart->modelOffset = vtxMemMove.ComputeOffset( vtxBodyPart, vtxBodyPart->modelOffset );
  669. ITERATE_END
  670. vtxHdr->materialReplacementListOffset = vtxMemMove.ComputeOffset( vtxHdr, vtxHdr->materialReplacementListOffset );
  671. vtxHdr->bodyPartOffset = vtxMemMove.ComputeOffset( vtxHdr, vtxHdr->bodyPartOffset );
  672. // Perform final memory move
  673. vtxMemMove.MemMove( vtxHdr, vtxLength );
  674. vtxBuffer.SeekPut( vtxBuffer.SEEK_HEAD, vtxBuffer.TellGet() + vtxLength );
  675. //
  676. // Fill the newly insterted gaps with real data
  677. //
  678. {
  679. OptimizedModel::Vertex_t optVertex;
  680. for ( int j = 0; j < MAX_NUM_BONES_PER_VERT; ++ j )
  681. optVertex.boneWeightIndex[j] = j, optVertex.boneID[j] = 0;
  682. optVertex.numBones = 1; // we are processing only 1-bone models
  683. uint32 uiEdgeDmaInputOffsetPerStripGroup = 0;
  684. ITERATE_CHILDREN2( OptimizedModel::BodyPartHeader_t, mstudiobodyparts_t, vtxBodyPart, mdlBodyPart, vtxHdr, mdlHdr, pBodyPart, pBodypart, numBodyParts )
  685. ITERATE_CHILDREN2( OptimizedModel::ModelHeader_t, mstudiomodel_t, vtxModel, mdlModel, vtxBodyPart, mdlBodyPart, pModel, pModel, numModels )
  686. uint32 uiRunningOriginalVertexId = 0;
  687. // Process each mesh separately (NOTE: loop reversed: MESH, then LOD)
  688. ITERATE_CHILDREN( mstudiomesh_t, mdlMesh, mdlModel, pMesh, nummeshes )
  689. ITERATE_CHILDREN( OptimizedModel::ModelLODHeader_t, vtxLod, vtxModel, pLOD, numLODs )
  690. if ( vtxLod->numMeshes <= mdlMesh_idx ) continue;
  691. OptimizedModel::MeshHeader_t *vtxMesh = vtxLod->pMesh( mdlMesh_idx );
  692. ITERATE_CHILDREN( OptimizedModel::StripGroupHeader_t, vtxStripGroup, vtxMesh, pStripGroup, numStripGroups )
  693. uint32 uiStipGroupFilledVerts = 0;
  694. uint32 uiRunningEdgeDmaInputEnd = uiEdgeDmaInputOffsetPerStripGroup;
  695. CUtlVector< OptimizedModel::OptimizedIndexBufferMarkupPs3_t * > arrGroupMarkups;
  696. ITERATE_CHILDREN( OptimizedModel::StripHeader_t, vtxStrip, vtxStripGroup, pStrip, numStrips )
  697. CMdlStripInfo::Ps3studioBatch_t &batch = *ps3studioBatches[ mapMBI[ mapMBI.Find( ModelBatchKey_t( vtxBodyPart_idx, vtxModel_idx, vtxLod_idx, mdlMesh_idx, vtxStripGroup_idx, vtxStrip_idx ) ) ] ];
  698. uint16 *vtxIdx = CHILD_AT( vtxStripGroup, pIndex, vtxStrip->indexOffset );
  699. uint32 uiNumExtraBytes = sizeof( OptimizedModel::OptimizedIndexBufferMarkupPs3_t ) +
  700. batch.m_arrPartitions.Count() * sizeof( OptimizedModel::OptimizedIndexBufferMarkupPs3_t::Partition_t );
  701. uiNumExtraBytes = ( ( uiNumExtraBytes + 5 ) / 6 ) * 6; // make it even number of 3 indices
  702. // Write the "markup" header
  703. DECLARE_PTR( OptimizedModel::OptimizedIndexBufferMarkupPs3_t, pMarkup, vtxIdx );
  704. arrGroupMarkups.AddToTail( pMarkup );
  705. pMarkup->m_uiHeaderCookie = pMarkup->kHeaderCookie;
  706. pMarkup->m_uiVersionFlags = pMarkup->kVersion1;
  707. pMarkup->m_numBytesMarkup = uiNumExtraBytes;
  708. pMarkup->m_numPartitions = batch.m_arrPartitions.Count();
  709. pMarkup->m_numIndicesTotal = 0;
  710. pMarkup->m_numVerticesTotal = 0;
  711. pMarkup->m_nEdgeDmaInputOffsetPerStripGroup = uiEdgeDmaInputOffsetPerStripGroup; // updated later
  712. pMarkup->m_nEdgeDmaInputSizePerStripGroup = 0; // filled later
  713. uint32 uiSkipIdx = uiNumExtraBytes / sizeof( uint16 ), uiSkipVerts = 0;
  714. for ( int k = 0; k < batch.m_arrPartitions.Count(); ++ k )
  715. {
  716. CMdlStripInfo::Ps3studioPartition_t &partition = *batch.m_arrPartitions[k];
  717. pMarkup->m_partitions[k].m_numIndicesToSkipInIBs = uiSkipIdx;
  718. pMarkup->m_partitions[k].m_numVerticesToSkipInVBs = uiSkipVerts;
  719. pMarkup->m_partitions[k].m_nIoBufferSize = partition.m_nIoBufferSize;
  720. pMarkup->m_partitions[k].m_numIndices = partition.m_arrLocalIndices.Count();
  721. pMarkup->m_partitions[k].m_numVertices = partition.m_arrVertOriginalIndices.Count();
  722. if ( uiRunningEdgeDmaInputEnd == uiEdgeDmaInputOffsetPerStripGroup )
  723. {
  724. pMarkup->m_nEdgeDmaInputOffsetPerStripGroup =
  725. uiEdgeDmaInputOffsetPerStripGroup =
  726. partition.m_nEdgeDmaInputIdx;
  727. }
  728. pMarkup->m_partitions[k].m_nEdgeDmaInputIdx = partition.m_nEdgeDmaInputIdx - uiEdgeDmaInputOffsetPerStripGroup;
  729. pMarkup->m_partitions[k].m_nEdgeDmaInputVtx = partition.m_nEdgeDmaInputVtx - uiEdgeDmaInputOffsetPerStripGroup;
  730. pMarkup->m_partitions[k].m_nEdgeDmaInputEnd = partition.m_nEdgeDmaInputEnd - uiEdgeDmaInputOffsetPerStripGroup;
  731. uiRunningEdgeDmaInputEnd = partition.m_nEdgeDmaInputEnd;
  732. pMarkup->m_numIndicesTotal += pMarkup->m_partitions[k].m_numIndices;
  733. pMarkup->m_numVerticesTotal += pMarkup->m_partitions[k].m_numVertices;
  734. if ( bEmitIndices )
  735. {
  736. //
  737. // Write raw partition indices
  738. //
  739. for ( int j = 0; j < partition.m_arrLocalIndices.Count(); ++ j )
  740. {
  741. vtxIdx[ uiSkipIdx + j ] = partition.m_arrLocalIndices[j];
  742. }
  743. uiSkipIdx += partition.m_arrLocalIndices.Count();
  744. }
  745. //
  746. // Advance written verts
  747. //
  748. uiSkipVerts += partition.m_arrVertOriginalIndices.Count();
  749. }
  750. vtxStrip->numIndices = uiSkipIdx;
  751. // Fill out our Vertex_t structures
  752. bool bWarningSpewed = false;
  753. if ( uiSkipVerts > vtxStripGroup->numVerts )
  754. {
  755. Warning( "WARNING: %s: VTX strip group overflow %d/%d\n", mdlHdr->pszName(), uiSkipVerts, vtxStripGroup->numVerts );
  756. Assert( !"VTX strip group overflow!" );
  757. bWarningSpewed = true;
  758. }
  759. for ( int j = 0; j < uiSkipVerts; ++ j )
  760. {
  761. optVertex.origMeshVertID = uiRunningOriginalVertexId - mdlMesh->vertexoffset;
  762. if ( !bWarningSpewed && (
  763. ( uiRunningOriginalVertexId < mdlMesh->vertexoffset ) ||
  764. ( uint32( optVertex.origMeshVertID ) != uint32( uiRunningOriginalVertexId - mdlMesh->vertexoffset ) ) ||
  765. ( mdlMesh->numvertices <= optVertex.origMeshVertID )
  766. ) )
  767. {
  768. Warning( "WARNING: %s: VTX vertex indirection overflow id=%d, off=%d, idx=%d/%d\n", mdlHdr->pszName(), uiRunningOriginalVertexId, mdlMesh->vertexoffset, uint32( optVertex.origMeshVertID ), mdlMesh->numvertices );
  769. Assert( !"VTX vertex indirection overflow!" );
  770. bWarningSpewed = true;
  771. }
  772. uiRunningOriginalVertexId ++;
  773. V_memcpy( vtxStripGroup->pVertex( uiStipGroupFilledVerts + j ), &optVertex, sizeof( optVertex ) );
  774. }
  775. uiStipGroupFilledVerts += uiSkipVerts;
  776. ITERATE_END
  777. for ( int jjj = 0; jjj < arrGroupMarkups.Count(); ++ jjj )
  778. {
  779. arrGroupMarkups[jjj]->m_nEdgeDmaInputSizePerStripGroup = uiRunningEdgeDmaInputEnd - uiEdgeDmaInputOffsetPerStripGroup;
  780. // Need pre-swapping inside index buffer
  781. Helper_SwapOptimizedIndexBufferMarkup_forPs3( arrGroupMarkups[jjj] );
  782. }
  783. uiEdgeDmaInputOffsetPerStripGroup = uiRunningEdgeDmaInputEnd;
  784. ITERATE_END
  785. ITERATE_END
  786. ITERATE_END
  787. ITERATE_END
  788. ITERATE_END
  789. }
  790. //
  791. // ===================
  792. // =================== Validate that we have valid information for VHV processing
  793. // ===================
  794. //
  795. {
  796. // Keep track of which verts got touched
  797. CGrowableBitVec arrTouchedOriginalVerts;
  798. uint32 uiDebugOriginalVertsPresent = numVhvOriginalModelVertices;
  799. for ( uint32 iMesh = 0, iBatch = 0; iMesh < pMsi->m_ps3studioStripGroupHeaderBatchOffset.Count(); ++ iMesh )
  800. {
  801. uint32 numVerts = 0;
  802. uint32 iBatchEnd = ( iMesh < pMsi->m_ps3studioStripGroupHeaderBatchOffset.Count() - 1 )
  803. ? pMsi->m_ps3studioStripGroupHeaderBatchOffset[iMesh+1] : pMsi->m_ps3studioBatches.Count();
  804. iBatchEnd = MIN( iBatchEnd, pMsi->m_ps3studioBatches.Count() );
  805. for ( ; iBatch < iBatchEnd; ++ iBatch )
  806. {
  807. CMdlStripInfo::Ps3studioBatch_t &batch = *pMsi->m_ps3studioBatches[iBatch];
  808. for ( uint32 iPartition = 0; iPartition < batch.m_arrPartitions.Count(); ++ iPartition )
  809. {
  810. CMdlStripInfo::Ps3studioPartition_t &partition = *batch.m_arrPartitions[iPartition];
  811. numVerts += partition.m_arrVertOriginalIndices.Count();
  812. for ( uint32 iVertIndex = 0; iVertIndex < partition.m_arrVertOriginalIndices.Count(); ++ iVertIndex )
  813. {
  814. // uint32 uiOrigVertIndex = partition.m_arrVertOriginalIndices[iVertIndex];
  815. uint32 uiOrigVertIndex = partition.m_arrStripLocalOriginalIndices[iVertIndex];
  816. uiOrigVertIndex += batch.m_uiVhvIndexOffset;
  817. arrTouchedOriginalVerts.GrowSetBit( uiOrigVertIndex );
  818. }
  819. }
  820. }
  821. }
  822. {
  823. uint32 uiDebugTouchedOriginalVerts = arrTouchedOriginalVerts.GetNumBits();
  824. if ( uiDebugTouchedOriginalVerts == uiDebugOriginalVertsPresent )
  825. {
  826. for ( uint32 iDebugOrigVert = 0; iDebugOrigVert < uiDebugOriginalVertsPresent; ++ iDebugOrigVert )
  827. {
  828. if ( !arrTouchedOriginalVerts.IsBitSet( iDebugOrigVert ) )
  829. {
  830. Warning( "WARNING: %s: VHV source vertex %d/%d skipped\n", mdlHdr->pszName(), iDebugOrigVert, uiDebugOriginalVertsPresent );
  831. Assert( !"VHV source vertex skipped!" );
  832. break;
  833. }
  834. }
  835. }
  836. else
  837. {
  838. Warning( "WARNING: %s: VHV expected vertex count mismatch %d!=%d\n", mdlHdr->pszName(), uiDebugTouchedOriginalVerts, uiDebugOriginalVertsPresent );
  839. Assert( !"VHV expected vertex count mismatch!" );
  840. }
  841. }
  842. }
  843. // Done
  844. return true;
  845. }
  846. /*
  847. If the changelist comment includes the following line:
  848. *** force rebuild ***
  849. then it will trigger a full content rebuild which is very
  850. useful when changing output formats.
  851. */