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.

5247 lines
151 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #include "cmdlib.h"
  9. #include "mathlib/mathlib.h"
  10. #include "bsplib.h"
  11. #include "zip_utils.h"
  12. #include "scriplib.h"
  13. #include "utllinkedlist.h"
  14. #include "bsptreedata.h"
  15. #include "cmodel.h"
  16. #include "gamebspfile.h"
  17. #include "materialsystem/imaterial.h"
  18. #include "materialsystem/hardwareverts.h"
  19. #include "utlbuffer.h"
  20. #include "utlrbtree.h"
  21. #include "utlsymbol.h"
  22. #include "utlstring.h"
  23. #include "checksum_crc.h"
  24. #include "physdll.h"
  25. #include "tier0/dbg.h"
  26. #include "lumpfiles.h"
  27. #include "vtf/vtf.h"
  28. #include "lzma/lzma.h"
  29. #include "tier1/lzmaDecoder.h"
  30. #include "tier0/memdbgon.h"
  31. //=============================================================================
  32. // Boundary each lump should be aligned to
  33. #define LUMP_ALIGNMENT 4
  34. // Data descriptions for byte swapping - only needed
  35. // for structures that are written to file for use by the game.
  36. BEGIN_BYTESWAP_DATADESC( dheader_t )
  37. DEFINE_FIELD( ident, FIELD_INTEGER ),
  38. DEFINE_FIELD( version, FIELD_INTEGER ),
  39. DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ),
  40. DEFINE_FIELD( mapRevision, FIELD_INTEGER ),
  41. END_BYTESWAP_DATADESC()
  42. BEGIN_BYTESWAP_DATADESC( lump_t )
  43. DEFINE_FIELD( fileofs, FIELD_INTEGER ),
  44. DEFINE_FIELD( filelen, FIELD_INTEGER ),
  45. DEFINE_FIELD( version, FIELD_INTEGER ),
  46. DEFINE_FIELD( uncompressedSize, FIELD_INTEGER ),
  47. END_BYTESWAP_DATADESC()
  48. BEGIN_BYTESWAP_DATADESC( dflagslump_t )
  49. DEFINE_FIELD( m_LevelFlags, FIELD_INTEGER ),
  50. END_BYTESWAP_DATADESC()
  51. BEGIN_BYTESWAP_DATADESC( dplane_t )
  52. DEFINE_FIELD( normal, FIELD_VECTOR ),
  53. DEFINE_FIELD( dist, FIELD_FLOAT ),
  54. DEFINE_FIELD( type, FIELD_INTEGER ),
  55. END_BYTESWAP_DATADESC()
  56. BEGIN_BYTESWAP_DATADESC( dleaf_version_0_t )
  57. DEFINE_FIELD( contents, FIELD_INTEGER ),
  58. DEFINE_FIELD( cluster, FIELD_SHORT ),
  59. DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
  60. DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
  61. DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
  62. DEFINE_FIELD( firstleafface, FIELD_SHORT ),
  63. DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
  64. DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
  65. DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
  66. DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
  67. DEFINE_EMBEDDED( m_AmbientLighting ),
  68. END_BYTESWAP_DATADESC()
  69. BEGIN_BYTESWAP_DATADESC( dleaf_t )
  70. DEFINE_FIELD( contents, FIELD_INTEGER ),
  71. DEFINE_FIELD( cluster, FIELD_SHORT ),
  72. DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
  73. DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
  74. DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
  75. DEFINE_FIELD( firstleafface, FIELD_SHORT ),
  76. DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
  77. DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
  78. DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
  79. DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
  80. END_BYTESWAP_DATADESC()
  81. BEGIN_BYTESWAP_DATADESC( CompressedLightCube ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
  82. DEFINE_ARRAY( m_Color, FIELD_CHARACTER, 6 * sizeof(ColorRGBExp32) ),
  83. END_BYTESWAP_DATADESC()
  84. BEGIN_BYTESWAP_DATADESC( dleafambientindex_t )
  85. DEFINE_FIELD( ambientSampleCount, FIELD_SHORT ),
  86. DEFINE_FIELD( firstAmbientSample, FIELD_SHORT ),
  87. END_BYTESWAP_DATADESC()
  88. BEGIN_BYTESWAP_DATADESC( dleafambientlighting_t ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
  89. DEFINE_EMBEDDED( cube ),
  90. DEFINE_FIELD( x, FIELD_CHARACTER ),
  91. DEFINE_FIELD( y, FIELD_CHARACTER ),
  92. DEFINE_FIELD( z, FIELD_CHARACTER ),
  93. DEFINE_FIELD( pad, FIELD_CHARACTER ),
  94. END_BYTESWAP_DATADESC()
  95. BEGIN_BYTESWAP_DATADESC( dvertex_t )
  96. DEFINE_FIELD( point, FIELD_VECTOR ),
  97. END_BYTESWAP_DATADESC()
  98. BEGIN_BYTESWAP_DATADESC( dnode_t )
  99. DEFINE_FIELD( planenum, FIELD_INTEGER ),
  100. DEFINE_ARRAY( children, FIELD_INTEGER, 2 ),
  101. DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
  102. DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
  103. DEFINE_FIELD( firstface, FIELD_SHORT ),
  104. DEFINE_FIELD( numfaces, FIELD_SHORT ),
  105. DEFINE_FIELD( area, FIELD_SHORT ),
  106. END_BYTESWAP_DATADESC()
  107. BEGIN_BYTESWAP_DATADESC( texinfo_t )
  108. DEFINE_ARRAY( textureVecsTexelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
  109. DEFINE_ARRAY( lightmapVecsLuxelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
  110. DEFINE_FIELD( flags, FIELD_INTEGER ),
  111. DEFINE_FIELD( texdata, FIELD_INTEGER ),
  112. END_BYTESWAP_DATADESC()
  113. BEGIN_BYTESWAP_DATADESC( dtexdata_t )
  114. DEFINE_FIELD( reflectivity, FIELD_VECTOR ),
  115. DEFINE_FIELD( nameStringTableID, FIELD_INTEGER ),
  116. DEFINE_FIELD( width, FIELD_INTEGER ),
  117. DEFINE_FIELD( height, FIELD_INTEGER ),
  118. DEFINE_FIELD( view_width, FIELD_INTEGER ),
  119. DEFINE_FIELD( view_height, FIELD_INTEGER ),
  120. END_BYTESWAP_DATADESC()
  121. BEGIN_BYTESWAP_DATADESC( ddispinfo_t )
  122. DEFINE_FIELD( startPosition, FIELD_VECTOR ),
  123. DEFINE_FIELD( m_iDispVertStart, FIELD_INTEGER ),
  124. DEFINE_FIELD( m_iDispTriStart, FIELD_INTEGER ),
  125. DEFINE_FIELD( power, FIELD_INTEGER ),
  126. DEFINE_FIELD( minTess, FIELD_INTEGER ),
  127. DEFINE_FIELD( smoothingAngle, FIELD_FLOAT ),
  128. DEFINE_FIELD( contents, FIELD_INTEGER ),
  129. DEFINE_FIELD( m_iMapFace, FIELD_SHORT ),
  130. DEFINE_FIELD( m_iLightmapAlphaStart, FIELD_INTEGER ),
  131. DEFINE_FIELD( m_iLightmapSamplePositionStart, FIELD_INTEGER ),
  132. DEFINE_EMBEDDED_ARRAY( m_EdgeNeighbors, 4 ),
  133. DEFINE_EMBEDDED_ARRAY( m_CornerNeighbors, 4 ),
  134. DEFINE_ARRAY( m_AllowedVerts, FIELD_INTEGER, ddispinfo_t::ALLOWEDVERTS_SIZE ), // unsigned long
  135. END_BYTESWAP_DATADESC()
  136. BEGIN_BYTESWAP_DATADESC( CDispNeighbor )
  137. DEFINE_EMBEDDED_ARRAY( m_SubNeighbors, 2 ),
  138. END_BYTESWAP_DATADESC()
  139. BEGIN_BYTESWAP_DATADESC( CDispCornerNeighbors )
  140. DEFINE_ARRAY( m_Neighbors, FIELD_SHORT, MAX_DISP_CORNER_NEIGHBORS ),
  141. DEFINE_FIELD( m_nNeighbors, FIELD_CHARACTER ),
  142. END_BYTESWAP_DATADESC()
  143. BEGIN_BYTESWAP_DATADESC( CDispSubNeighbor )
  144. DEFINE_FIELD( m_iNeighbor, FIELD_SHORT ),
  145. DEFINE_FIELD( m_NeighborOrientation, FIELD_CHARACTER ),
  146. DEFINE_FIELD( m_Span, FIELD_CHARACTER ),
  147. DEFINE_FIELD( m_NeighborSpan, FIELD_CHARACTER ),
  148. END_BYTESWAP_DATADESC()
  149. BEGIN_BYTESWAP_DATADESC( CDispVert )
  150. DEFINE_FIELD( m_vVector, FIELD_VECTOR ),
  151. DEFINE_FIELD( m_flDist, FIELD_FLOAT ),
  152. DEFINE_FIELD( m_flAlpha, FIELD_FLOAT ),
  153. END_BYTESWAP_DATADESC()
  154. BEGIN_BYTESWAP_DATADESC( CDispTri )
  155. DEFINE_FIELD( m_uiTags, FIELD_SHORT ),
  156. END_BYTESWAP_DATADESC()
  157. BEGIN_BYTESWAP_DATADESC( CFaceMacroTextureInfo )
  158. DEFINE_FIELD( m_MacroTextureNameID, FIELD_SHORT ),
  159. END_BYTESWAP_DATADESC()
  160. BEGIN_BYTESWAP_DATADESC( dprimitive_t )
  161. DEFINE_FIELD( type, FIELD_CHARACTER ),
  162. DEFINE_FIELD( firstIndex, FIELD_SHORT ),
  163. DEFINE_FIELD( indexCount, FIELD_SHORT ),
  164. DEFINE_FIELD( firstVert, FIELD_SHORT ),
  165. DEFINE_FIELD( vertCount, FIELD_SHORT ),
  166. END_BYTESWAP_DATADESC()
  167. BEGIN_BYTESWAP_DATADESC( dprimvert_t )
  168. DEFINE_FIELD( pos, FIELD_VECTOR ),
  169. END_BYTESWAP_DATADESC()
  170. BEGIN_BYTESWAP_DATADESC( dface_t )
  171. DEFINE_FIELD( planenum, FIELD_SHORT ),
  172. DEFINE_FIELD( side, FIELD_CHARACTER ),
  173. DEFINE_FIELD( onNode, FIELD_CHARACTER ),
  174. DEFINE_FIELD( firstedge, FIELD_INTEGER ),
  175. DEFINE_FIELD( numedges, FIELD_SHORT ),
  176. DEFINE_FIELD( texinfo, FIELD_SHORT ),
  177. DEFINE_FIELD( dispinfo, FIELD_SHORT ),
  178. DEFINE_FIELD( surfaceFogVolumeID, FIELD_SHORT ),
  179. DEFINE_ARRAY( styles, FIELD_CHARACTER, MAXLIGHTMAPS ),
  180. DEFINE_FIELD( lightofs, FIELD_INTEGER ),
  181. DEFINE_FIELD( area, FIELD_FLOAT ),
  182. DEFINE_ARRAY( m_LightmapTextureMinsInLuxels, FIELD_INTEGER, 2 ),
  183. DEFINE_ARRAY( m_LightmapTextureSizeInLuxels, FIELD_INTEGER, 2 ),
  184. DEFINE_FIELD( origFace, FIELD_INTEGER ),
  185. DEFINE_FIELD( m_NumPrims, FIELD_SHORT ),
  186. DEFINE_FIELD( firstPrimID, FIELD_SHORT ),
  187. DEFINE_FIELD( smoothingGroups, FIELD_INTEGER ),
  188. END_BYTESWAP_DATADESC()
  189. BEGIN_BYTESWAP_DATADESC( dfaceid_t )
  190. DEFINE_FIELD( hammerfaceid, FIELD_SHORT ),
  191. END_BYTESWAP_DATADESC()
  192. BEGIN_BYTESWAP_DATADESC( dbrush_t )
  193. DEFINE_FIELD( firstside, FIELD_INTEGER ),
  194. DEFINE_FIELD( numsides, FIELD_INTEGER ),
  195. DEFINE_FIELD( contents, FIELD_INTEGER ),
  196. END_BYTESWAP_DATADESC()
  197. BEGIN_BYTESWAP_DATADESC( dbrushside_t )
  198. DEFINE_FIELD( planenum, FIELD_SHORT ),
  199. DEFINE_FIELD( texinfo, FIELD_SHORT ),
  200. DEFINE_FIELD( dispinfo, FIELD_SHORT ),
  201. DEFINE_FIELD( bevel, FIELD_SHORT ),
  202. END_BYTESWAP_DATADESC()
  203. BEGIN_BYTESWAP_DATADESC( dedge_t )
  204. DEFINE_ARRAY( v, FIELD_SHORT, 2 ),
  205. END_BYTESWAP_DATADESC()
  206. BEGIN_BYTESWAP_DATADESC( dmodel_t )
  207. DEFINE_FIELD( mins, FIELD_VECTOR ),
  208. DEFINE_FIELD( maxs, FIELD_VECTOR ),
  209. DEFINE_FIELD( origin, FIELD_VECTOR ),
  210. DEFINE_FIELD( headnode, FIELD_INTEGER ),
  211. DEFINE_FIELD( firstface, FIELD_INTEGER ),
  212. DEFINE_FIELD( numfaces, FIELD_INTEGER ),
  213. END_BYTESWAP_DATADESC()
  214. BEGIN_BYTESWAP_DATADESC( dphysmodel_t )
  215. DEFINE_FIELD( modelIndex, FIELD_INTEGER ),
  216. DEFINE_FIELD( dataSize, FIELD_INTEGER ),
  217. DEFINE_FIELD( keydataSize, FIELD_INTEGER ),
  218. DEFINE_FIELD( solidCount, FIELD_INTEGER ),
  219. END_BYTESWAP_DATADESC()
  220. BEGIN_BYTESWAP_DATADESC( dphysdisp_t )
  221. DEFINE_FIELD( numDisplacements, FIELD_SHORT ),
  222. END_BYTESWAP_DATADESC()
  223. BEGIN_BYTESWAP_DATADESC( darea_t )
  224. DEFINE_FIELD( numareaportals, FIELD_INTEGER ),
  225. DEFINE_FIELD( firstareaportal, FIELD_INTEGER ),
  226. END_BYTESWAP_DATADESC()
  227. BEGIN_BYTESWAP_DATADESC( dareaportal_t )
  228. DEFINE_FIELD( m_PortalKey, FIELD_SHORT ),
  229. DEFINE_FIELD( otherarea, FIELD_SHORT ),
  230. DEFINE_FIELD( m_FirstClipPortalVert, FIELD_SHORT ),
  231. DEFINE_FIELD( m_nClipPortalVerts, FIELD_SHORT ),
  232. DEFINE_FIELD( planenum, FIELD_INTEGER ),
  233. END_BYTESWAP_DATADESC()
  234. BEGIN_BYTESWAP_DATADESC( dworldlight_t )
  235. DEFINE_FIELD( origin, FIELD_VECTOR ),
  236. DEFINE_FIELD( intensity, FIELD_VECTOR ),
  237. DEFINE_FIELD( normal, FIELD_VECTOR ),
  238. DEFINE_FIELD( cluster, FIELD_INTEGER ),
  239. DEFINE_FIELD( type, FIELD_INTEGER ), // enumeration
  240. DEFINE_FIELD( style, FIELD_INTEGER ),
  241. DEFINE_FIELD( stopdot, FIELD_FLOAT ),
  242. DEFINE_FIELD( stopdot2, FIELD_FLOAT ),
  243. DEFINE_FIELD( exponent, FIELD_FLOAT ),
  244. DEFINE_FIELD( radius, FIELD_FLOAT ),
  245. DEFINE_FIELD( constant_attn, FIELD_FLOAT ),
  246. DEFINE_FIELD( linear_attn, FIELD_FLOAT ),
  247. DEFINE_FIELD( quadratic_attn, FIELD_FLOAT ),
  248. DEFINE_FIELD( flags, FIELD_INTEGER ),
  249. DEFINE_FIELD( texinfo, FIELD_INTEGER ),
  250. DEFINE_FIELD( owner, FIELD_INTEGER ),
  251. END_BYTESWAP_DATADESC()
  252. BEGIN_BYTESWAP_DATADESC( dleafwaterdata_t )
  253. DEFINE_FIELD( surfaceZ, FIELD_FLOAT ),
  254. DEFINE_FIELD( minZ, FIELD_FLOAT ),
  255. DEFINE_FIELD( surfaceTexInfoID, FIELD_SHORT ),
  256. END_BYTESWAP_DATADESC()
  257. BEGIN_BYTESWAP_DATADESC( doccluderdata_t )
  258. DEFINE_FIELD( flags, FIELD_INTEGER ),
  259. DEFINE_FIELD( firstpoly, FIELD_INTEGER ),
  260. DEFINE_FIELD( polycount, FIELD_INTEGER ),
  261. DEFINE_FIELD( mins, FIELD_VECTOR ),
  262. DEFINE_FIELD( maxs, FIELD_VECTOR ),
  263. DEFINE_FIELD( area, FIELD_INTEGER ),
  264. END_BYTESWAP_DATADESC()
  265. BEGIN_BYTESWAP_DATADESC( doccluderpolydata_t )
  266. DEFINE_FIELD( firstvertexindex, FIELD_INTEGER ),
  267. DEFINE_FIELD( vertexcount, FIELD_INTEGER ),
  268. DEFINE_FIELD( planenum, FIELD_INTEGER ),
  269. END_BYTESWAP_DATADESC()
  270. BEGIN_BYTESWAP_DATADESC( dcubemapsample_t )
  271. DEFINE_ARRAY( origin, FIELD_INTEGER, 3 ),
  272. DEFINE_FIELD( size, FIELD_CHARACTER ),
  273. END_BYTESWAP_DATADESC()
  274. BEGIN_BYTESWAP_DATADESC( doverlay_t )
  275. DEFINE_FIELD( nId, FIELD_INTEGER ),
  276. DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
  277. DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
  278. DEFINE_ARRAY( aFaces, FIELD_INTEGER, OVERLAY_BSP_FACE_COUNT ),
  279. DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
  280. DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
  281. DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
  282. DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
  283. DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
  284. END_BYTESWAP_DATADESC()
  285. BEGIN_BYTESWAP_DATADESC( dwateroverlay_t )
  286. DEFINE_FIELD( nId, FIELD_INTEGER ),
  287. DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
  288. DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
  289. DEFINE_ARRAY( aFaces, FIELD_INTEGER, WATEROVERLAY_BSP_FACE_COUNT ),
  290. DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
  291. DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
  292. DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
  293. DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
  294. DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
  295. END_BYTESWAP_DATADESC()
  296. BEGIN_BYTESWAP_DATADESC( doverlayfade_t )
  297. DEFINE_FIELD( flFadeDistMinSq, FIELD_FLOAT ),
  298. DEFINE_FIELD( flFadeDistMaxSq, FIELD_FLOAT ),
  299. END_BYTESWAP_DATADESC()
  300. BEGIN_BYTESWAP_DATADESC( dgamelumpheader_t )
  301. DEFINE_FIELD( lumpCount, FIELD_INTEGER ),
  302. END_BYTESWAP_DATADESC()
  303. BEGIN_BYTESWAP_DATADESC( dgamelump_t )
  304. DEFINE_FIELD( id, FIELD_INTEGER ), // GameLumpId_t
  305. DEFINE_FIELD( flags, FIELD_SHORT ),
  306. DEFINE_FIELD( version, FIELD_SHORT ),
  307. DEFINE_FIELD( fileofs, FIELD_INTEGER ),
  308. DEFINE_FIELD( filelen, FIELD_INTEGER ),
  309. END_BYTESWAP_DATADESC()
  310. // From gamebspfile.h
  311. BEGIN_BYTESWAP_DATADESC( StaticPropDictLump_t )
  312. DEFINE_ARRAY( m_Name, FIELD_CHARACTER, STATIC_PROP_NAME_LENGTH ),
  313. END_BYTESWAP_DATADESC()
  314. BEGIN_BYTESWAP_DATADESC( StaticPropLump_t )
  315. DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
  316. DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
  317. DEFINE_FIELD( m_PropType, FIELD_SHORT ),
  318. DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
  319. DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
  320. DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
  321. DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
  322. DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
  323. DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
  324. DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
  325. DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
  326. DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
  327. DEFINE_FIELD( m_nMinDXLevel, FIELD_SHORT ),
  328. DEFINE_FIELD( m_nMaxDXLevel, FIELD_SHORT ),
  329. END_BYTESWAP_DATADESC()
  330. BEGIN_BYTESWAP_DATADESC( StaticPropLumpV4_t )
  331. DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
  332. DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
  333. DEFINE_FIELD( m_PropType, FIELD_SHORT ),
  334. DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
  335. DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
  336. DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
  337. DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
  338. DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
  339. DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
  340. DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
  341. DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
  342. END_BYTESWAP_DATADESC()
  343. BEGIN_BYTESWAP_DATADESC( StaticPropLumpV5_t )
  344. DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
  345. DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
  346. DEFINE_FIELD( m_PropType, FIELD_SHORT ),
  347. DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
  348. DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
  349. DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
  350. DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
  351. DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
  352. DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
  353. DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
  354. DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
  355. DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
  356. END_BYTESWAP_DATADESC()
  357. BEGIN_BYTESWAP_DATADESC( StaticPropLeafLump_t )
  358. DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
  359. END_BYTESWAP_DATADESC()
  360. BEGIN_BYTESWAP_DATADESC( DetailObjectDictLump_t )
  361. DEFINE_ARRAY( m_Name, FIELD_CHARACTER, DETAIL_NAME_LENGTH ),
  362. END_BYTESWAP_DATADESC()
  363. BEGIN_BYTESWAP_DATADESC( DetailObjectLump_t )
  364. DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
  365. DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
  366. DEFINE_FIELD( m_DetailModel, FIELD_SHORT ),
  367. DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
  368. DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
  369. DEFINE_FIELD( m_LightStyles, FIELD_INTEGER ),
  370. DEFINE_FIELD( m_LightStyleCount, FIELD_CHARACTER ),
  371. DEFINE_FIELD( m_SwayAmount, FIELD_CHARACTER ),
  372. DEFINE_FIELD( m_ShapeAngle, FIELD_CHARACTER ),
  373. DEFINE_FIELD( m_ShapeSize, FIELD_CHARACTER ),
  374. DEFINE_FIELD( m_Orientation, FIELD_CHARACTER ),
  375. DEFINE_ARRAY( m_Padding2, FIELD_CHARACTER, 3 ),
  376. DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
  377. DEFINE_ARRAY( m_Padding3, FIELD_CHARACTER, 3 ),
  378. DEFINE_FIELD( m_flScale, FIELD_FLOAT ),
  379. END_BYTESWAP_DATADESC()
  380. BEGIN_BYTESWAP_DATADESC( DetailSpriteDictLump_t )
  381. DEFINE_FIELD( m_UL, FIELD_VECTOR2D ),
  382. DEFINE_FIELD( m_LR, FIELD_VECTOR2D ),
  383. DEFINE_FIELD( m_TexUL, FIELD_VECTOR2D ),
  384. DEFINE_FIELD( m_TexLR, FIELD_VECTOR2D ),
  385. END_BYTESWAP_DATADESC()
  386. BEGIN_BYTESWAP_DATADESC( DetailPropLightstylesLump_t )
  387. DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
  388. DEFINE_FIELD( m_Style, FIELD_CHARACTER ),
  389. END_BYTESWAP_DATADESC()
  390. // From vradstaticprops.h
  391. namespace HardwareVerts
  392. {
  393. BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
  394. DEFINE_FIELD( m_nLod, FIELD_INTEGER ),
  395. DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
  396. DEFINE_FIELD( m_nOffset, FIELD_INTEGER ),
  397. DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
  398. END_BYTESWAP_DATADESC()
  399. BEGIN_BYTESWAP_DATADESC( FileHeader_t )
  400. DEFINE_FIELD( m_nVersion, FIELD_INTEGER ),
  401. DEFINE_FIELD( m_nChecksum, FIELD_INTEGER ),
  402. DEFINE_FIELD( m_nVertexFlags, FIELD_INTEGER ),
  403. DEFINE_FIELD( m_nVertexSize, FIELD_INTEGER ),
  404. DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
  405. DEFINE_FIELD( m_nMeshes, FIELD_INTEGER ),
  406. DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
  407. END_BYTESWAP_DATADESC()
  408. } // end namespace
  409. static const char *s_LumpNames[] = {
  410. "LUMP_ENTITIES", // 0
  411. "LUMP_PLANES", // 1
  412. "LUMP_TEXDATA", // 2
  413. "LUMP_VERTEXES", // 3
  414. "LUMP_VISIBILITY", // 4
  415. "LUMP_NODES", // 5
  416. "LUMP_TEXINFO", // 6
  417. "LUMP_FACES", // 7
  418. "LUMP_LIGHTING", // 8
  419. "LUMP_OCCLUSION", // 9
  420. "LUMP_LEAFS", // 10
  421. "LUMP_FACEIDS", // 11
  422. "LUMP_EDGES", // 12
  423. "LUMP_SURFEDGES", // 13
  424. "LUMP_MODELS", // 14
  425. "LUMP_WORLDLIGHTS", // 15
  426. "LUMP_LEAFFACES", // 16
  427. "LUMP_LEAFBRUSHES", // 17
  428. "LUMP_BRUSHES", // 18
  429. "LUMP_BRUSHSIDES", // 19
  430. "LUMP_AREAS", // 20
  431. "LUMP_AREAPORTALS", // 21
  432. "LUMP_UNUSED0", // 22
  433. "LUMP_UNUSED1", // 23
  434. "LUMP_UNUSED2", // 24
  435. "LUMP_UNUSED3", // 25
  436. "LUMP_DISPINFO", // 26
  437. "LUMP_ORIGINALFACES", // 27
  438. "LUMP_PHYSDISP", // 28
  439. "LUMP_PHYSCOLLIDE", // 29
  440. "LUMP_VERTNORMALS", // 30
  441. "LUMP_VERTNORMALINDICES", // 31
  442. "LUMP_DISP_LIGHTMAP_ALPHAS", // 32
  443. "LUMP_DISP_VERTS", // 33
  444. "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", // 34
  445. "LUMP_GAME_LUMP", // 35
  446. "LUMP_LEAFWATERDATA", // 36
  447. "LUMP_PRIMITIVES", // 37
  448. "LUMP_PRIMVERTS", // 38
  449. "LUMP_PRIMINDICES", // 39
  450. "LUMP_PAKFILE", // 40
  451. "LUMP_CLIPPORTALVERTS", // 41
  452. "LUMP_CUBEMAPS", // 42
  453. "LUMP_TEXDATA_STRING_DATA", // 43
  454. "LUMP_TEXDATA_STRING_TABLE", // 44
  455. "LUMP_OVERLAYS", // 45
  456. "LUMP_LEAFMINDISTTOWATER", // 46
  457. "LUMP_FACE_MACRO_TEXTURE_INFO", // 47
  458. "LUMP_DISP_TRIS", // 48
  459. "LUMP_PHYSCOLLIDESURFACE", // 49
  460. "LUMP_WATEROVERLAYS", // 50
  461. "LUMP_LEAF_AMBIENT_INDEX_HDR", // 51
  462. "LUMP_LEAF_AMBIENT_INDEX", // 52
  463. "LUMP_LIGHTING_HDR", // 53
  464. "LUMP_WORLDLIGHTS_HDR", // 54
  465. "LUMP_LEAF_AMBIENT_LIGHTING_HDR", // 55
  466. "LUMP_LEAF_AMBIENT_LIGHTING", // 56
  467. "LUMP_XZIPPAKFILE", // 57
  468. "LUMP_FACES_HDR", // 58
  469. "LUMP_MAP_FLAGS", // 59
  470. "LUMP_OVERLAY_FADES", // 60
  471. };
  472. const char *GetLumpName( unsigned int lumpnum )
  473. {
  474. if ( lumpnum >= ARRAYSIZE( s_LumpNames ) )
  475. {
  476. return "UNKNOWN";
  477. }
  478. return s_LumpNames[lumpnum];
  479. }
  480. // "-hdr" tells us to use the HDR fields (if present) on the light sources. Also, tells us to write
  481. // out the HDR lumps for lightmaps, ambient leaves, and lights sources.
  482. bool g_bHDR = false;
  483. // Set to true to generate Xbox360 native output files
  484. static bool g_bSwapOnLoad = false;
  485. static bool g_bSwapOnWrite = false;
  486. VTFConvertFunc_t g_pVTFConvertFunc;
  487. VHVFixupFunc_t g_pVHVFixupFunc;
  488. CompressFunc_t g_pCompressFunc;
  489. CUtlVector< CUtlString > g_StaticPropNames;
  490. CUtlVector< int > g_StaticPropInstances;
  491. CByteswap g_Swap;
  492. uint32 g_LevelFlags = 0;
  493. int nummodels;
  494. dmodel_t dmodels[MAX_MAP_MODELS];
  495. int visdatasize;
  496. byte dvisdata[MAX_MAP_VISIBILITY];
  497. dvis_t *dvis = (dvis_t *)dvisdata;
  498. CUtlVector<byte> dlightdataHDR;
  499. CUtlVector<byte> dlightdataLDR;
  500. CUtlVector<byte> *pdlightdata = &dlightdataLDR;
  501. CUtlVector<char> dentdata;
  502. int numleafs;
  503. #if !defined( BSP_USE_LESS_MEMORY )
  504. dleaf_t dleafs[MAX_MAP_LEAFS];
  505. #else
  506. dleaf_t *dleafs;
  507. #endif
  508. CUtlVector<dleafambientindex_t> g_LeafAmbientIndexLDR;
  509. CUtlVector<dleafambientindex_t> g_LeafAmbientIndexHDR;
  510. CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex = NULL;
  511. CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingLDR;
  512. CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingHDR;
  513. CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting = NULL;
  514. unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
  515. int numplanes;
  516. dplane_t dplanes[MAX_MAP_PLANES];
  517. int numvertexes;
  518. dvertex_t dvertexes[MAX_MAP_VERTS];
  519. int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
  520. unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
  521. int g_numvertnormals;
  522. Vector g_vertnormals[MAX_MAP_VERTNORMALS];
  523. int numnodes;
  524. dnode_t dnodes[MAX_MAP_NODES];
  525. CUtlVector<texinfo_t> texinfo( MAX_MAP_TEXINFO );
  526. int numtexdata;
  527. dtexdata_t dtexdata[MAX_MAP_TEXDATA];
  528. //
  529. // displacement map bsp file info: dispinfo
  530. //
  531. CUtlVector<ddispinfo_t> g_dispinfo;
  532. CUtlVector<CDispVert> g_DispVerts;
  533. CUtlVector<CDispTri> g_DispTris;
  534. CUtlVector<unsigned char> g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
  535. int numorigfaces;
  536. dface_t dorigfaces[MAX_MAP_FACES];
  537. int g_numprimitives = 0;
  538. dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
  539. int g_numprimverts = 0;
  540. dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
  541. int g_numprimindices = 0;
  542. unsigned short g_primindices[MAX_MAP_PRIMINDICES];
  543. int numfaces;
  544. dface_t dfaces[MAX_MAP_FACES];
  545. int numfaceids;
  546. CUtlVector<dfaceid_t> dfaceids;
  547. int numfaces_hdr;
  548. dface_t dfaces_hdr[MAX_MAP_FACES];
  549. int numedges;
  550. dedge_t dedges[MAX_MAP_EDGES];
  551. int numleaffaces;
  552. unsigned short dleaffaces[MAX_MAP_LEAFFACES];
  553. int numleafbrushes;
  554. unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
  555. int numsurfedges;
  556. int dsurfedges[MAX_MAP_SURFEDGES];
  557. int numbrushes;
  558. dbrush_t dbrushes[MAX_MAP_BRUSHES];
  559. int numbrushsides;
  560. dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
  561. int numareas;
  562. darea_t dareas[MAX_MAP_AREAS];
  563. int numareaportals;
  564. dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
  565. int numworldlightsLDR;
  566. dworldlight_t dworldlightsLDR[MAX_MAP_WORLDLIGHTS];
  567. int numworldlightsHDR;
  568. dworldlight_t dworldlightsHDR[MAX_MAP_WORLDLIGHTS];
  569. int *pNumworldlights = &numworldlightsLDR;
  570. dworldlight_t *dworldlights = dworldlightsLDR;
  571. int numleafwaterdata = 0;
  572. dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
  573. CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
  574. Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
  575. int g_nClipPortalVerts;
  576. dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
  577. int g_nCubemapSamples = 0;
  578. int g_nOverlayCount;
  579. doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
  580. doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS];
  581. int g_nWaterOverlayCount;
  582. dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
  583. CUtlVector<char> g_TexDataStringData;
  584. CUtlVector<int> g_TexDataStringTable;
  585. byte *g_pPhysCollide = NULL;
  586. int g_PhysCollideSize = 0;
  587. int g_MapRevision = 0;
  588. byte *g_pPhysDisp = NULL;
  589. int g_PhysDispSize = 0;
  590. CUtlVector<doccluderdata_t> g_OccluderData( 256, 256 );
  591. CUtlVector<doccluderpolydata_t> g_OccluderPolyData( 1024, 1024 );
  592. CUtlVector<int> g_OccluderVertexIndices( 2048, 2048 );
  593. template <class T> static void WriteData( T *pData, int count = 1 );
  594. template <class T> static void WriteData( int fieldType, T *pData, int count = 1 );
  595. template< class T > static void AddLump( int lumpnum, T *pData, int count, int version = 0 );
  596. template< class T > static void AddLump( int lumpnum, CUtlVector<T> &data, int version = 0 );
  597. dheader_t *g_pBSPHeader;
  598. FileHandle_t g_hBSPFile;
  599. struct Lump_t
  600. {
  601. void *pLumps[HEADER_LUMPS];
  602. int size[HEADER_LUMPS];
  603. bool bLumpParsed[HEADER_LUMPS];
  604. } g_Lumps;
  605. CGameLump g_GameLumps;
  606. static IZip *s_pakFile = 0;
  607. //-----------------------------------------------------------------------------
  608. // Keep the file position aligned to an arbitrary boundary.
  609. // Returns updated file position.
  610. //-----------------------------------------------------------------------------
  611. static unsigned int AlignFilePosition( FileHandle_t hFile, int alignment )
  612. {
  613. unsigned int currPosition = g_pFileSystem->Tell( hFile );
  614. if ( alignment >= 2 )
  615. {
  616. unsigned int newPosition = AlignValue( currPosition, alignment );
  617. unsigned int count = newPosition - currPosition;
  618. if ( count )
  619. {
  620. char *pBuffer;
  621. char smallBuffer[4096];
  622. if ( count > sizeof( smallBuffer ) )
  623. {
  624. pBuffer = (char *)malloc( count );
  625. }
  626. else
  627. {
  628. pBuffer = smallBuffer;
  629. }
  630. memset( pBuffer, 0, count );
  631. SafeWrite( hFile, pBuffer, count );
  632. if ( pBuffer != smallBuffer )
  633. {
  634. free( pBuffer );
  635. }
  636. currPosition = newPosition;
  637. }
  638. }
  639. return currPosition;
  640. }
  641. //-----------------------------------------------------------------------------
  642. // Purpose: // Get a pakfile instance
  643. // Output : IZip*
  644. //-----------------------------------------------------------------------------
  645. IZip* GetPakFile( void )
  646. {
  647. if ( !s_pakFile )
  648. {
  649. s_pakFile = IZip::CreateZip();
  650. }
  651. return s_pakFile;
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose: Free the pak files
  655. //-----------------------------------------------------------------------------
  656. void ReleasePakFileLumps( void )
  657. {
  658. // Release the pak files
  659. IZip::ReleaseZip( s_pakFile );
  660. s_pakFile = NULL;
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Purpose: Set the sector alignment for all subsequent zip operations
  664. //-----------------------------------------------------------------------------
  665. void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize )
  666. {
  667. pak->ForceAlignment( bAlign, bCompatibleFormat, alignmentSize );
  668. }
  669. //-----------------------------------------------------------------------------
  670. // Purpose: Store data back out to .bsp file
  671. //-----------------------------------------------------------------------------
  672. static void WritePakFileLump( void )
  673. {
  674. CUtlBuffer buf( 0, 0 );
  675. GetPakFile()->ActivateByteSwapping( IsX360() );
  676. GetPakFile()->SaveToBuffer( buf );
  677. // must respect pak file alignment
  678. // pad up and ensure lump starts on same aligned boundary
  679. AlignFilePosition( g_hBSPFile, GetPakFile()->GetAlignment() );
  680. // Now store final buffers out to file
  681. AddLump( LUMP_PAKFILE, (byte*)buf.Base(), buf.TellPut() );
  682. }
  683. //-----------------------------------------------------------------------------
  684. // Purpose: Remove all entries
  685. //-----------------------------------------------------------------------------
  686. void ClearPakFile( IZip *pak )
  687. {
  688. pak->Reset();
  689. }
  690. //-----------------------------------------------------------------------------
  691. // Purpose: Add file from disk to .bsp PAK lump
  692. // Input : *relativename -
  693. // *fullpath -
  694. //-----------------------------------------------------------------------------
  695. void AddFileToPak( IZip *pak, const char *relativename, const char *fullpath, IZip::eCompressionType compressionType )
  696. {
  697. DevMsg( "Adding file to pakfile [ %s ]\n", fullpath );
  698. pak->AddFileToZip( relativename, fullpath, compressionType );
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Purpose: Add buffer to .bsp PAK lump as named file
  702. // Input : *relativename -
  703. // *data -
  704. // length -
  705. //-----------------------------------------------------------------------------
  706. void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType )
  707. {
  708. pak->AddBufferToZip( pRelativeName, data, length, bTextMode, compressionType );
  709. }
  710. //-----------------------------------------------------------------------------
  711. // Purpose: Add entire directory to .bsp PAK lump as named file
  712. // Input : *relativename -
  713. // *data -
  714. // length -
  715. //-----------------------------------------------------------------------------
  716. void AddDirToPak( IZip *pak, const char *pDirPath, const char *pPakPrefix )
  717. {
  718. if ( !g_pFullFileSystem->IsDirectory( pDirPath ) )
  719. {
  720. Warning( "Passed non-directory to AddDirToPak [ %s ]\n", pDirPath );
  721. return;
  722. }
  723. DevMsg( "Adding directory to pakfile [ %s ]\n", pDirPath );
  724. // Enumerate dir
  725. char szEnumerateDir[MAX_PATH] = { 0 };
  726. V_snprintf( szEnumerateDir, sizeof( szEnumerateDir ), "%s/*.*", pDirPath );
  727. V_FixSlashes( szEnumerateDir );
  728. FileFindHandle_t handle;
  729. const char *szFindResult = g_pFullFileSystem->FindFirst( szEnumerateDir, &handle );
  730. do
  731. {
  732. if ( szFindResult[0] != '.' )
  733. {
  734. char szPakName[MAX_PATH] = { 0 };
  735. char szFullPath[MAX_PATH] = { 0 };
  736. if ( pPakPrefix )
  737. {
  738. V_snprintf( szPakName, sizeof( szPakName ), "%s/%s", pPakPrefix, szFindResult );
  739. }
  740. else
  741. {
  742. V_strncpy( szPakName, szFindResult, sizeof( szPakName ) );
  743. }
  744. V_snprintf( szFullPath, sizeof( szFullPath ), "%s/%s", pDirPath, szFindResult );
  745. V_FixDoubleSlashes( szFullPath );
  746. V_FixDoubleSlashes( szPakName );
  747. if ( g_pFullFileSystem->FindIsDirectory( handle ) )
  748. {
  749. // Recurse
  750. AddDirToPak( pak, szFullPath, szPakName );
  751. }
  752. else
  753. {
  754. // Just add this file
  755. AddFileToPak( pak, szPakName, szFullPath );
  756. }
  757. }
  758. szFindResult = g_pFullFileSystem->FindNext( handle );
  759. } while ( szFindResult);
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose: Check if a file already exists in the pack file.
  763. // Input : *relativename -
  764. //-----------------------------------------------------------------------------
  765. bool FileExistsInPak( IZip *pak, const char *pRelativeName )
  766. {
  767. return pak->FileExistsInZip( pRelativeName );
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Read a file from the pack file
  771. //-----------------------------------------------------------------------------
  772. bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
  773. {
  774. return pak->ReadFileFromZip( pRelativeName, bTextMode, buf );
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Purpose: Remove file from .bsp PAK lump
  778. // Input : *relativename -
  779. //-----------------------------------------------------------------------------
  780. void RemoveFileFromPak( IZip *pak, const char *relativename )
  781. {
  782. pak->RemoveFileFromZip( relativename );
  783. }
  784. //-----------------------------------------------------------------------------
  785. // Purpose: Get next filename in directory
  786. // Input : id, -1 to start, returns next id, or -1 at list conclusion
  787. //-----------------------------------------------------------------------------
  788. int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize )
  789. {
  790. return pak->GetNextFilename( id, pBuffer, bufferSize, fileSize );
  791. }
  792. //-----------------------------------------------------------------------------
  793. // Convert four-CC code to a handle + back
  794. //-----------------------------------------------------------------------------
  795. GameLumpHandle_t CGameLump::GetGameLumpHandle( GameLumpId_t id )
  796. {
  797. // NOTE: I'm also expecting game lump id's to be four-CC codes
  798. Assert( id > HEADER_LUMPS );
  799. FOR_EACH_LL(m_GameLumps, i)
  800. {
  801. if (m_GameLumps[i].m_Id == id)
  802. return i;
  803. }
  804. return InvalidGameLump();
  805. }
  806. GameLumpId_t CGameLump::GetGameLumpId( GameLumpHandle_t handle )
  807. {
  808. return m_GameLumps[handle].m_Id;
  809. }
  810. int CGameLump::GetGameLumpFlags( GameLumpHandle_t handle )
  811. {
  812. return m_GameLumps[handle].m_Flags;
  813. }
  814. int CGameLump::GetGameLumpVersion( GameLumpHandle_t handle )
  815. {
  816. return m_GameLumps[handle].m_Version;
  817. }
  818. //-----------------------------------------------------------------------------
  819. // Game lump accessor methods
  820. //-----------------------------------------------------------------------------
  821. void* CGameLump::GetGameLump( GameLumpHandle_t id )
  822. {
  823. return m_GameLumps[id].m_Memory.Base();
  824. }
  825. int CGameLump::GameLumpSize( GameLumpHandle_t id )
  826. {
  827. return m_GameLumps[id].m_Memory.NumAllocated();
  828. }
  829. //-----------------------------------------------------------------------------
  830. // Game lump iteration methods
  831. //-----------------------------------------------------------------------------
  832. GameLumpHandle_t CGameLump::FirstGameLump()
  833. {
  834. return (m_GameLumps.Count()) ? m_GameLumps.Head() : InvalidGameLump();
  835. }
  836. GameLumpHandle_t CGameLump::NextGameLump( GameLumpHandle_t handle )
  837. {
  838. return (m_GameLumps.IsValidIndex(handle)) ? m_GameLumps.Next(handle) : InvalidGameLump();
  839. }
  840. GameLumpHandle_t CGameLump::InvalidGameLump()
  841. {
  842. return 0xFFFF;
  843. }
  844. //-----------------------------------------------------------------------------
  845. // Game lump creation/destruction method
  846. //-----------------------------------------------------------------------------
  847. GameLumpHandle_t CGameLump::CreateGameLump( GameLumpId_t id, int size, int flags, int version )
  848. {
  849. Assert( GetGameLumpHandle(id) == InvalidGameLump() );
  850. GameLumpHandle_t handle = m_GameLumps.AddToTail();
  851. m_GameLumps[handle].m_Id = id;
  852. m_GameLumps[handle].m_Flags = flags;
  853. m_GameLumps[handle].m_Version = version;
  854. m_GameLumps[handle].m_Memory.EnsureCapacity( size );
  855. return handle;
  856. }
  857. void CGameLump::DestroyGameLump( GameLumpHandle_t handle )
  858. {
  859. m_GameLumps.Remove( handle );
  860. }
  861. void CGameLump::DestroyAllGameLumps()
  862. {
  863. m_GameLumps.RemoveAll();
  864. }
  865. //-----------------------------------------------------------------------------
  866. // Compute file size and clump count
  867. //-----------------------------------------------------------------------------
  868. void CGameLump::ComputeGameLumpSizeAndCount( int& size, int& clumpCount )
  869. {
  870. // Figure out total size of the client lumps
  871. size = 0;
  872. clumpCount = 0;
  873. GameLumpHandle_t h;
  874. for( h = FirstGameLump(); h != InvalidGameLump(); h = NextGameLump( h ) )
  875. {
  876. ++clumpCount;
  877. size += GameLumpSize( h );
  878. }
  879. // Add on headers
  880. size += sizeof( dgamelumpheader_t ) + clumpCount * sizeof( dgamelump_t );
  881. }
  882. void CGameLump::SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int length )
  883. {
  884. int count = 0;
  885. switch( id )
  886. {
  887. case GAMELUMP_STATIC_PROPS:
  888. // Swap the static prop model dict
  889. count = *(int*)src;
  890. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  891. count = g_bSwapOnLoad ? *(int*)dest : count;
  892. src += sizeof(int);
  893. dest += sizeof(int);
  894. g_Swap.SwapFieldsToTargetEndian( (StaticPropDictLump_t*)dest, (StaticPropDictLump_t*)src, count );
  895. src += sizeof(StaticPropDictLump_t) * count;
  896. dest += sizeof(StaticPropDictLump_t) * count;
  897. // Swap the leaf list
  898. count = *(int*)src;
  899. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  900. count = g_bSwapOnLoad ? *(int*)dest : count;
  901. src += sizeof(int);
  902. dest += sizeof(int);
  903. g_Swap.SwapFieldsToTargetEndian( (StaticPropLeafLump_t*)dest, (StaticPropLeafLump_t*)src, count );
  904. src += sizeof(StaticPropLeafLump_t) * count;
  905. dest += sizeof(StaticPropLeafLump_t) * count;
  906. // Swap the models
  907. count = *(int*)src;
  908. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  909. count = g_bSwapOnLoad ? *(int*)dest : count;
  910. src += sizeof(int);
  911. dest += sizeof(int);
  912. // The one-at-a-time swap is to compensate for these structures
  913. // possibly being misaligned, which crashes the Xbox 360.
  914. if ( version == 4 )
  915. {
  916. StaticPropLumpV4_t lump;
  917. for ( int i = 0; i < count; ++i )
  918. {
  919. Q_memcpy( &lump, src, sizeof(StaticPropLumpV4_t) );
  920. g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
  921. Q_memcpy( dest, &lump, sizeof(StaticPropLumpV4_t) );
  922. src += sizeof( StaticPropLumpV4_t );
  923. dest += sizeof( StaticPropLumpV4_t );
  924. }
  925. }
  926. else if ( version == 5 )
  927. {
  928. StaticPropLumpV5_t lump;
  929. for ( int i = 0; i < count; ++i )
  930. {
  931. Q_memcpy( &lump, src, sizeof(StaticPropLumpV5_t) );
  932. g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
  933. Q_memcpy( dest, &lump, sizeof(StaticPropLumpV5_t) );
  934. src += sizeof( StaticPropLumpV5_t );
  935. dest += sizeof( StaticPropLumpV5_t );
  936. }
  937. }
  938. else
  939. {
  940. if ( version != 6 )
  941. {
  942. Error( "Unknown Static Prop Lump version %d didn't get swapped!\n", version );
  943. }
  944. StaticPropLump_t lump;
  945. for ( int i = 0; i < count; ++i )
  946. {
  947. Q_memcpy( &lump, src, sizeof(StaticPropLump_t) );
  948. g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
  949. Q_memcpy( dest, &lump, sizeof(StaticPropLump_t) );
  950. src += sizeof( StaticPropLump_t );
  951. dest += sizeof( StaticPropLump_t );
  952. }
  953. }
  954. break;
  955. case GAMELUMP_DETAIL_PROPS:
  956. // Swap the detail prop model dict
  957. count = *(int*)src;
  958. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  959. count = g_bSwapOnLoad ? *(int*)dest : count;
  960. src += sizeof(int);
  961. dest += sizeof(int);
  962. g_Swap.SwapFieldsToTargetEndian( (DetailObjectDictLump_t*)dest, (DetailObjectDictLump_t*)src, count );
  963. src += sizeof(DetailObjectDictLump_t) * count;
  964. dest += sizeof(DetailObjectDictLump_t) * count;
  965. if ( version == 4 )
  966. {
  967. // Swap the detail sprite dict
  968. count = *(int*)src;
  969. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  970. count = g_bSwapOnLoad ? *(int*)dest : count;
  971. src += sizeof(int);
  972. dest += sizeof(int);
  973. DetailSpriteDictLump_t spritelump;
  974. for ( int i = 0; i < count; ++i )
  975. {
  976. Q_memcpy( &spritelump, src, sizeof(DetailSpriteDictLump_t) );
  977. g_Swap.SwapFieldsToTargetEndian( &spritelump, &spritelump );
  978. Q_memcpy( dest, &spritelump, sizeof(DetailSpriteDictLump_t) );
  979. src += sizeof(DetailSpriteDictLump_t);
  980. dest += sizeof(DetailSpriteDictLump_t);
  981. }
  982. // Swap the models
  983. count = *(int*)src;
  984. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  985. count = g_bSwapOnLoad ? *(int*)dest : count;
  986. src += sizeof(int);
  987. dest += sizeof(int);
  988. DetailObjectLump_t objectlump;
  989. for ( int i = 0; i < count; ++i )
  990. {
  991. Q_memcpy( &objectlump, src, sizeof(DetailObjectLump_t) );
  992. g_Swap.SwapFieldsToTargetEndian( &objectlump, &objectlump );
  993. Q_memcpy( dest, &objectlump, sizeof(DetailObjectLump_t) );
  994. src += sizeof(DetailObjectLump_t);
  995. dest += sizeof(DetailObjectLump_t);
  996. }
  997. }
  998. break;
  999. case GAMELUMP_DETAIL_PROP_LIGHTING:
  1000. // Swap the LDR light styles
  1001. count = *(int*)src;
  1002. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  1003. count = g_bSwapOnLoad ? *(int*)dest : count;
  1004. src += sizeof(int);
  1005. dest += sizeof(int);
  1006. g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
  1007. src += sizeof(DetailObjectDictLump_t) * count;
  1008. dest += sizeof(DetailObjectDictLump_t) * count;
  1009. break;
  1010. case GAMELUMP_DETAIL_PROP_LIGHTING_HDR:
  1011. // Swap the HDR light styles
  1012. count = *(int*)src;
  1013. g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
  1014. count = g_bSwapOnLoad ? *(int*)dest : count;
  1015. src += sizeof(int);
  1016. dest += sizeof(int);
  1017. g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
  1018. src += sizeof(DetailObjectDictLump_t) * count;
  1019. dest += sizeof(DetailObjectDictLump_t) * count;
  1020. break;
  1021. default:
  1022. char idchars[5] = {0};
  1023. Q_memcpy( idchars, &id, 4 );
  1024. Warning( "Unknown game lump '%s' didn't get swapped!\n", idchars );
  1025. memcpy ( dest, src, length);
  1026. break;
  1027. }
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Game lump file I/O
  1031. //-----------------------------------------------------------------------------
  1032. void CGameLump::ParseGameLump( dheader_t* pHeader )
  1033. {
  1034. g_GameLumps.DestroyAllGameLumps();
  1035. g_Lumps.bLumpParsed[LUMP_GAME_LUMP] = true;
  1036. int length = pHeader->lumps[LUMP_GAME_LUMP].filelen;
  1037. int ofs = pHeader->lumps[LUMP_GAME_LUMP].fileofs;
  1038. if (length > 0)
  1039. {
  1040. // Read dictionary...
  1041. dgamelumpheader_t* pGameLumpHeader = (dgamelumpheader_t*)((byte *)pHeader + ofs);
  1042. if ( g_bSwapOnLoad )
  1043. {
  1044. g_Swap.SwapFieldsToTargetEndian( pGameLumpHeader );
  1045. }
  1046. dgamelump_t* pGameLump = (dgamelump_t*)(pGameLumpHeader + 1);
  1047. for (int i = 0; i < pGameLumpHeader->lumpCount; ++i )
  1048. {
  1049. if ( g_bSwapOnLoad )
  1050. {
  1051. g_Swap.SwapFieldsToTargetEndian( &pGameLump[i] );
  1052. }
  1053. int length = pGameLump[i].filelen;
  1054. GameLumpHandle_t lump = g_GameLumps.CreateGameLump( pGameLump[i].id, length, pGameLump[i].flags, pGameLump[i].version );
  1055. if ( g_bSwapOnLoad )
  1056. {
  1057. SwapGameLump( pGameLump[i].id, pGameLump[i].version, (byte*)g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
  1058. }
  1059. else
  1060. {
  1061. memcpy( g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
  1062. }
  1063. }
  1064. }
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // String table methods
  1068. //-----------------------------------------------------------------------------
  1069. const char *TexDataStringTable_GetString( int stringID )
  1070. {
  1071. return &g_TexDataStringData[g_TexDataStringTable[stringID]];
  1072. }
  1073. int TexDataStringTable_AddOrFindString( const char *pString )
  1074. {
  1075. int i;
  1076. // garymcthack: Make this use an RBTree!
  1077. for( i = 0; i < g_TexDataStringTable.Count(); i++ )
  1078. {
  1079. if( stricmp( pString, &g_TexDataStringData[g_TexDataStringTable[i]] ) == 0 )
  1080. {
  1081. return i;
  1082. }
  1083. }
  1084. int len = strlen( pString );
  1085. int outOffset = g_TexDataStringData.AddMultipleToTail( len+1, pString );
  1086. int outIndex = g_TexDataStringTable.AddToTail( outOffset );
  1087. return outIndex;
  1088. }
  1089. //-----------------------------------------------------------------------------
  1090. // Adds all game lumps into one big block
  1091. //-----------------------------------------------------------------------------
  1092. static void AddGameLumps( )
  1093. {
  1094. // Figure out total size of the client lumps
  1095. int size, clumpCount;
  1096. g_GameLumps.ComputeGameLumpSizeAndCount( size, clumpCount );
  1097. // Set up the main lump dictionary entry
  1098. g_Lumps.size[LUMP_GAME_LUMP] = 0; // mark it written
  1099. lump_t* lump = &g_pBSPHeader->lumps[LUMP_GAME_LUMP];
  1100. lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
  1101. lump->filelen = size;
  1102. // write header
  1103. dgamelumpheader_t header;
  1104. header.lumpCount = clumpCount;
  1105. WriteData( &header );
  1106. // write dictionary
  1107. dgamelump_t dict;
  1108. int offset = lump->fileofs + sizeof(header) + clumpCount * sizeof(dgamelump_t);
  1109. GameLumpHandle_t h;
  1110. for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
  1111. {
  1112. dict.id = g_GameLumps.GetGameLumpId(h);
  1113. dict.version = g_GameLumps.GetGameLumpVersion(h);
  1114. dict.flags = g_GameLumps.GetGameLumpFlags(h);
  1115. dict.fileofs = offset;
  1116. dict.filelen = g_GameLumps.GameLumpSize( h );
  1117. offset += dict.filelen;
  1118. WriteData( &dict );
  1119. }
  1120. // write lumps..
  1121. for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
  1122. {
  1123. unsigned int lumpsize = g_GameLumps.GameLumpSize(h);
  1124. if ( g_bSwapOnWrite )
  1125. {
  1126. g_GameLumps.SwapGameLump( g_GameLumps.GetGameLumpId(h), g_GameLumps.GetGameLumpVersion(h), (byte*)g_GameLumps.GetGameLump(h), (byte*)g_GameLumps.GetGameLump(h), lumpsize );
  1127. }
  1128. SafeWrite( g_hBSPFile, g_GameLumps.GetGameLump(h), lumpsize );
  1129. }
  1130. // align to doubleword
  1131. AlignFilePosition( g_hBSPFile, 4 );
  1132. }
  1133. //-----------------------------------------------------------------------------
  1134. // Adds the occluder lump...
  1135. //-----------------------------------------------------------------------------
  1136. static void AddOcclusionLump( )
  1137. {
  1138. g_Lumps.size[LUMP_OCCLUSION] = 0; // mark it written
  1139. int nOccluderCount = g_OccluderData.Count();
  1140. int nOccluderPolyDataCount = g_OccluderPolyData.Count();
  1141. int nOccluderVertexIndices = g_OccluderVertexIndices.Count();
  1142. int nLumpLength = nOccluderCount * sizeof(doccluderdata_t) +
  1143. nOccluderPolyDataCount * sizeof(doccluderpolydata_t) +
  1144. nOccluderVertexIndices * sizeof(int) +
  1145. 3 * sizeof(int);
  1146. lump_t *lump = &g_pBSPHeader->lumps[LUMP_OCCLUSION];
  1147. lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
  1148. lump->filelen = nLumpLength;
  1149. lump->version = LUMP_OCCLUSION_VERSION;
  1150. lump->uncompressedSize = 0;
  1151. // Data is swapped in place, so the 'Count' variables aren't safe to use after they're written
  1152. WriteData( FIELD_INTEGER, &nOccluderCount );
  1153. WriteData( (doccluderdata_t*)g_OccluderData.Base(), g_OccluderData.Count() );
  1154. WriteData( FIELD_INTEGER, &nOccluderPolyDataCount );
  1155. WriteData( (doccluderpolydata_t*)g_OccluderPolyData.Base(), g_OccluderPolyData.Count() );
  1156. WriteData( FIELD_INTEGER, &nOccluderVertexIndices );
  1157. WriteData( FIELD_INTEGER, (int*)g_OccluderVertexIndices.Base(), g_OccluderVertexIndices.Count() );
  1158. }
  1159. //-----------------------------------------------------------------------------
  1160. // Loads the occluder lump...
  1161. //-----------------------------------------------------------------------------
  1162. static void UnserializeOcclusionLumpV2( CUtlBuffer &buf )
  1163. {
  1164. int nCount = buf.GetInt();
  1165. if ( nCount )
  1166. {
  1167. g_OccluderData.SetCount( nCount );
  1168. buf.GetObjects( g_OccluderData.Base(), nCount );
  1169. }
  1170. nCount = buf.GetInt();
  1171. if ( nCount )
  1172. {
  1173. g_OccluderPolyData.SetCount( nCount );
  1174. buf.GetObjects( g_OccluderPolyData.Base(), nCount );
  1175. }
  1176. nCount = buf.GetInt();
  1177. if ( nCount )
  1178. {
  1179. if ( g_bSwapOnLoad )
  1180. {
  1181. g_Swap.SwapBufferToTargetEndian( (int*)buf.PeekGet(), (int*)buf.PeekGet(), nCount );
  1182. }
  1183. g_OccluderVertexIndices.SetCount( nCount );
  1184. buf.Get( g_OccluderVertexIndices.Base(), nCount * sizeof(g_OccluderVertexIndices[0]) );
  1185. }
  1186. }
  1187. static void LoadOcclusionLump()
  1188. {
  1189. g_OccluderData.RemoveAll();
  1190. g_OccluderPolyData.RemoveAll();
  1191. g_OccluderVertexIndices.RemoveAll();
  1192. int length, ofs;
  1193. g_Lumps.bLumpParsed[LUMP_OCCLUSION] = true;
  1194. length = g_pBSPHeader->lumps[LUMP_OCCLUSION].filelen;
  1195. ofs = g_pBSPHeader->lumps[LUMP_OCCLUSION].fileofs;
  1196. CUtlBuffer buf( (byte *)g_pBSPHeader + ofs, length, CUtlBuffer::READ_ONLY );
  1197. buf.ActivateByteSwapping( g_bSwapOnLoad );
  1198. switch ( g_pBSPHeader->lumps[LUMP_OCCLUSION].version )
  1199. {
  1200. case 2:
  1201. UnserializeOcclusionLumpV2( buf );
  1202. break;
  1203. case 0:
  1204. break;
  1205. default:
  1206. Error("Unknown occlusion lump version!\n");
  1207. break;
  1208. }
  1209. }
  1210. /*
  1211. ===============
  1212. CompressVis
  1213. ===============
  1214. */
  1215. int CompressVis (byte *vis, byte *dest)
  1216. {
  1217. int j;
  1218. int rep;
  1219. int visrow;
  1220. byte *dest_p;
  1221. dest_p = dest;
  1222. // visrow = (r_numvisleafs + 7)>>3;
  1223. visrow = (dvis->numclusters + 7)>>3;
  1224. for (j=0 ; j<visrow ; j++)
  1225. {
  1226. *dest_p++ = vis[j];
  1227. if (vis[j])
  1228. continue;
  1229. rep = 1;
  1230. for ( j++; j<visrow ; j++)
  1231. if (vis[j] || rep == 255)
  1232. break;
  1233. else
  1234. rep++;
  1235. *dest_p++ = rep;
  1236. j--;
  1237. }
  1238. return dest_p - dest;
  1239. }
  1240. /*
  1241. ===================
  1242. DecompressVis
  1243. ===================
  1244. */
  1245. void DecompressVis (byte *in, byte *decompressed)
  1246. {
  1247. int c;
  1248. byte *out;
  1249. int row;
  1250. // row = (r_numvisleafs+7)>>3;
  1251. row = (dvis->numclusters+7)>>3;
  1252. out = decompressed;
  1253. do
  1254. {
  1255. if (*in)
  1256. {
  1257. *out++ = *in++;
  1258. continue;
  1259. }
  1260. c = in[1];
  1261. if (!c)
  1262. Error ("DecompressVis: 0 repeat");
  1263. in += 2;
  1264. if ((out - decompressed) + c > row)
  1265. {
  1266. c = row - (out - decompressed);
  1267. Warning( "warning: Vis decompression overrun\n" );
  1268. }
  1269. while (c)
  1270. {
  1271. *out++ = 0;
  1272. c--;
  1273. }
  1274. } while (out - decompressed < row);
  1275. }
  1276. //-----------------------------------------------------------------------------
  1277. // Lump-specific swap functions
  1278. //-----------------------------------------------------------------------------
  1279. struct swapcollideheader_t
  1280. {
  1281. DECLARE_BYTESWAP_DATADESC();
  1282. int size;
  1283. int vphysicsID;
  1284. short version;
  1285. short modelType;
  1286. };
  1287. struct swapcompactsurfaceheader_t : swapcollideheader_t
  1288. {
  1289. DECLARE_BYTESWAP_DATADESC();
  1290. int surfaceSize;
  1291. Vector dragAxisAreas;
  1292. int axisMapSize;
  1293. };
  1294. struct swapmoppsurfaceheader_t : swapcollideheader_t
  1295. {
  1296. DECLARE_BYTESWAP_DATADESC();
  1297. int moppSize;
  1298. };
  1299. BEGIN_BYTESWAP_DATADESC( swapcollideheader_t )
  1300. DEFINE_FIELD( size, FIELD_INTEGER ),
  1301. DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
  1302. DEFINE_FIELD( version, FIELD_SHORT ),
  1303. DEFINE_FIELD( modelType, FIELD_SHORT ),
  1304. END_BYTESWAP_DATADESC()
  1305. BEGIN_BYTESWAP_DATADESC_( swapcompactsurfaceheader_t, swapcollideheader_t )
  1306. DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
  1307. DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
  1308. DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
  1309. END_BYTESWAP_DATADESC()
  1310. BEGIN_BYTESWAP_DATADESC_( swapmoppsurfaceheader_t, swapcollideheader_t )
  1311. DEFINE_FIELD( moppSize, FIELD_INTEGER ),
  1312. END_BYTESWAP_DATADESC()
  1313. static void SwapPhyscollideLump( byte *pDestBase, byte *pSrcBase, unsigned int &count )
  1314. {
  1315. IPhysicsCollision *physcollision = NULL;
  1316. CSysModule *pPhysicsModule = g_pFullFileSystem->LoadModule( "vphysics.dll" );
  1317. if ( pPhysicsModule )
  1318. {
  1319. CreateInterfaceFn physicsFactory = Sys_GetFactory( pPhysicsModule );
  1320. if ( physicsFactory )
  1321. {
  1322. physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
  1323. }
  1324. }
  1325. if ( !physcollision )
  1326. {
  1327. Warning("!!! WARNING: Can't swap the physcollide lump!\n" );
  1328. return;
  1329. }
  1330. // physics data is variable length. The last physmodel is a NULL pointer
  1331. // with modelIndex -1, dataSize -1
  1332. dphysmodel_t *pPhysModel;
  1333. byte *pSrc = pSrcBase;
  1334. // first the src chunks have to be aligned properly
  1335. // swap increases size, allocate enough expansion room
  1336. byte *pSrcAlignedBase = (byte*)malloc( 2*count );
  1337. byte *basePtr = pSrcAlignedBase;
  1338. byte *pSrcAligned = pSrcAlignedBase;
  1339. do
  1340. {
  1341. if ( g_bSwapOnLoad )
  1342. {
  1343. g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pSrcAligned, (dphysmodel_t*)pSrc );
  1344. }
  1345. else
  1346. {
  1347. Q_memcpy( pSrcAligned, pSrc, sizeof(dphysmodel_t) );
  1348. }
  1349. pPhysModel = (dphysmodel_t*)pSrcAligned;
  1350. pSrc += sizeof(dphysmodel_t);
  1351. pSrcAligned += sizeof(dphysmodel_t);
  1352. if ( pPhysModel->dataSize > 0 )
  1353. {
  1354. // Align the collide headers
  1355. for ( int i = 0; i < pPhysModel->solidCount; ++i )
  1356. {
  1357. // Get data size
  1358. int size;
  1359. Q_memcpy( &size, pSrc, sizeof(int) );
  1360. if ( g_bSwapOnLoad )
  1361. size = SwapLong( size );
  1362. // Fixup size
  1363. int padBytes = 0;
  1364. if ( size % 4 != 0 )
  1365. {
  1366. padBytes = ( 4 - size % 4 );
  1367. count += padBytes;
  1368. pPhysModel->dataSize += padBytes;
  1369. }
  1370. // Copy data and size into alligned buffer
  1371. int newsize = size + padBytes;
  1372. if ( g_bSwapOnLoad )
  1373. newsize = SwapLong( newsize );
  1374. Q_memcpy( pSrcAligned, &newsize, sizeof(int) );
  1375. Q_memcpy( pSrcAligned + sizeof(int), pSrc + sizeof(int), size );
  1376. pSrcAligned += size + padBytes + sizeof(int);
  1377. pSrc += size + sizeof(int);
  1378. }
  1379. int padBytes = 0;
  1380. int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
  1381. Q_memcpy( pSrcAligned, pSrc, pPhysModel->keydataSize );
  1382. pSrc += pPhysModel->keydataSize;
  1383. pSrcAligned += pPhysModel->keydataSize;
  1384. if ( dataSize % 4 != 0 )
  1385. {
  1386. // Next chunk will be unaligned
  1387. padBytes = ( 4 - dataSize % 4 );
  1388. pPhysModel->keydataSize += padBytes;
  1389. count += padBytes;
  1390. Q_memset( pSrcAligned, 0, padBytes );
  1391. pSrcAligned += padBytes;
  1392. }
  1393. }
  1394. } while ( pPhysModel->dataSize > 0 );
  1395. // Now the data can be swapped properly
  1396. pSrcBase = pSrcAlignedBase;
  1397. pSrc = pSrcBase;
  1398. byte *pDest = pDestBase;
  1399. do
  1400. {
  1401. // src headers are in native format
  1402. pPhysModel = (dphysmodel_t*)pSrc;
  1403. if ( g_bSwapOnWrite )
  1404. {
  1405. g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pDest, (dphysmodel_t*)pSrc );
  1406. }
  1407. else
  1408. {
  1409. Q_memcpy( pDest, pSrc, sizeof(dphysmodel_t) );
  1410. }
  1411. pSrc += sizeof(dphysmodel_t);
  1412. pDest += sizeof(dphysmodel_t);
  1413. pSrcBase = pSrc;
  1414. pDestBase = pDest;
  1415. if ( pPhysModel->dataSize > 0 )
  1416. {
  1417. vcollide_t collide = {0};
  1418. int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
  1419. if ( g_bSwapOnWrite )
  1420. {
  1421. // Load the collide data
  1422. physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, false );
  1423. }
  1424. int *offsets = new int[ pPhysModel->solidCount ];
  1425. // Swap the collision data headers
  1426. for ( int i = 0; i < pPhysModel->solidCount; ++i )
  1427. {
  1428. int headerSize = 0;
  1429. swapcollideheader_t *baseHdr = (swapcollideheader_t*)pSrc;
  1430. short modelType = baseHdr->modelType;
  1431. if ( g_bSwapOnLoad )
  1432. {
  1433. g_Swap.SwapBufferToTargetEndian( &modelType );
  1434. }
  1435. if ( modelType == 0 ) // COLLIDE_POLY
  1436. {
  1437. headerSize = sizeof(swapcompactsurfaceheader_t);
  1438. swapcompactsurfaceheader_t swapHdr;
  1439. Q_memcpy( &swapHdr, pSrc, headerSize );
  1440. g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
  1441. Q_memcpy( pDest, &swapHdr, headerSize );
  1442. }
  1443. else if ( modelType == 1 ) // COLLIDE_MOPP
  1444. {
  1445. // The PC still unserializes these, but we don't support them
  1446. if ( g_bSwapOnWrite )
  1447. {
  1448. collide.solids[i] = NULL;
  1449. }
  1450. headerSize = sizeof(swapmoppsurfaceheader_t);
  1451. swapmoppsurfaceheader_t swapHdr;
  1452. Q_memcpy( &swapHdr, pSrc, headerSize );
  1453. g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
  1454. Q_memcpy( pDest, &swapHdr, headerSize );
  1455. }
  1456. else
  1457. {
  1458. // Shouldn't happen
  1459. Assert( 0 );
  1460. }
  1461. if ( g_bSwapOnLoad )
  1462. {
  1463. // src needs the native header data to load the vcollides
  1464. Q_memcpy( pSrc, pDest, headerSize );
  1465. }
  1466. // HACK: Need either surfaceSize or moppSize - both sit at the same offset in the structure
  1467. swapmoppsurfaceheader_t *hdr = (swapmoppsurfaceheader_t*)pSrc;
  1468. pSrc += hdr->size + sizeof(int);
  1469. pDest += hdr->size + sizeof(int);
  1470. offsets[i] = hdr->size;
  1471. }
  1472. pSrc = pSrcBase;
  1473. pDest = pDestBase;
  1474. if ( g_bSwapOnLoad )
  1475. {
  1476. physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, true );
  1477. }
  1478. // Write out the ledge tree data
  1479. for ( int i = 0; i < pPhysModel->solidCount; ++i )
  1480. {
  1481. if ( collide.solids[i] )
  1482. {
  1483. // skip over the size member
  1484. pSrc += sizeof(int);
  1485. pDest += sizeof(int);
  1486. int offset = physcollision->CollideWrite( (char*)pDest, collide.solids[i], g_bSwapOnWrite );
  1487. pSrc += offset;
  1488. pDest += offset;
  1489. }
  1490. else
  1491. {
  1492. pSrc += offsets[i] + sizeof(int);
  1493. pDest += offsets[i] + sizeof(int);
  1494. }
  1495. }
  1496. // copy the keyvalues data
  1497. Q_memcpy( pDest, pSrc, pPhysModel->keydataSize );
  1498. pDest += pPhysModel->keydataSize;
  1499. pSrc += pPhysModel->keydataSize;
  1500. // Free the memory
  1501. physcollision->VCollideUnload( &collide );
  1502. delete [] offsets;
  1503. }
  1504. // avoid infinite loop on badly formed file
  1505. if ( (pSrc - basePtr) > count )
  1506. break;
  1507. } while ( pPhysModel->dataSize > 0 );
  1508. free( pSrcAlignedBase );
  1509. }
  1510. // UNDONE: This code is not yet tested.
  1511. static void SwapPhysdispLump( byte *pDest, byte *pSrc, int count )
  1512. {
  1513. // the format of this lump is one unsigned short dispCount, then dispCount unsigned shorts of sizes
  1514. // followed by an array of variable length (each element is the length of the corresponding entry in the
  1515. // previous table) byte-stream data structure of the displacement collision models
  1516. // these byte-stream structs are endian-neutral because each element is byte-sized
  1517. unsigned short dispCount = *(unsigned short*)pSrc;
  1518. if ( g_bSwapOnLoad )
  1519. {
  1520. g_Swap.SwapBufferToTargetEndian( &dispCount );
  1521. }
  1522. g_Swap.SwapBufferToTargetEndian( (unsigned short*)pDest, (unsigned short*)pSrc, dispCount + 1 );
  1523. const int nBytes = (dispCount + 1) * sizeof( unsigned short );
  1524. pSrc += nBytes;
  1525. pDest += nBytes;
  1526. count -= nBytes;
  1527. g_Swap.SwapBufferToTargetEndian( pDest, pSrc, count );
  1528. }
  1529. static void SwapVisibilityLump( byte *pDest, byte *pSrc, int count )
  1530. {
  1531. int firstInt = *(int*)pSrc;
  1532. if ( g_bSwapOnLoad )
  1533. {
  1534. g_Swap.SwapBufferToTargetEndian( &firstInt );
  1535. }
  1536. int intCt = firstInt * 2 + 1;
  1537. const int hdrSize = intCt * sizeof(int);
  1538. g_Swap.SwapBufferToTargetEndian( (int*)pDest, (int*)pSrc, intCt );
  1539. g_Swap.SwapBufferToTargetEndian( pDest + hdrSize, pSrc + hdrSize, count - hdrSize );
  1540. }
  1541. //=============================================================================
  1542. void Lumps_Init( void )
  1543. {
  1544. memset( &g_Lumps, 0, sizeof(g_Lumps) );
  1545. }
  1546. int LumpVersion( int lump )
  1547. {
  1548. return g_pBSPHeader->lumps[lump].version;
  1549. }
  1550. bool HasLump( int lump )
  1551. {
  1552. return g_pBSPHeader->lumps[lump].filelen > 0;
  1553. }
  1554. void ValidateLump( int lump, int length, int size, int forceVersion )
  1555. {
  1556. if ( length % size )
  1557. {
  1558. Error( "ValidateLump: odd size for lump %d", lump );
  1559. }
  1560. if ( forceVersion >= 0 && forceVersion != g_pBSPHeader->lumps[lump].version )
  1561. {
  1562. Error( "ValidateLump: old version for lump %d in map!", lump );
  1563. }
  1564. }
  1565. //-----------------------------------------------------------------------------
  1566. // Add Lumps of integral types without datadescs
  1567. //-----------------------------------------------------------------------------
  1568. template< class T >
  1569. int CopyLumpInternal( int fieldType, int lump, T *dest, int forceVersion )
  1570. {
  1571. g_Lumps.bLumpParsed[lump] = true;
  1572. // Vectors are passed in as floats
  1573. int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
  1574. unsigned int length = g_pBSPHeader->lumps[lump].filelen;
  1575. unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
  1576. // count must be of the integral type
  1577. unsigned int count = length / sizeof(T);
  1578. ValidateLump( lump, length, fieldSize, forceVersion );
  1579. if ( g_bSwapOnLoad )
  1580. {
  1581. switch( lump )
  1582. {
  1583. case LUMP_VISIBILITY:
  1584. SwapVisibilityLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
  1585. break;
  1586. case LUMP_PHYSCOLLIDE:
  1587. // SwapPhyscollideLump may change size
  1588. SwapPhyscollideLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
  1589. length = count;
  1590. break;
  1591. case LUMP_PHYSDISP:
  1592. SwapPhysdispLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
  1593. break;
  1594. default:
  1595. g_Swap.SwapBufferToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
  1596. break;
  1597. }
  1598. }
  1599. else
  1600. {
  1601. memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
  1602. }
  1603. // Return actual count of elements
  1604. return length / fieldSize;
  1605. }
  1606. template< class T >
  1607. int CopyLump( int fieldType, int lump, T *dest, int forceVersion = -1 )
  1608. {
  1609. return CopyLumpInternal( fieldType, lump, dest, forceVersion );
  1610. }
  1611. template< class T >
  1612. void CopyLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
  1613. {
  1614. Assert( fieldType != FIELD_VECTOR ); // TODO: Support this if necessary
  1615. dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
  1616. CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
  1617. }
  1618. template< class T >
  1619. void CopyOptionalLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
  1620. {
  1621. // not fatal if not present
  1622. if ( !HasLump( lump ) )
  1623. return;
  1624. dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
  1625. CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
  1626. }
  1627. template< class T >
  1628. int CopyVariableLump( int fieldType, int lump, void **dest, int forceVersion = -1 )
  1629. {
  1630. int length = g_pBSPHeader->lumps[lump].filelen;
  1631. *dest = malloc( length );
  1632. return CopyLumpInternal<T>( fieldType, lump, (T*)*dest, forceVersion );
  1633. }
  1634. //-----------------------------------------------------------------------------
  1635. // Add Lumps of object types with datadescs
  1636. //-----------------------------------------------------------------------------
  1637. template< class T >
  1638. int CopyLumpInternal( int lump, T *dest, int forceVersion )
  1639. {
  1640. g_Lumps.bLumpParsed[lump] = true;
  1641. unsigned int length = g_pBSPHeader->lumps[lump].filelen;
  1642. unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
  1643. unsigned int count = length / sizeof(T);
  1644. ValidateLump( lump, length, sizeof(T), forceVersion );
  1645. if ( g_bSwapOnLoad )
  1646. {
  1647. g_Swap.SwapFieldsToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
  1648. }
  1649. else
  1650. {
  1651. memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
  1652. }
  1653. return count;
  1654. }
  1655. template< class T >
  1656. int CopyLump( int lump, T *dest, int forceVersion = -1 )
  1657. {
  1658. return CopyLumpInternal( lump, dest, forceVersion );
  1659. }
  1660. template< class T >
  1661. void CopyLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
  1662. {
  1663. dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
  1664. CopyLumpInternal( lump, dest.Base(), forceVersion );
  1665. }
  1666. template< class T >
  1667. void CopyOptionalLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
  1668. {
  1669. // not fatal if not present
  1670. if ( !HasLump( lump ) )
  1671. return;
  1672. dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
  1673. CopyLumpInternal( lump, dest.Base(), forceVersion );
  1674. }
  1675. template< class T >
  1676. int CopyVariableLump( int lump, void **dest, int forceVersion = -1 )
  1677. {
  1678. int length = g_pBSPHeader->lumps[lump].filelen;
  1679. *dest = malloc( length );
  1680. return CopyLumpInternal<T>( lump, (T*)*dest, forceVersion );
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. // Add/Write unknown lumps
  1684. //-----------------------------------------------------------------------------
  1685. void Lumps_Parse( void )
  1686. {
  1687. int i;
  1688. for ( i = 0; i < HEADER_LUMPS; i++ )
  1689. {
  1690. if ( !g_Lumps.bLumpParsed[i] && g_pBSPHeader->lumps[i].filelen )
  1691. {
  1692. g_Lumps.size[i] = CopyVariableLump<byte>( FIELD_CHARACTER, i, &g_Lumps.pLumps[i], -1 );
  1693. Msg( "Reading unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
  1694. }
  1695. }
  1696. }
  1697. void Lumps_Write( void )
  1698. {
  1699. int i;
  1700. for ( i = 0; i < HEADER_LUMPS; i++ )
  1701. {
  1702. if ( g_Lumps.size[i] )
  1703. {
  1704. Msg( "Writing unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
  1705. AddLump( i, (byte*)g_Lumps.pLumps[i], g_Lumps.size[i] );
  1706. }
  1707. if ( g_Lumps.pLumps[i] )
  1708. {
  1709. free( g_Lumps.pLumps[i] );
  1710. g_Lumps.pLumps[i] = NULL;
  1711. }
  1712. }
  1713. }
  1714. int LoadLeafs( void )
  1715. {
  1716. #if defined( BSP_USE_LESS_MEMORY )
  1717. dleafs = (dleaf_t*)malloc( g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
  1718. #endif
  1719. switch ( LumpVersion( LUMP_LEAFS ) )
  1720. {
  1721. case 0:
  1722. {
  1723. g_Lumps.bLumpParsed[LUMP_LEAFS] = true;
  1724. int length = g_pBSPHeader->lumps[LUMP_LEAFS].filelen;
  1725. int size = sizeof( dleaf_version_0_t );
  1726. if ( length % size )
  1727. {
  1728. Error( "odd size for LUMP_LEAFS\n" );
  1729. }
  1730. int count = length / size;
  1731. void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAFS].fileofs );
  1732. dleaf_version_0_t *pSrc = (dleaf_version_0_t *)pSrcBase;
  1733. dleaf_t *pDst = dleafs;
  1734. // version 0 predates HDR, build the LDR
  1735. g_LeafAmbientLightingLDR.SetCount( count );
  1736. g_LeafAmbientIndexLDR.SetCount( count );
  1737. dleafambientlighting_t *pDstLeafAmbientLighting = &g_LeafAmbientLightingLDR[0];
  1738. for ( int i = 0; i < count; i++ )
  1739. {
  1740. g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
  1741. g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
  1742. if ( g_bSwapOnLoad )
  1743. {
  1744. g_Swap.SwapFieldsToTargetEndian( pSrc );
  1745. }
  1746. // pDst is a subset of pSrc;
  1747. *pDst = *( ( dleaf_t * )( void * )pSrc );
  1748. pDstLeafAmbientLighting->cube = pSrc->m_AmbientLighting;
  1749. pDstLeafAmbientLighting->x = pDstLeafAmbientLighting->y = pDstLeafAmbientLighting->z = pDstLeafAmbientLighting->pad = 0;
  1750. pDst++;
  1751. pSrc++;
  1752. pDstLeafAmbientLighting++;
  1753. }
  1754. return count;
  1755. }
  1756. case 1:
  1757. return CopyLump( LUMP_LEAFS, dleafs );
  1758. default:
  1759. Assert( 0 );
  1760. Error( "Unknown LUMP_LEAFS version\n" );
  1761. return 0;
  1762. }
  1763. }
  1764. void LoadLeafAmbientLighting( int numLeafs )
  1765. {
  1766. if ( LumpVersion( LUMP_LEAFS ) == 0 )
  1767. {
  1768. // an older leaf version already built the LDR ambient lighting on load
  1769. return;
  1770. }
  1771. // old BSP with ambient, or new BSP with no lighting, convert ambient light to new format or create dummy ambient
  1772. if ( !HasLump( LUMP_LEAF_AMBIENT_INDEX ) )
  1773. {
  1774. // a bunch of legacy maps, have these lumps with garbage versions
  1775. // expect them to be NOT the current version
  1776. if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING) )
  1777. {
  1778. Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
  1779. }
  1780. if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING_HDR) )
  1781. {
  1782. Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
  1783. }
  1784. void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].fileofs );
  1785. CompressedLightCube *pSrc = NULL;
  1786. if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING ) )
  1787. {
  1788. pSrc = (CompressedLightCube*)pSrcBase;
  1789. }
  1790. g_LeafAmbientIndexLDR.SetCount( numLeafs );
  1791. g_LeafAmbientLightingLDR.SetCount( numLeafs );
  1792. void *pSrcBaseHDR = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].fileofs );
  1793. CompressedLightCube *pSrcHDR = NULL;
  1794. if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
  1795. {
  1796. pSrcHDR = (CompressedLightCube*)pSrcBaseHDR;
  1797. }
  1798. g_LeafAmbientIndexHDR.SetCount( numLeafs );
  1799. g_LeafAmbientLightingHDR.SetCount( numLeafs );
  1800. for ( int i = 0; i < numLeafs; i++ )
  1801. {
  1802. g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
  1803. g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
  1804. g_LeafAmbientIndexHDR[i].ambientSampleCount = 1;
  1805. g_LeafAmbientIndexHDR[i].firstAmbientSample = i;
  1806. Q_memset( &g_LeafAmbientLightingLDR[i], 0, sizeof(g_LeafAmbientLightingLDR[i]) );
  1807. Q_memset( &g_LeafAmbientLightingHDR[i], 0, sizeof(g_LeafAmbientLightingHDR[i]) );
  1808. if ( pSrc )
  1809. {
  1810. if ( g_bSwapOnLoad )
  1811. {
  1812. g_Swap.SwapFieldsToTargetEndian( &pSrc[i] );
  1813. }
  1814. g_LeafAmbientLightingLDR[i].cube = pSrc[i];
  1815. }
  1816. if ( pSrcHDR )
  1817. {
  1818. if ( g_bSwapOnLoad )
  1819. {
  1820. g_Swap.SwapFieldsToTargetEndian( &pSrcHDR[i] );
  1821. }
  1822. g_LeafAmbientLightingHDR[i].cube = pSrcHDR[i];
  1823. }
  1824. }
  1825. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
  1826. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
  1827. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
  1828. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
  1829. }
  1830. else
  1831. {
  1832. CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR );
  1833. CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
  1834. CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR );
  1835. CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
  1836. }
  1837. }
  1838. void ValidateHeader( const char *filename, const dheader_t *pHeader )
  1839. {
  1840. if ( pHeader->ident != IDBSPHEADER )
  1841. {
  1842. Error ("%s is not a IBSP file", filename);
  1843. }
  1844. if ( pHeader->version < MINBSPVERSION || pHeader->version > BSPVERSION )
  1845. {
  1846. Error ("%s is version %i, not %i", filename, pHeader->version, BSPVERSION);
  1847. }
  1848. }
  1849. //-----------------------------------------------------------------------------
  1850. // Low level BSP opener for external parsing. Parses headers, but nothing else.
  1851. // You must close the BSP, via CloseBSPFile().
  1852. //-----------------------------------------------------------------------------
  1853. void OpenBSPFile( const char *filename )
  1854. {
  1855. Lumps_Init();
  1856. // load the file header
  1857. LoadFile( filename, (void **)&g_pBSPHeader );
  1858. if ( g_bSwapOnLoad )
  1859. {
  1860. g_Swap.ActivateByteSwapping( true );
  1861. g_Swap.SwapFieldsToTargetEndian( g_pBSPHeader );
  1862. }
  1863. ValidateHeader( filename, g_pBSPHeader );
  1864. g_MapRevision = g_pBSPHeader->mapRevision;
  1865. }
  1866. //-----------------------------------------------------------------------------
  1867. // CloseBSPFile
  1868. //-----------------------------------------------------------------------------
  1869. void CloseBSPFile( void )
  1870. {
  1871. free( g_pBSPHeader );
  1872. g_pBSPHeader = NULL;
  1873. }
  1874. //-----------------------------------------------------------------------------
  1875. // LoadBSPFile
  1876. //-----------------------------------------------------------------------------
  1877. void LoadBSPFile( const char *filename )
  1878. {
  1879. OpenBSPFile( filename );
  1880. nummodels = CopyLump( LUMP_MODELS, dmodels );
  1881. numvertexes = CopyLump( LUMP_VERTEXES, dvertexes );
  1882. numplanes = CopyLump( LUMP_PLANES, dplanes );
  1883. numleafs = LoadLeafs();
  1884. numnodes = CopyLump( LUMP_NODES, dnodes );
  1885. CopyLump( LUMP_TEXINFO, texinfo );
  1886. numtexdata = CopyLump( LUMP_TEXDATA, dtexdata );
  1887. CopyLump( LUMP_DISPINFO, g_dispinfo );
  1888. CopyLump( LUMP_DISP_VERTS, g_DispVerts );
  1889. CopyLump( LUMP_DISP_TRIS, g_DispTris );
  1890. CopyLump( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
  1891. CopyLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
  1892. numfaces = CopyLump(LUMP_FACES, dfaces, LUMP_FACES_VERSION);
  1893. if ( HasLump( LUMP_FACES_HDR ) )
  1894. numfaces_hdr = CopyLump( LUMP_FACES_HDR, dfaces_hdr, LUMP_FACES_VERSION );
  1895. else
  1896. numfaces_hdr = 0;
  1897. CopyOptionalLump( LUMP_FACEIDS, dfaceids );
  1898. g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives );
  1899. g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts );
  1900. g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices );
  1901. numorigfaces = CopyLump( LUMP_ORIGINALFACES, dorigfaces ); // original faces
  1902. numleaffaces = CopyLump( FIELD_SHORT, LUMP_LEAFFACES, dleaffaces );
  1903. numleafbrushes = CopyLump( FIELD_SHORT, LUMP_LEAFBRUSHES, dleafbrushes );
  1904. numsurfedges = CopyLump( FIELD_INTEGER, LUMP_SURFEDGES, dsurfedges );
  1905. numedges = CopyLump( LUMP_EDGES, dedges );
  1906. numbrushes = CopyLump( LUMP_BRUSHES, dbrushes );
  1907. numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides );
  1908. numareas = CopyLump( LUMP_AREAS, dareas );
  1909. numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals );
  1910. visdatasize = CopyLump ( FIELD_CHARACTER, LUMP_VISIBILITY, dvisdata );
  1911. CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
  1912. CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
  1913. LoadLeafAmbientLighting( numleafs );
  1914. CopyLump( FIELD_CHARACTER, LUMP_ENTITIES, dentdata );
  1915. numworldlightsLDR = CopyLump( LUMP_WORLDLIGHTS, dworldlightsLDR );
  1916. numworldlightsHDR = CopyLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR );
  1917. numleafwaterdata = CopyLump( LUMP_LEAFWATERDATA, dleafwaterdata );
  1918. g_PhysCollideSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide );
  1919. g_PhysDispSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSDISP, (void**)&g_pPhysDisp );
  1920. g_numvertnormals = CopyLump( FIELD_VECTOR, LUMP_VERTNORMALS, (float*)g_vertnormals );
  1921. g_numvertnormalindices = CopyLump( FIELD_SHORT, LUMP_VERTNORMALINDICES, g_vertnormalindices );
  1922. g_nClipPortalVerts = CopyLump( FIELD_VECTOR, LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts );
  1923. g_nCubemapSamples = CopyLump( LUMP_CUBEMAPS, g_CubemapSamples );
  1924. CopyLump( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
  1925. CopyLump( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
  1926. g_nOverlayCount = CopyLump( LUMP_OVERLAYS, g_Overlays );
  1927. g_nWaterOverlayCount = CopyLump( LUMP_WATEROVERLAYS, g_WaterOverlays );
  1928. CopyLump( LUMP_OVERLAY_FADES, g_OverlayFades );
  1929. dflagslump_t flags_lump;
  1930. if ( HasLump( LUMP_MAP_FLAGS ) )
  1931. CopyLump ( LUMP_MAP_FLAGS, &flags_lump );
  1932. else
  1933. memset( &flags_lump, 0, sizeof( flags_lump ) ); // default flags to 0
  1934. g_LevelFlags = flags_lump.m_LevelFlags;
  1935. LoadOcclusionLump();
  1936. CopyLump( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater );
  1937. /*
  1938. int crap;
  1939. for( crap = 0; crap < g_nBSPStringTable; crap++ )
  1940. {
  1941. Msg( "stringtable %d", ( int )crap );
  1942. Msg( " %d:", ( int )g_BSPStringTable[crap] );
  1943. puts( &g_BSPStringData[g_BSPStringTable[crap]] );
  1944. puts( "\n" );
  1945. }
  1946. */
  1947. // Load PAK file lump into appropriate data structure
  1948. byte *pakbuffer = NULL;
  1949. int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
  1950. if ( paksize > 0 )
  1951. {
  1952. GetPakFile()->ActivateByteSwapping( IsX360() );
  1953. GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
  1954. }
  1955. else
  1956. {
  1957. GetPakFile()->Reset();
  1958. }
  1959. free( pakbuffer );
  1960. g_GameLumps.ParseGameLump( g_pBSPHeader );
  1961. // NOTE: Do NOT call CopyLump after Lumps_Parse() it parses all un-Copied lumps
  1962. // parse any additional lumps
  1963. Lumps_Parse();
  1964. // everything has been copied out
  1965. CloseBSPFile();
  1966. g_Swap.ActivateByteSwapping( false );
  1967. }
  1968. //-----------------------------------------------------------------------------
  1969. // Reset any state.
  1970. //-----------------------------------------------------------------------------
  1971. void UnloadBSPFile()
  1972. {
  1973. nummodels = 0;
  1974. numvertexes = 0;
  1975. numplanes = 0;
  1976. numleafs = 0;
  1977. #if defined( BSP_USE_LESS_MEMORY )
  1978. if ( dleafs )
  1979. {
  1980. free( dleafs );
  1981. dleafs = NULL;
  1982. }
  1983. #endif
  1984. numnodes = 0;
  1985. texinfo.Purge();
  1986. numtexdata = 0;
  1987. g_dispinfo.Purge();
  1988. g_DispVerts.Purge();
  1989. g_DispTris.Purge();
  1990. g_DispLightmapSamplePositions.Purge();
  1991. g_FaceMacroTextureInfos.Purge();
  1992. numfaces = 0;
  1993. numfaces_hdr = 0;
  1994. dfaceids.Purge();
  1995. g_numprimitives = 0;
  1996. g_numprimverts = 0;
  1997. g_numprimindices = 0;
  1998. numorigfaces = 0;
  1999. numleaffaces = 0;
  2000. numleafbrushes = 0;
  2001. numsurfedges = 0;
  2002. numedges = 0;
  2003. numbrushes = 0;
  2004. numbrushsides = 0;
  2005. numareas = 0;
  2006. numareaportals = 0;
  2007. visdatasize = 0;
  2008. dlightdataLDR.Purge();
  2009. dlightdataHDR.Purge();
  2010. g_LeafAmbientLightingLDR.Purge();
  2011. g_LeafAmbientLightingHDR.Purge();
  2012. g_LeafAmbientIndexHDR.Purge();
  2013. g_LeafAmbientIndexLDR.Purge();
  2014. dentdata.Purge();
  2015. numworldlightsLDR = 0;
  2016. numworldlightsHDR = 0;
  2017. numleafwaterdata = 0;
  2018. if ( g_pPhysCollide )
  2019. {
  2020. free( g_pPhysCollide );
  2021. g_pPhysCollide = NULL;
  2022. }
  2023. g_PhysCollideSize = 0;
  2024. if ( g_pPhysDisp )
  2025. {
  2026. free( g_pPhysDisp );
  2027. g_pPhysDisp = NULL;
  2028. }
  2029. g_PhysDispSize = 0;
  2030. g_numvertnormals = 0;
  2031. g_numvertnormalindices = 0;
  2032. g_nClipPortalVerts = 0;
  2033. g_nCubemapSamples = 0;
  2034. g_TexDataStringData.Purge();
  2035. g_TexDataStringTable.Purge();
  2036. g_nOverlayCount = 0;
  2037. g_nWaterOverlayCount = 0;
  2038. g_LevelFlags = 0;
  2039. g_OccluderData.Purge();
  2040. g_OccluderPolyData.Purge();
  2041. g_OccluderVertexIndices.Purge();
  2042. g_GameLumps.DestroyAllGameLumps();
  2043. for ( int i = 0; i < HEADER_LUMPS; i++ )
  2044. {
  2045. if ( g_Lumps.pLumps[i] )
  2046. {
  2047. free( g_Lumps.pLumps[i] );
  2048. g_Lumps.pLumps[i] = NULL;
  2049. }
  2050. }
  2051. ReleasePakFileLumps();
  2052. }
  2053. //-----------------------------------------------------------------------------
  2054. // LoadBSPFileFilesystemOnly
  2055. //-----------------------------------------------------------------------------
  2056. void LoadBSPFile_FileSystemOnly( const char *filename )
  2057. {
  2058. Lumps_Init();
  2059. //
  2060. // load the file header
  2061. //
  2062. LoadFile( filename, (void **)&g_pBSPHeader );
  2063. ValidateHeader( filename, g_pBSPHeader );
  2064. // Load PAK file lump into appropriate data structure
  2065. byte *pakbuffer = NULL;
  2066. int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer, 1 );
  2067. if ( paksize > 0 )
  2068. {
  2069. GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
  2070. }
  2071. else
  2072. {
  2073. GetPakFile()->Reset();
  2074. }
  2075. free( pakbuffer );
  2076. // everything has been copied out
  2077. free( g_pBSPHeader );
  2078. g_pBSPHeader = NULL;
  2079. }
  2080. void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName )
  2081. {
  2082. Lumps_Init();
  2083. //
  2084. // load the file header
  2085. //
  2086. LoadFile( pBSPFileName, (void **)&g_pBSPHeader);
  2087. ValidateHeader( pBSPFileName, g_pBSPHeader );
  2088. byte *pakbuffer = NULL;
  2089. int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
  2090. if ( paksize > 0 )
  2091. {
  2092. FILE *fp;
  2093. fp = fopen( pZipFileName, "wb" );
  2094. if( !fp )
  2095. {
  2096. fprintf( stderr, "can't open %s\n", pZipFileName );
  2097. return;
  2098. }
  2099. fwrite( pakbuffer, paksize, 1, fp );
  2100. fclose( fp );
  2101. }
  2102. else
  2103. {
  2104. fprintf( stderr, "zip file is zero length!\n" );
  2105. }
  2106. }
  2107. /*
  2108. =============
  2109. LoadBSPFileTexinfo
  2110. Only loads the texinfo lump, so qdata can scan for textures
  2111. =============
  2112. */
  2113. void LoadBSPFileTexinfo( const char *filename )
  2114. {
  2115. FILE *f;
  2116. int length, ofs;
  2117. g_pBSPHeader = (dheader_t*)malloc( sizeof(dheader_t) );
  2118. f = fopen( filename, "rb" );
  2119. fread( g_pBSPHeader, sizeof(dheader_t), 1, f);
  2120. ValidateHeader( filename, g_pBSPHeader );
  2121. length = g_pBSPHeader->lumps[LUMP_TEXINFO].filelen;
  2122. ofs = g_pBSPHeader->lumps[LUMP_TEXINFO].fileofs;
  2123. int nCount = length / sizeof(texinfo_t);
  2124. texinfo.Purge();
  2125. texinfo.AddMultipleToTail( nCount );
  2126. fseek( f, ofs, SEEK_SET );
  2127. fread( texinfo.Base(), length, 1, f );
  2128. fclose( f );
  2129. // everything has been copied out
  2130. free( g_pBSPHeader );
  2131. g_pBSPHeader = NULL;
  2132. }
  2133. static void AddLumpInternal( int lumpnum, void *data, int len, int version )
  2134. {
  2135. lump_t *lump;
  2136. g_Lumps.size[lumpnum] = 0; // mark it written
  2137. lump = &g_pBSPHeader->lumps[lumpnum];
  2138. lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
  2139. lump->filelen = len;
  2140. lump->version = version;
  2141. lump->uncompressedSize = 0;
  2142. SafeWrite( g_hBSPFile, data, len );
  2143. // pad out to the next dword
  2144. AlignFilePosition( g_hBSPFile, 4 );
  2145. }
  2146. template< class T >
  2147. static void SwapInPlace( T *pData, int count )
  2148. {
  2149. if ( !pData )
  2150. return;
  2151. // use the datadesc to swap the fields in place
  2152. g_Swap.SwapFieldsToTargetEndian<T>( (T*)pData, pData, count );
  2153. }
  2154. template< class T >
  2155. static void SwapInPlace( int fieldType, T *pData, int count )
  2156. {
  2157. if ( !pData )
  2158. return;
  2159. // swap the data in place
  2160. g_Swap.SwapBufferToTargetEndian<T>( (T*)pData, (T*)pData, count );
  2161. }
  2162. //-----------------------------------------------------------------------------
  2163. // Add raw data chunk to file (not a lump)
  2164. //-----------------------------------------------------------------------------
  2165. template< class T >
  2166. static void WriteData( int fieldType, T *pData, int count )
  2167. {
  2168. if ( g_bSwapOnWrite )
  2169. {
  2170. SwapInPlace( fieldType, pData, count );
  2171. }
  2172. SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
  2173. }
  2174. template< class T >
  2175. static void WriteData( T *pData, int count )
  2176. {
  2177. if ( g_bSwapOnWrite )
  2178. {
  2179. SwapInPlace( pData, count );
  2180. }
  2181. SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
  2182. }
  2183. //-----------------------------------------------------------------------------
  2184. // Add Lump of object types with datadescs
  2185. //-----------------------------------------------------------------------------
  2186. template< class T >
  2187. static void AddLump( int lumpnum, T *pData, int count, int version )
  2188. {
  2189. AddLumpInternal( lumpnum, pData, count * sizeof(T), version );
  2190. }
  2191. template< class T >
  2192. static void AddLump( int lumpnum, CUtlVector<T> &data, int version )
  2193. {
  2194. AddLumpInternal( lumpnum, data.Base(), data.Count() * sizeof(T), version );
  2195. }
  2196. /*
  2197. =============
  2198. WriteBSPFile
  2199. Swaps the bsp file in place, so it should not be referenced again
  2200. =============
  2201. */
  2202. void WriteBSPFile( const char *filename, char *pUnused )
  2203. {
  2204. if ( texinfo.Count() > MAX_MAP_TEXINFO )
  2205. {
  2206. Error( "Map has too many texinfos (has %d, can have at most %d)\n", texinfo.Count(), MAX_MAP_TEXINFO );
  2207. return;
  2208. }
  2209. dheader_t outHeader;
  2210. g_pBSPHeader = &outHeader;
  2211. memset( g_pBSPHeader, 0, sizeof( dheader_t ) );
  2212. g_pBSPHeader->ident = IDBSPHEADER;
  2213. g_pBSPHeader->version = BSPVERSION;
  2214. g_pBSPHeader->mapRevision = g_MapRevision;
  2215. g_hBSPFile = SafeOpenWrite( filename );
  2216. WriteData( g_pBSPHeader ); // overwritten later
  2217. AddLump( LUMP_PLANES, dplanes, numplanes );
  2218. AddLump( LUMP_LEAFS, dleafs, numleafs, LUMP_LEAFS_VERSION );
  2219. AddLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
  2220. AddLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
  2221. AddLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
  2222. AddLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
  2223. AddLump( LUMP_VERTEXES, dvertexes, numvertexes );
  2224. AddLump( LUMP_NODES, dnodes, numnodes );
  2225. AddLump( LUMP_TEXINFO, texinfo );
  2226. AddLump( LUMP_TEXDATA, dtexdata, numtexdata );
  2227. AddLump( LUMP_DISPINFO, g_dispinfo );
  2228. AddLump( LUMP_DISP_VERTS, g_DispVerts );
  2229. AddLump( LUMP_DISP_TRIS, g_DispTris );
  2230. AddLump( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
  2231. AddLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
  2232. AddLump( LUMP_PRIMITIVES, g_primitives, g_numprimitives );
  2233. AddLump( LUMP_PRIMVERTS, g_primverts, g_numprimverts );
  2234. AddLump( LUMP_PRIMINDICES, g_primindices, g_numprimindices );
  2235. AddLump( LUMP_FACES, dfaces, numfaces, LUMP_FACES_VERSION );
  2236. if (numfaces_hdr)
  2237. AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION );
  2238. AddLump ( LUMP_FACEIDS, dfaceids, numfaceids );
  2239. AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump
  2240. AddLump( LUMP_BRUSHES, dbrushes, numbrushes );
  2241. AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides );
  2242. AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces );
  2243. AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes );
  2244. AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges );
  2245. AddLump( LUMP_EDGES, dedges, numedges );
  2246. AddLump( LUMP_MODELS, dmodels, nummodels );
  2247. AddLump( LUMP_AREAS, dareas, numareas );
  2248. AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals );
  2249. AddLump( LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
  2250. AddLump( LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
  2251. AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
  2252. AddLump( LUMP_ENTITIES, dentdata );
  2253. AddLump( LUMP_WORLDLIGHTS, dworldlightsLDR, numworldlightsLDR );
  2254. AddLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR, numworldlightsHDR );
  2255. AddLump( LUMP_LEAFWATERDATA, dleafwaterdata, numleafwaterdata );
  2256. AddOcclusionLump();
  2257. dflagslump_t flags_lump;
  2258. flags_lump.m_LevelFlags = g_LevelFlags;
  2259. AddLump( LUMP_MAP_FLAGS, &flags_lump, 1 );
  2260. // NOTE: This is just for debugging, so it is disabled in release maps
  2261. #if 0
  2262. // add the vis portals to the BSP for visualization
  2263. AddLump( LUMP_PORTALS, dportals, numportals );
  2264. AddLump( LUMP_CLUSTERS, dclusters, numclusters );
  2265. AddLump( LUMP_PORTALVERTS, dportalverts, numportalverts );
  2266. AddLump( LUMP_CLUSTERPORTALS, dclusterportals, numclusterportals );
  2267. #endif
  2268. AddLump( LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts, g_nClipPortalVerts * 3 );
  2269. AddLump( LUMP_CUBEMAPS, g_CubemapSamples, g_nCubemapSamples );
  2270. AddLump( LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
  2271. AddLump( LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
  2272. AddLump( LUMP_OVERLAYS, g_Overlays, g_nOverlayCount );
  2273. AddLump( LUMP_WATEROVERLAYS, g_WaterOverlays, g_nWaterOverlayCount );
  2274. AddLump( LUMP_OVERLAY_FADES, g_OverlayFades, g_nOverlayCount );
  2275. if ( g_pPhysCollide )
  2276. {
  2277. AddLump( LUMP_PHYSCOLLIDE, g_pPhysCollide, g_PhysCollideSize );
  2278. }
  2279. if ( g_pPhysDisp )
  2280. {
  2281. AddLump ( LUMP_PHYSDISP, g_pPhysDisp, g_PhysDispSize );
  2282. }
  2283. AddLump( LUMP_VERTNORMALS, (float*)g_vertnormals, g_numvertnormals * 3 );
  2284. AddLump( LUMP_VERTNORMALINDICES, g_vertnormalindices, g_numvertnormalindices );
  2285. AddLump( LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater, numleafs );
  2286. AddGameLumps();
  2287. // Write pakfile lump to disk
  2288. WritePakFileLump();
  2289. // NOTE: Do NOT call AddLump after Lumps_Write() it writes all un-Added lumps
  2290. // write any additional lumps
  2291. Lumps_Write();
  2292. g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
  2293. WriteData( g_pBSPHeader );
  2294. g_pFileSystem->Close( g_hBSPFile );
  2295. }
  2296. // Generate the next clear lump filename for the bsp file
  2297. bool GenerateNextLumpFileName( const char *bspfilename, char *lumpfilename, int buffsize )
  2298. {
  2299. for (int i = 0; i < MAX_LUMPFILES; i++)
  2300. {
  2301. GenerateLumpFileName( bspfilename, lumpfilename, buffsize, i );
  2302. if ( !g_pFileSystem->FileExists( lumpfilename ) )
  2303. return true;
  2304. }
  2305. return false;
  2306. }
  2307. void WriteLumpToFile( char *filename, int lump )
  2308. {
  2309. if ( !HasLump(lump) )
  2310. return;
  2311. char lumppre[MAX_PATH];
  2312. if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
  2313. {
  2314. Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
  2315. return;
  2316. }
  2317. // Open the file
  2318. FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
  2319. if ( !lumpfile )
  2320. {
  2321. Error ("Error opening %s! (Check for write enable)\n",filename);
  2322. return;
  2323. }
  2324. int ofs = g_pBSPHeader->lumps[lump].fileofs;
  2325. int length = g_pBSPHeader->lumps[lump].filelen;
  2326. // Write the header
  2327. lumpfileheader_t lumpHeader;
  2328. lumpHeader.lumpID = lump;
  2329. lumpHeader.lumpVersion = LumpVersion(lump);
  2330. lumpHeader.lumpLength = length;
  2331. lumpHeader.mapRevision = LittleLong( g_MapRevision );
  2332. lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
  2333. SafeWrite (lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
  2334. // Write the lump
  2335. SafeWrite (lumpfile, (byte *)g_pBSPHeader + ofs, length);
  2336. }
  2337. void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen )
  2338. {
  2339. char lumppre[MAX_PATH];
  2340. if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
  2341. {
  2342. Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
  2343. return;
  2344. }
  2345. // Open the file
  2346. FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
  2347. if ( !lumpfile )
  2348. {
  2349. Error ("Error opening %s! (Check for write enable)\n",filename);
  2350. return;
  2351. }
  2352. // Write the header
  2353. lumpfileheader_t lumpHeader;
  2354. lumpHeader.lumpID = lump;
  2355. lumpHeader.lumpVersion = nLumpVersion;
  2356. lumpHeader.lumpLength = nBufLen;
  2357. lumpHeader.mapRevision = LittleLong( g_MapRevision );
  2358. lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
  2359. SafeWrite( lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
  2360. // Write the lump
  2361. SafeWrite( lumpfile, pBuffer, nBufLen );
  2362. g_pFileSystem->Close( lumpfile );
  2363. }
  2364. //============================================================================
  2365. #define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
  2366. #define ENTRYSIZE(a) (sizeof(*(a)))
  2367. int ArrayUsage( const char *szItem, int items, int maxitems, int itemsize )
  2368. {
  2369. float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
  2370. Msg("%-17.17s %8i/%-8i %8i/%-8i (%4.1f%%) ",
  2371. szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
  2372. if ( percentage > 80.0 )
  2373. Msg( "VERY FULL!\n" );
  2374. else if ( percentage > 95.0 )
  2375. Msg( "SIZE DANGER!\n" );
  2376. else if ( percentage > 99.9 )
  2377. Msg( "SIZE OVERFLOW!!!\n" );
  2378. else
  2379. Msg( "\n" );
  2380. return items * itemsize;
  2381. }
  2382. int GlobUsage( const char *szItem, int itemstorage, int maxstorage )
  2383. {
  2384. float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
  2385. Msg("%-17.17s [variable] %8i/%-8i (%4.1f%%) ",
  2386. szItem, itemstorage, maxstorage, percentage );
  2387. if ( percentage > 80.0 )
  2388. Msg( "VERY FULL!\n" );
  2389. else if ( percentage > 95.0 )
  2390. Msg( "SIZE DANGER!\n" );
  2391. else if ( percentage > 99.9 )
  2392. Msg( "SIZE OVERFLOW!!!\n" );
  2393. else
  2394. Msg( "\n" );
  2395. return itemstorage;
  2396. }
  2397. /*
  2398. =============
  2399. PrintBSPFileSizes
  2400. Dumps info about current file
  2401. =============
  2402. */
  2403. void PrintBSPFileSizes (void)
  2404. {
  2405. int totalmemory = 0;
  2406. // if (!num_entities)
  2407. // ParseEntities ();
  2408. Msg("\n");
  2409. Msg( "%-17s %16s %16s %9s \n", "Object names", "Objects/Maxobjs", "Memory / Maxmem", "Fullness" );
  2410. Msg( "%-17s %16s %16s %9s \n", "------------", "---------------", "---------------", "--------" );
  2411. totalmemory += ArrayUsage( "models", nummodels, ENTRIES(dmodels), ENTRYSIZE(dmodels) );
  2412. totalmemory += ArrayUsage( "brushes", numbrushes, ENTRIES(dbrushes), ENTRYSIZE(dbrushes) );
  2413. totalmemory += ArrayUsage( "brushsides", numbrushsides, ENTRIES(dbrushsides), ENTRYSIZE(dbrushsides) );
  2414. totalmemory += ArrayUsage( "planes", numplanes, ENTRIES(dplanes), ENTRYSIZE(dplanes) );
  2415. totalmemory += ArrayUsage( "vertexes", numvertexes, ENTRIES(dvertexes), ENTRYSIZE(dvertexes) );
  2416. totalmemory += ArrayUsage( "nodes", numnodes, ENTRIES(dnodes), ENTRYSIZE(dnodes) );
  2417. totalmemory += ArrayUsage( "texinfos", texinfo.Count(),MAX_MAP_TEXINFO, sizeof(texinfo_t) );
  2418. totalmemory += ArrayUsage( "texdata", numtexdata, ENTRIES(dtexdata), ENTRYSIZE(dtexdata) );
  2419. totalmemory += ArrayUsage( "dispinfos", g_dispinfo.Count(), 0, sizeof( ddispinfo_t ) );
  2420. totalmemory += ArrayUsage( "disp_verts", g_DispVerts.Count(), 0, sizeof( g_DispVerts[0] ) );
  2421. totalmemory += ArrayUsage( "disp_tris", g_DispTris.Count(), 0, sizeof( g_DispTris[0] ) );
  2422. totalmemory += ArrayUsage( "disp_lmsamples",g_DispLightmapSamplePositions.Count(),0,sizeof( g_DispLightmapSamplePositions[0] ) );
  2423. totalmemory += ArrayUsage( "faces", numfaces, ENTRIES(dfaces), ENTRYSIZE(dfaces) );
  2424. totalmemory += ArrayUsage( "hdr faces", numfaces_hdr, ENTRIES(dfaces_hdr), ENTRYSIZE(dfaces_hdr) );
  2425. totalmemory += ArrayUsage( "origfaces", numorigfaces, ENTRIES(dorigfaces), ENTRYSIZE(dorigfaces) ); // original faces
  2426. totalmemory += ArrayUsage( "leaves", numleafs, ENTRIES(dleafs), ENTRYSIZE(dleafs) );
  2427. totalmemory += ArrayUsage( "leaffaces", numleaffaces, ENTRIES(dleaffaces), ENTRYSIZE(dleaffaces) );
  2428. totalmemory += ArrayUsage( "leafbrushes", numleafbrushes, ENTRIES(dleafbrushes), ENTRYSIZE(dleafbrushes) );
  2429. totalmemory += ArrayUsage( "areas", numareas, ENTRIES(dareas), ENTRYSIZE(dareas) );
  2430. totalmemory += ArrayUsage( "surfedges", numsurfedges, ENTRIES(dsurfedges), ENTRYSIZE(dsurfedges) );
  2431. totalmemory += ArrayUsage( "edges", numedges, ENTRIES(dedges), ENTRYSIZE(dedges) );
  2432. totalmemory += ArrayUsage( "LDR worldlights", numworldlightsLDR, ENTRIES(dworldlightsLDR), ENTRYSIZE(dworldlightsLDR) );
  2433. totalmemory += ArrayUsage( "HDR worldlights", numworldlightsHDR, ENTRIES(dworldlightsHDR), ENTRYSIZE(dworldlightsHDR) );
  2434. totalmemory += ArrayUsage( "leafwaterdata", numleafwaterdata,ENTRIES(dleafwaterdata), ENTRYSIZE(dleafwaterdata) );
  2435. totalmemory += ArrayUsage( "waterstrips", g_numprimitives,ENTRIES(g_primitives), ENTRYSIZE(g_primitives) );
  2436. totalmemory += ArrayUsage( "waterverts", g_numprimverts, ENTRIES(g_primverts), ENTRYSIZE(g_primverts) );
  2437. totalmemory += ArrayUsage( "waterindices", g_numprimindices,ENTRIES(g_primindices),ENTRYSIZE(g_primindices) );
  2438. totalmemory += ArrayUsage( "cubemapsamples", g_nCubemapSamples,ENTRIES(g_CubemapSamples),ENTRYSIZE(g_CubemapSamples) );
  2439. totalmemory += ArrayUsage( "overlays", g_nOverlayCount, ENTRIES(g_Overlays), ENTRYSIZE(g_Overlays) );
  2440. totalmemory += GlobUsage( "LDR lightdata", dlightdataLDR.Count(), 0 );
  2441. totalmemory += GlobUsage( "HDR lightdata", dlightdataHDR.Count(), 0 );
  2442. totalmemory += GlobUsage( "visdata", visdatasize, sizeof(dvisdata) );
  2443. totalmemory += GlobUsage( "entdata", dentdata.Count(), 384*1024 ); // goal is <384K
  2444. totalmemory += ArrayUsage( "LDR ambient table", g_LeafAmbientIndexLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexLDR[0] ) );
  2445. totalmemory += ArrayUsage( "HDR ambient table", g_LeafAmbientIndexHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexHDR[0] ) );
  2446. totalmemory += ArrayUsage( "LDR leaf ambient lighting", g_LeafAmbientLightingLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingLDR[0] ) );
  2447. totalmemory += ArrayUsage( "HDR leaf ambient lighting", g_LeafAmbientLightingHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingHDR[0] ) );
  2448. totalmemory += ArrayUsage( "occluders", g_OccluderData.Count(), 0, sizeof( g_OccluderData[0] ) );
  2449. totalmemory += ArrayUsage( "occluder polygons", g_OccluderPolyData.Count(), 0, sizeof( g_OccluderPolyData[0] ) );
  2450. totalmemory += ArrayUsage( "occluder vert ind",g_OccluderVertexIndices.Count(),0, sizeof( g_OccluderVertexIndices[0] ) );
  2451. GameLumpHandle_t h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
  2452. if (h != g_GameLumps.InvalidGameLump())
  2453. totalmemory += GlobUsage( "detail props", 1, g_GameLumps.GameLumpSize(h) );
  2454. h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING );
  2455. if (h != g_GameLumps.InvalidGameLump())
  2456. totalmemory += GlobUsage( "dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
  2457. h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING_HDR );
  2458. if (h != g_GameLumps.InvalidGameLump())
  2459. totalmemory += GlobUsage( "HDR dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
  2460. h = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
  2461. if (h != g_GameLumps.InvalidGameLump())
  2462. totalmemory += GlobUsage( "static props", 1, g_GameLumps.GameLumpSize(h) );
  2463. totalmemory += GlobUsage( "pakfile", GetPakFile()->EstimateSize(), 0 );
  2464. // HACKHACK: Set physics limit at 4MB, in reality this is totally dynamic
  2465. totalmemory += GlobUsage( "physics", g_PhysCollideSize, 4*1024*1024 );
  2466. totalmemory += GlobUsage( "physics terrain", g_PhysDispSize, 1*1024*1024 );
  2467. Msg( "\nLevel flags = %x\n", g_LevelFlags );
  2468. Msg( "\n" );
  2469. int triangleCount = 0;
  2470. for ( int i = 0; i < numfaces; i++ )
  2471. {
  2472. // face tris = numedges - 2
  2473. triangleCount += dfaces[i].numedges - 2;
  2474. }
  2475. Msg("Total triangle count: %d\n", triangleCount );
  2476. // UNDONE:
  2477. // areaportals, portals, texdata, clusters, worldlights, portalverts
  2478. }
  2479. /*
  2480. =============
  2481. PrintBSPPackDirectory
  2482. Dumps a list of files stored in the bsp pack.
  2483. =============
  2484. */
  2485. void PrintBSPPackDirectory( void )
  2486. {
  2487. GetPakFile()->PrintDirectory();
  2488. }
  2489. //============================================
  2490. int num_entities;
  2491. entity_t entities[MAX_MAP_ENTITIES];
  2492. void StripTrailing (char *e)
  2493. {
  2494. char *s;
  2495. s = e + strlen(e)-1;
  2496. while (s >= e && *s <= 32)
  2497. {
  2498. *s = 0;
  2499. s--;
  2500. }
  2501. }
  2502. /*
  2503. =================
  2504. ParseEpair
  2505. =================
  2506. */
  2507. epair_t *ParseEpair (void)
  2508. {
  2509. epair_t *e;
  2510. e = (epair_t*)malloc (sizeof(epair_t));
  2511. memset (e, 0, sizeof(epair_t));
  2512. if (strlen(token) >= MAX_KEY-1)
  2513. Error ("ParseEpar: token too long");
  2514. e->key = copystring(token);
  2515. GetToken (false);
  2516. if (strlen(token) >= MAX_VALUE-1)
  2517. Error ("ParseEpar: token too long");
  2518. e->value = copystring(token);
  2519. // strip trailing spaces
  2520. StripTrailing (e->key);
  2521. StripTrailing (e->value);
  2522. return e;
  2523. }
  2524. /*
  2525. ================
  2526. ParseEntity
  2527. ================
  2528. */
  2529. qboolean ParseEntity (void)
  2530. {
  2531. epair_t *e;
  2532. entity_t *mapent;
  2533. if (!GetToken (true))
  2534. return false;
  2535. if (Q_stricmp (token, "{") )
  2536. Error ("ParseEntity: { not found");
  2537. if (num_entities == MAX_MAP_ENTITIES)
  2538. Error ("num_entities == MAX_MAP_ENTITIES");
  2539. mapent = &entities[num_entities];
  2540. num_entities++;
  2541. do
  2542. {
  2543. if (!GetToken (true))
  2544. Error ("ParseEntity: EOF without closing brace");
  2545. if (!Q_stricmp (token, "}") )
  2546. break;
  2547. e = ParseEpair ();
  2548. e->next = mapent->epairs;
  2549. mapent->epairs = e;
  2550. } while (1);
  2551. return true;
  2552. }
  2553. /*
  2554. ================
  2555. ParseEntities
  2556. Parses the dentdata string into entities
  2557. ================
  2558. */
  2559. void ParseEntities (void)
  2560. {
  2561. num_entities = 0;
  2562. ParseFromMemory (dentdata.Base(), dentdata.Count());
  2563. while (ParseEntity ())
  2564. {
  2565. }
  2566. }
  2567. /*
  2568. ================
  2569. UnparseEntities
  2570. Generates the dentdata string from all the entities
  2571. ================
  2572. */
  2573. void UnparseEntities (void)
  2574. {
  2575. epair_t *ep;
  2576. char line[2048];
  2577. int i;
  2578. char key[1024], value[1024];
  2579. CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  2580. buffer.EnsureCapacity( 256 * 1024 );
  2581. for (i=0 ; i<num_entities ; i++)
  2582. {
  2583. ep = entities[i].epairs;
  2584. if (!ep)
  2585. continue; // ent got removed
  2586. buffer.PutString( "{\n" );
  2587. for (ep = entities[i].epairs ; ep ; ep=ep->next)
  2588. {
  2589. strcpy (key, ep->key);
  2590. StripTrailing (key);
  2591. strcpy (value, ep->value);
  2592. StripTrailing (value);
  2593. sprintf(line, "\"%s\" \"%s\"\n", key, value);
  2594. buffer.PutString( line );
  2595. }
  2596. buffer.PutString("}\n");
  2597. }
  2598. int entdatasize = buffer.TellPut()+1;
  2599. dentdata.SetSize( entdatasize );
  2600. memcpy( dentdata.Base(), buffer.Base(), entdatasize-1 );
  2601. dentdata[entdatasize-1] = 0;
  2602. }
  2603. void PrintEntity (entity_t *ent)
  2604. {
  2605. epair_t *ep;
  2606. Msg ("------- entity %p -------\n", ent);
  2607. for (ep=ent->epairs ; ep ; ep=ep->next)
  2608. {
  2609. Msg ("%s = %s\n", ep->key, ep->value);
  2610. }
  2611. }
  2612. void SetKeyValue(entity_t *ent, const char *key, const char *value)
  2613. {
  2614. epair_t *ep;
  2615. for (ep=ent->epairs ; ep ; ep=ep->next)
  2616. if (!Q_stricmp (ep->key, key) )
  2617. {
  2618. free (ep->value);
  2619. ep->value = copystring(value);
  2620. return;
  2621. }
  2622. ep = (epair_t*)malloc (sizeof(*ep));
  2623. ep->next = ent->epairs;
  2624. ent->epairs = ep;
  2625. ep->key = copystring(key);
  2626. ep->value = copystring(value);
  2627. }
  2628. char *ValueForKey (entity_t *ent, char *key)
  2629. {
  2630. for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
  2631. if (!Q_stricmp (ep->key, key) )
  2632. return ep->value;
  2633. return "";
  2634. }
  2635. vec_t FloatForKey (entity_t *ent, char *key)
  2636. {
  2637. char *k = ValueForKey (ent, key);
  2638. return atof(k);
  2639. }
  2640. vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value)
  2641. {
  2642. for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
  2643. if (!Q_stricmp (ep->key, key) )
  2644. return atof( ep->value );
  2645. return default_value;
  2646. }
  2647. int IntForKey (entity_t *ent, char *key)
  2648. {
  2649. char *k = ValueForKey (ent, key);
  2650. return atol(k);
  2651. }
  2652. int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault )
  2653. {
  2654. char *k = ValueForKey (ent, key);
  2655. if ( !k[0] )
  2656. return nDefault;
  2657. return atol(k);
  2658. }
  2659. void GetVectorForKey (entity_t *ent, char *key, Vector& vec)
  2660. {
  2661. char *k = ValueForKey (ent, key);
  2662. // scanf into doubles, then assign, so it is vec_t size independent
  2663. double v1, v2, v3;
  2664. v1 = v2 = v3 = 0;
  2665. sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
  2666. vec[0] = v1;
  2667. vec[1] = v2;
  2668. vec[2] = v3;
  2669. }
  2670. void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec)
  2671. {
  2672. double v1, v2;
  2673. char *k = ValueForKey (ent, key);
  2674. // scanf into doubles, then assign, so it is vec_t size independent
  2675. v1 = v2 = 0;
  2676. sscanf (k, "%lf %lf", &v1, &v2);
  2677. vec[0] = v1;
  2678. vec[1] = v2;
  2679. }
  2680. void GetAnglesForKey (entity_t *ent, char *key, QAngle& angle)
  2681. {
  2682. char *k;
  2683. double v1, v2, v3;
  2684. k = ValueForKey (ent, key);
  2685. // scanf into doubles, then assign, so it is vec_t size independent
  2686. v1 = v2 = v3 = 0;
  2687. sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
  2688. angle[0] = v1;
  2689. angle[1] = v2;
  2690. angle[2] = v3;
  2691. }
  2692. //-----------------------------------------------------------------------------
  2693. //-----------------------------------------------------------------------------
  2694. void BuildFaceCalcWindingData( dface_t *pFace, int *points )
  2695. {
  2696. for( int i = 0; i < pFace->numedges; i++ )
  2697. {
  2698. int eIndex = dsurfedges[pFace->firstedge+i];
  2699. if( eIndex < 0 )
  2700. {
  2701. points[i] = dedges[-eIndex].v[1];
  2702. }
  2703. else
  2704. {
  2705. points[i] = dedges[eIndex].v[0];
  2706. }
  2707. }
  2708. }
  2709. void TriStripToTriList(
  2710. unsigned short const *pTriStripIndices,
  2711. int nTriStripIndices,
  2712. unsigned short **pTriListIndices,
  2713. int *pnTriListIndices )
  2714. {
  2715. int nMaxTriListIndices = (nTriStripIndices - 2) * 3;
  2716. *pTriListIndices = new unsigned short[ nMaxTriListIndices ];
  2717. *pnTriListIndices = 0;
  2718. for( int i=0; i < nTriStripIndices - 2; i++ )
  2719. {
  2720. if( pTriStripIndices[i] == pTriStripIndices[i+1] ||
  2721. pTriStripIndices[i] == pTriStripIndices[i+2] ||
  2722. pTriStripIndices[i+1] == pTriStripIndices[i+2] )
  2723. {
  2724. }
  2725. else
  2726. {
  2727. // Flip odd numbered tris..
  2728. if( i & 1 )
  2729. {
  2730. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
  2731. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
  2732. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
  2733. }
  2734. else
  2735. {
  2736. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
  2737. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
  2738. (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
  2739. }
  2740. }
  2741. }
  2742. }
  2743. void CalcTextureCoordsAtPoints(
  2744. float const texelsPerWorldUnits[2][4],
  2745. int const subtractOffset[2],
  2746. Vector const *pPoints,
  2747. int const nPoints,
  2748. Vector2D *pCoords )
  2749. {
  2750. for( int i=0; i < nPoints; i++ )
  2751. {
  2752. for( int iCoord=0; iCoord < 2; iCoord++ )
  2753. {
  2754. float *pDestCoord = &pCoords[i][iCoord];
  2755. *pDestCoord = 0;
  2756. for( int iDot=0; iDot < 3; iDot++ )
  2757. *pDestCoord += pPoints[i][iDot] * texelsPerWorldUnits[iCoord][iDot];
  2758. *pDestCoord += texelsPerWorldUnits[iCoord][3];
  2759. *pDestCoord -= subtractOffset[iCoord];
  2760. }
  2761. }
  2762. }
  2763. /*
  2764. ================
  2765. CalcFaceExtents
  2766. Fills in s->texmins[] and s->texsize[]
  2767. ================
  2768. */
  2769. void CalcFaceExtents(dface_t *s, int lightmapTextureMinsInLuxels[2], int lightmapTextureSizeInLuxels[2])
  2770. {
  2771. vec_t mins[2], maxs[2], val=0;
  2772. int i,j, e=0;
  2773. dvertex_t *v=NULL;
  2774. texinfo_t *tex=NULL;
  2775. mins[0] = mins[1] = 1e24;
  2776. maxs[0] = maxs[1] = -1e24;
  2777. tex = &texinfo[s->texinfo];
  2778. for (i=0 ; i<s->numedges ; i++)
  2779. {
  2780. e = dsurfedges[s->firstedge+i];
  2781. if (e >= 0)
  2782. v = dvertexes + dedges[e].v[0];
  2783. else
  2784. v = dvertexes + dedges[-e].v[1];
  2785. for (j=0 ; j<2 ; j++)
  2786. {
  2787. val = v->point[0] * tex->lightmapVecsLuxelsPerWorldUnits[j][0] +
  2788. v->point[1] * tex->lightmapVecsLuxelsPerWorldUnits[j][1] +
  2789. v->point[2] * tex->lightmapVecsLuxelsPerWorldUnits[j][2] +
  2790. tex->lightmapVecsLuxelsPerWorldUnits[j][3];
  2791. if (val < mins[j])
  2792. mins[j] = val;
  2793. if (val > maxs[j])
  2794. maxs[j] = val;
  2795. }
  2796. }
  2797. int nMaxLightmapDim = (s->dispinfo == -1) ? MAX_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER;
  2798. for (i=0 ; i<2 ; i++)
  2799. {
  2800. mins[i] = ( float )floor( mins[i] );
  2801. maxs[i] = ( float )ceil( maxs[i] );
  2802. lightmapTextureMinsInLuxels[i] = ( int )mins[i];
  2803. lightmapTextureSizeInLuxels[i] = ( int )( maxs[i] - mins[i] );
  2804. if( lightmapTextureSizeInLuxels[i] > nMaxLightmapDim + 1 )
  2805. {
  2806. Vector point = vec3_origin;
  2807. for (int j=0 ; j<s->numedges ; j++)
  2808. {
  2809. e = dsurfedges[s->firstedge+j];
  2810. v = (e<0)?dvertexes + dedges[-e].v[1] : dvertexes + dedges[e].v[0];
  2811. point += v->point;
  2812. Warning( "Bad surface extents point: %f %f %f\n", v->point.x, v->point.y, v->point.z );
  2813. }
  2814. point *= 1.0f/s->numedges;
  2815. Error( "Bad surface extents - surface is too big to have a lightmap\n\tmaterial %s around point (%.1f %.1f %.1f)\n\t(dimension: %d, %d>%d)\n",
  2816. TexDataStringTable_GetString( dtexdata[texinfo[s->texinfo].texdata].nameStringTableID ),
  2817. point.x, point.y, point.z,
  2818. ( int )i,
  2819. ( int )lightmapTextureSizeInLuxels[i],
  2820. ( int )( nMaxLightmapDim + 1 )
  2821. );
  2822. }
  2823. }
  2824. }
  2825. void UpdateAllFaceLightmapExtents()
  2826. {
  2827. for( int i=0; i < numfaces; i++ )
  2828. {
  2829. dface_t *pFace = &dfaces[i];
  2830. if ( texinfo[pFace->texinfo].flags & (SURF_SKY|SURF_NOLIGHT) )
  2831. continue; // non-lit texture
  2832. CalcFaceExtents( pFace, pFace->m_LightmapTextureMinsInLuxels, pFace->m_LightmapTextureSizeInLuxels );
  2833. }
  2834. }
  2835. //-----------------------------------------------------------------------------
  2836. //
  2837. // Helper class to iterate over leaves, used by tools
  2838. //
  2839. //-----------------------------------------------------------------------------
  2840. #define TEST_EPSILON (0.03125)
  2841. class CToolBSPTree : public ISpatialQuery
  2842. {
  2843. public:
  2844. // Returns the number of leaves
  2845. int LeafCount() const;
  2846. // Enumerates the leaves along a ray, box, etc.
  2847. bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
  2848. bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
  2849. bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
  2850. bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
  2851. };
  2852. //-----------------------------------------------------------------------------
  2853. // Returns the number of leaves
  2854. //-----------------------------------------------------------------------------
  2855. int CToolBSPTree::LeafCount() const
  2856. {
  2857. return numleafs;
  2858. }
  2859. //-----------------------------------------------------------------------------
  2860. // Enumerates the leaves at a point
  2861. //-----------------------------------------------------------------------------
  2862. bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt,
  2863. ISpatialLeafEnumerator* pEnum, int context )
  2864. {
  2865. int node = 0;
  2866. while( node >= 0 )
  2867. {
  2868. dnode_t* pNode = &dnodes[node];
  2869. dplane_t* pPlane = &dplanes[pNode->planenum];
  2870. if (DotProduct( pPlane->normal, pt ) <= pPlane->dist)
  2871. {
  2872. node = pNode->children[1];
  2873. }
  2874. else
  2875. {
  2876. node = pNode->children[0];
  2877. }
  2878. }
  2879. return pEnum->EnumerateLeaf( - node - 1, context );
  2880. }
  2881. //-----------------------------------------------------------------------------
  2882. // Enumerates the leaves in a box
  2883. //-----------------------------------------------------------------------------
  2884. static bool EnumerateLeavesInBox_R( int node, Vector const& mins,
  2885. Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
  2886. {
  2887. Vector cornermin, cornermax;
  2888. while( node >= 0 )
  2889. {
  2890. dnode_t* pNode = &dnodes[node];
  2891. dplane_t* pPlane = &dplanes[pNode->planenum];
  2892. // Arbitrary split plane here
  2893. for (int i = 0; i < 3; ++i)
  2894. {
  2895. if (pPlane->normal[i] >= 0)
  2896. {
  2897. cornermin[i] = mins[i];
  2898. cornermax[i] = maxs[i];
  2899. }
  2900. else
  2901. {
  2902. cornermin[i] = maxs[i];
  2903. cornermax[i] = mins[i];
  2904. }
  2905. }
  2906. if ( (DotProduct( pPlane->normal, cornermax ) - pPlane->dist) <= -TEST_EPSILON )
  2907. {
  2908. node = pNode->children[1];
  2909. }
  2910. else if ( (DotProduct( pPlane->normal, cornermin ) - pPlane->dist) >= TEST_EPSILON )
  2911. {
  2912. node = pNode->children[0];
  2913. }
  2914. else
  2915. {
  2916. if (!EnumerateLeavesInBox_R( pNode->children[0], mins, maxs, pEnum, context ))
  2917. {
  2918. return false;
  2919. }
  2920. return EnumerateLeavesInBox_R( pNode->children[1], mins, maxs, pEnum, context );
  2921. }
  2922. }
  2923. return pEnum->EnumerateLeaf( - node - 1, context );
  2924. }
  2925. bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs,
  2926. ISpatialLeafEnumerator* pEnum, int context )
  2927. {
  2928. return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
  2929. }
  2930. //-----------------------------------------------------------------------------
  2931. // Enumerate leaves within a sphere
  2932. //-----------------------------------------------------------------------------
  2933. static bool EnumerateLeavesInSphere_R( int node, Vector const& origin,
  2934. float radius, ISpatialLeafEnumerator* pEnum, int context )
  2935. {
  2936. while( node >= 0 )
  2937. {
  2938. dnode_t* pNode = &dnodes[node];
  2939. dplane_t* pPlane = &dplanes[pNode->planenum];
  2940. if (DotProduct( pPlane->normal, origin ) + radius - pPlane->dist <= -TEST_EPSILON )
  2941. {
  2942. node = pNode->children[1];
  2943. }
  2944. else if (DotProduct( pPlane->normal, origin ) - radius - pPlane->dist >= TEST_EPSILON )
  2945. {
  2946. node = pNode->children[0];
  2947. }
  2948. else
  2949. {
  2950. if (!EnumerateLeavesInSphere_R( pNode->children[0],
  2951. origin, radius, pEnum, context ))
  2952. {
  2953. return false;
  2954. }
  2955. return EnumerateLeavesInSphere_R( pNode->children[1],
  2956. origin, radius, pEnum, context );
  2957. }
  2958. }
  2959. return pEnum->EnumerateLeaf( - node - 1, context );
  2960. }
  2961. bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
  2962. {
  2963. return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context );
  2964. }
  2965. //-----------------------------------------------------------------------------
  2966. // Enumerate leaves along a ray
  2967. //-----------------------------------------------------------------------------
  2968. static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray,
  2969. Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context )
  2970. {
  2971. float front,back;
  2972. while (node >= 0)
  2973. {
  2974. dnode_t* pNode = &dnodes[node];
  2975. dplane_t* pPlane = &dplanes[pNode->planenum];
  2976. if ( pPlane->type <= PLANE_Z )
  2977. {
  2978. front = start[pPlane->type] - pPlane->dist;
  2979. back = end[pPlane->type] - pPlane->dist;
  2980. }
  2981. else
  2982. {
  2983. front = DotProduct(start, pPlane->normal) - pPlane->dist;
  2984. back = DotProduct(end, pPlane->normal) - pPlane->dist;
  2985. }
  2986. if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
  2987. {
  2988. node = pNode->children[1];
  2989. }
  2990. else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
  2991. {
  2992. node = pNode->children[0];
  2993. }
  2994. else
  2995. {
  2996. // test the front side first
  2997. bool side = front < 0;
  2998. // Compute intersection point based on the original ray
  2999. float splitfrac;
  3000. float denom = DotProduct( ray.m_Delta, pPlane->normal );
  3001. if ( denom == 0.0f )
  3002. {
  3003. splitfrac = 1.0f;
  3004. }
  3005. else
  3006. {
  3007. splitfrac = ( pPlane->dist - DotProduct( ray.m_Start, pPlane->normal ) ) / denom;
  3008. if (splitfrac < 0)
  3009. splitfrac = 0;
  3010. else if (splitfrac > 1)
  3011. splitfrac = 1;
  3012. }
  3013. // Compute the split point
  3014. Vector split;
  3015. VectorMA( ray.m_Start, splitfrac, ray.m_Delta, split );
  3016. bool r = EnumerateLeavesAlongRay_R (pNode->children[side], ray, start, split, pEnum, context );
  3017. if (!r)
  3018. return r;
  3019. return EnumerateLeavesAlongRay_R (pNode->children[!side], ray, split, end, pEnum, context);
  3020. }
  3021. }
  3022. return pEnum->EnumerateLeaf( - node - 1, context );
  3023. }
  3024. bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
  3025. {
  3026. if (!ray.m_IsSwept)
  3027. {
  3028. Vector mins, maxs;
  3029. VectorAdd( ray.m_Start, ray.m_Extents, maxs );
  3030. VectorSubtract( ray.m_Start, ray.m_Extents, mins );
  3031. return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
  3032. }
  3033. // FIXME: Extruded ray not implemented yet
  3034. Assert( ray.m_IsRay );
  3035. Vector end;
  3036. VectorAdd( ray.m_Start, ray.m_Delta, end );
  3037. return EnumerateLeavesAlongRay_R( 0, ray, ray.m_Start, end, pEnum, context );
  3038. }
  3039. //-----------------------------------------------------------------------------
  3040. // Singleton accessor
  3041. //-----------------------------------------------------------------------------
  3042. ISpatialQuery* ToolBSPTree()
  3043. {
  3044. static CToolBSPTree s_ToolBSPTree;
  3045. return &s_ToolBSPTree;
  3046. }
  3047. //-----------------------------------------------------------------------------
  3048. // Enumerates nodes in front to back order...
  3049. //-----------------------------------------------------------------------------
  3050. // FIXME: Do we want this in the IBSPTree interface?
  3051. static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end,
  3052. IBSPNodeEnumerator* pEnum, int context )
  3053. {
  3054. float front, back;
  3055. float startDotN, deltaDotN;
  3056. while (node >= 0)
  3057. {
  3058. dnode_t* pNode = &dnodes[node];
  3059. dplane_t* pPlane = &dplanes[pNode->planenum];
  3060. if ( pPlane->type <= PLANE_Z )
  3061. {
  3062. startDotN = ray.m_Start[pPlane->type];
  3063. deltaDotN = ray.m_Delta[pPlane->type];
  3064. }
  3065. else
  3066. {
  3067. startDotN = DotProduct( ray.m_Start, pPlane->normal );
  3068. deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
  3069. }
  3070. front = startDotN + start * deltaDotN - pPlane->dist;
  3071. back = startDotN + end * deltaDotN - pPlane->dist;
  3072. if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
  3073. {
  3074. node = pNode->children[1];
  3075. }
  3076. else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
  3077. {
  3078. node = pNode->children[0];
  3079. }
  3080. else
  3081. {
  3082. // test the front side first
  3083. bool side = front < 0;
  3084. // Compute intersection point based on the original ray
  3085. float splitfrac;
  3086. if ( deltaDotN == 0.0f )
  3087. {
  3088. splitfrac = 1.0f;
  3089. }
  3090. else
  3091. {
  3092. splitfrac = ( pPlane->dist - startDotN ) / deltaDotN;
  3093. if (splitfrac < 0.0f)
  3094. splitfrac = 0.0f;
  3095. else if (splitfrac > 1.0f)
  3096. splitfrac = 1.0f;
  3097. }
  3098. bool r = EnumerateNodesAlongRay_R (pNode->children[side], ray, start, splitfrac, pEnum, context );
  3099. if (!r)
  3100. return r;
  3101. // Visit the node...
  3102. if (!pEnum->EnumerateNode( node, ray, splitfrac, context ))
  3103. return false;
  3104. return EnumerateNodesAlongRay_R (pNode->children[!side], ray, splitfrac, end, pEnum, context);
  3105. }
  3106. }
  3107. // Visit the leaf...
  3108. return pEnum->EnumerateLeaf( - node - 1, ray, start, end, context );
  3109. }
  3110. bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context )
  3111. {
  3112. Vector end;
  3113. VectorAdd( ray.m_Start, ray.m_Delta, end );
  3114. return EnumerateNodesAlongRay_R( 0, ray, 0.0f, 1.0f, pEnum, context );
  3115. }
  3116. //-----------------------------------------------------------------------------
  3117. // Helps us find all leaves associated with a particular cluster
  3118. //-----------------------------------------------------------------------------
  3119. CUtlVector<clusterlist_t> g_ClusterLeaves;
  3120. void BuildClusterTable( void )
  3121. {
  3122. int i, j;
  3123. int leafCount;
  3124. int leafList[MAX_MAP_LEAFS];
  3125. g_ClusterLeaves.SetCount( dvis->numclusters );
  3126. for ( i = 0; i < dvis->numclusters; i++ )
  3127. {
  3128. leafCount = 0;
  3129. for ( j = 0; j < numleafs; j++ )
  3130. {
  3131. if ( dleafs[j].cluster == i )
  3132. {
  3133. leafList[ leafCount ] = j;
  3134. leafCount++;
  3135. }
  3136. }
  3137. g_ClusterLeaves[i].leafCount = leafCount;
  3138. if ( leafCount )
  3139. {
  3140. g_ClusterLeaves[i].leafs.SetCount( leafCount );
  3141. memcpy( g_ClusterLeaves[i].leafs.Base(), leafList, sizeof(int) * leafCount );
  3142. }
  3143. }
  3144. }
  3145. // There's a version of this in checksum_engine.cpp!!! Make sure that they match.
  3146. static bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
  3147. {
  3148. byte chunk[1024];
  3149. lump_t *curLump;
  3150. FileHandle_t fp = g_pFileSystem->Open( pszFileName, "rb" );
  3151. if ( !fp )
  3152. return false;
  3153. // CRC across all lumps except for the Entities lump
  3154. for ( int l = 0; l < HEADER_LUMPS; ++l )
  3155. {
  3156. if (l == LUMP_ENTITIES)
  3157. continue;
  3158. curLump = &g_pBSPHeader->lumps[l];
  3159. unsigned int nSize = curLump->filelen;
  3160. g_pFileSystem->Seek( fp, curLump->fileofs, FILESYSTEM_SEEK_HEAD );
  3161. // Now read in 1K chunks
  3162. while ( nSize > 0 )
  3163. {
  3164. int nBytesRead = 0;
  3165. if ( nSize > 1024 )
  3166. nBytesRead = g_pFileSystem->Read( chunk, 1024, fp );
  3167. else
  3168. nBytesRead = g_pFileSystem->Read( chunk, nSize, fp );
  3169. // If any data was received, CRC it.
  3170. if ( nBytesRead > 0 )
  3171. {
  3172. nSize -= nBytesRead;
  3173. CRC32_ProcessBuffer( crcvalue, chunk, nBytesRead );
  3174. }
  3175. else
  3176. {
  3177. g_pFileSystem->Close( fp );
  3178. return false;
  3179. }
  3180. }
  3181. }
  3182. g_pFileSystem->Close( fp );
  3183. return true;
  3184. }
  3185. void SetHDRMode( bool bHDR )
  3186. {
  3187. g_bHDR = bHDR;
  3188. if ( bHDR )
  3189. {
  3190. pdlightdata = &dlightdataHDR;
  3191. g_pLeafAmbientLighting = &g_LeafAmbientLightingHDR;
  3192. g_pLeafAmbientIndex = &g_LeafAmbientIndexHDR;
  3193. pNumworldlights = &numworldlightsHDR;
  3194. dworldlights = dworldlightsHDR;
  3195. #ifdef VRAD
  3196. extern void VRadDetailProps_SetHDRMode( bool bHDR );
  3197. VRadDetailProps_SetHDRMode( bHDR );
  3198. #endif
  3199. }
  3200. else
  3201. {
  3202. pdlightdata = &dlightdataLDR;
  3203. g_pLeafAmbientLighting = &g_LeafAmbientLightingLDR;
  3204. g_pLeafAmbientIndex = &g_LeafAmbientIndexLDR;
  3205. pNumworldlights = &numworldlightsLDR;
  3206. dworldlights = dworldlightsLDR;
  3207. #ifdef VRAD
  3208. extern void VRadDetailProps_SetHDRMode( bool bHDR );
  3209. VRadDetailProps_SetHDRMode( bHDR );
  3210. #endif
  3211. }
  3212. }
  3213. bool SwapVHV( void *pDestBase, void *pSrcBase )
  3214. {
  3215. byte *pDest = (byte*)pDestBase;
  3216. byte *pSrc = (byte*)pSrcBase;
  3217. HardwareVerts::FileHeader_t *pHdr = (HardwareVerts::FileHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
  3218. g_Swap.SwapFieldsToTargetEndian<HardwareVerts::FileHeader_t>( (HardwareVerts::FileHeader_t*)pDest, (HardwareVerts::FileHeader_t*)pSrc );
  3219. pSrc += sizeof(HardwareVerts::FileHeader_t);
  3220. pDest += sizeof(HardwareVerts::FileHeader_t);
  3221. // This swap is pretty format specific
  3222. Assert( pHdr->m_nVersion == VHV_VERSION );
  3223. if ( pHdr->m_nVersion != VHV_VERSION )
  3224. return false;
  3225. HardwareVerts::MeshHeader_t *pSrcMesh = (HardwareVerts::MeshHeader_t*)pSrc;
  3226. HardwareVerts::MeshHeader_t *pDestMesh = (HardwareVerts::MeshHeader_t*)pDest;
  3227. HardwareVerts::MeshHeader_t *pMesh = (HardwareVerts::MeshHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
  3228. for ( int i = 0; i < pHdr->m_nMeshes; ++i, ++pMesh, ++pSrcMesh, ++pDestMesh )
  3229. {
  3230. g_Swap.SwapFieldsToTargetEndian( pDestMesh, pSrcMesh );
  3231. pSrc = (byte*)pSrcBase + pMesh->m_nOffset;
  3232. pDest = (byte*)pDestBase + pMesh->m_nOffset;
  3233. // Swap as a buffer of integers
  3234. // (source is bgra for an Intel swap to argb. PowerPC won't swap, so we need argb source.
  3235. g_Swap.SwapBufferToTargetEndian<int>( (int*)pDest, (int*)pSrc, pMesh->m_nVertexes );
  3236. }
  3237. return true;
  3238. }
  3239. const char *ResolveStaticPropToModel( const char *pPropName )
  3240. {
  3241. // resolve back to static prop
  3242. int iProp = -1;
  3243. // filename should be sp_???.vhv or sp_hdr_???.vhv
  3244. if ( V_strnicmp( pPropName, "sp_", 3 ) )
  3245. {
  3246. return NULL;
  3247. }
  3248. const char *pPropNumber = V_strrchr( pPropName, '_' );
  3249. if ( pPropNumber )
  3250. {
  3251. sscanf( pPropNumber+1, "%d.vhv", &iProp );
  3252. }
  3253. else
  3254. {
  3255. return NULL;
  3256. }
  3257. // look up the prop to get to the actual model
  3258. if ( iProp < 0 || iProp >= g_StaticPropInstances.Count() )
  3259. {
  3260. // prop out of range
  3261. return NULL;
  3262. }
  3263. int iModel = g_StaticPropInstances[iProp];
  3264. if ( iModel < 0 || iModel >= g_StaticPropNames.Count() )
  3265. {
  3266. // model out of range
  3267. return NULL;
  3268. }
  3269. return g_StaticPropNames[iModel].String();
  3270. }
  3271. //-----------------------------------------------------------------------------
  3272. // Iterate files in pak file, distribute to converters
  3273. // pak file will be ready for serialization upon completion
  3274. //-----------------------------------------------------------------------------
  3275. void ConvertPakFileContents( const char *pInFilename )
  3276. {
  3277. IZip *newPakFile = IZip::CreateZip( NULL );
  3278. CUtlBuffer sourceBuf;
  3279. CUtlBuffer targetBuf;
  3280. bool bConverted;
  3281. CUtlVector< CUtlString > hdrFiles;
  3282. int id = -1;
  3283. int fileSize;
  3284. while ( 1 )
  3285. {
  3286. char relativeName[MAX_PATH];
  3287. id = GetNextFilename( GetPakFile(), id, relativeName, sizeof( relativeName ), fileSize );
  3288. if ( id == -1)
  3289. break;
  3290. bConverted = false;
  3291. sourceBuf.Purge();
  3292. targetBuf.Purge();
  3293. const char* pExtension = V_GetFileExtension( relativeName );
  3294. const char* pExt = 0;
  3295. bool bOK = ReadFileFromPak( GetPakFile(), relativeName, false, sourceBuf );
  3296. if ( !bOK )
  3297. {
  3298. Warning( "Failed to load '%s' from lump pak for conversion or copy in '%s'.\n", relativeName, pInFilename );
  3299. continue;
  3300. }
  3301. if ( pExtension && !V_stricmp( pExtension, "vtf" ) )
  3302. {
  3303. bOK = g_pVTFConvertFunc( relativeName, sourceBuf, targetBuf, g_pCompressFunc );
  3304. if ( !bOK )
  3305. {
  3306. Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
  3307. continue;
  3308. }
  3309. bConverted = true;
  3310. pExt = ".vtf";
  3311. }
  3312. else if ( pExtension && !V_stricmp( pExtension, "vhv" ) )
  3313. {
  3314. CUtlBuffer tempBuffer;
  3315. if ( g_pVHVFixupFunc )
  3316. {
  3317. // caller supplied a fixup
  3318. const char *pModelName = ResolveStaticPropToModel( relativeName );
  3319. if ( !pModelName )
  3320. {
  3321. Warning( "Static Prop '%s' failed to resolve actual model in '%s'.\n", relativeName, pInFilename );
  3322. continue;
  3323. }
  3324. // output temp buffer may shrink, must use TellPut() to determine size
  3325. bOK = g_pVHVFixupFunc( relativeName, pModelName, sourceBuf, tempBuffer );
  3326. if ( !bOK )
  3327. {
  3328. Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
  3329. continue;
  3330. }
  3331. }
  3332. else
  3333. {
  3334. // use the source buffer as-is
  3335. tempBuffer.EnsureCapacity( sourceBuf.TellMaxPut() );
  3336. tempBuffer.Put( sourceBuf.Base(), sourceBuf.TellMaxPut() );
  3337. }
  3338. // swap the VHV
  3339. targetBuf.EnsureCapacity( tempBuffer.TellPut() );
  3340. bOK = SwapVHV( targetBuf.Base(), tempBuffer.Base() );
  3341. if ( !bOK )
  3342. {
  3343. Warning( "Failed to swap '%s' in '%s'.\n", relativeName, pInFilename );
  3344. continue;
  3345. }
  3346. targetBuf.SeekPut( CUtlBuffer::SEEK_HEAD, tempBuffer.TellPut() );
  3347. if ( g_pCompressFunc )
  3348. {
  3349. CUtlBuffer compressedBuffer;
  3350. targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, sizeof( HardwareVerts::FileHeader_t ) );
  3351. bool bCompressed = g_pCompressFunc( targetBuf, compressedBuffer );
  3352. if ( bCompressed )
  3353. {
  3354. // copy all the header data off
  3355. CUtlBuffer headerBuffer;
  3356. headerBuffer.EnsureCapacity( sizeof( HardwareVerts::FileHeader_t ) );
  3357. headerBuffer.Put( targetBuf.Base(), sizeof( HardwareVerts::FileHeader_t ) );
  3358. // reform the target with the header and then the compressed data
  3359. targetBuf.Clear();
  3360. targetBuf.Put( headerBuffer.Base(), sizeof( HardwareVerts::FileHeader_t ) );
  3361. targetBuf.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
  3362. }
  3363. targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  3364. }
  3365. bConverted = true;
  3366. pExt = ".vhv";
  3367. }
  3368. if ( !bConverted )
  3369. {
  3370. // straight copy
  3371. AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false, IZip::eCompressionType_None );
  3372. }
  3373. else
  3374. {
  3375. // converted filename
  3376. V_StripExtension( relativeName, relativeName, sizeof( relativeName ) );
  3377. V_strcat( relativeName, ".360", sizeof( relativeName ) );
  3378. V_strcat( relativeName, pExt, sizeof( relativeName ) );
  3379. AddBufferToPak( newPakFile, relativeName, targetBuf.Base(), targetBuf.TellMaxPut(), false, IZip::eCompressionType_None );
  3380. }
  3381. if ( V_stristr( relativeName, ".hdr" ) || V_stristr( relativeName, "_hdr" ) )
  3382. {
  3383. hdrFiles.AddToTail( relativeName );
  3384. }
  3385. DevMsg( "Created '%s' in lump pak in '%s'.\n", relativeName, pInFilename );
  3386. }
  3387. // strip ldr version of hdr files
  3388. for ( int i=0; i<hdrFiles.Count(); i++ )
  3389. {
  3390. char ldrFileName[MAX_PATH];
  3391. strcpy( ldrFileName, hdrFiles[i].String() );
  3392. char *pHDRExtension = V_stristr( ldrFileName, ".hdr" );
  3393. if ( !pHDRExtension )
  3394. {
  3395. pHDRExtension = V_stristr( ldrFileName, "_hdr" );
  3396. }
  3397. if ( pHDRExtension )
  3398. {
  3399. // strip .hdr or _hdr to get ldr filename
  3400. memcpy( pHDRExtension, pHDRExtension+4, strlen( pHDRExtension+4 )+1 );
  3401. DevMsg( "Stripping LDR: %s\n", ldrFileName );
  3402. newPakFile->RemoveFileFromZip( ldrFileName );
  3403. }
  3404. }
  3405. // discard old pak in favor of new pak
  3406. IZip::ReleaseZip( s_pakFile );
  3407. s_pakFile = newPakFile;
  3408. }
  3409. void SetAlignedLumpPosition( int lumpnum, int alignment = LUMP_ALIGNMENT )
  3410. {
  3411. g_pBSPHeader->lumps[lumpnum].fileofs = AlignFilePosition( g_hBSPFile, alignment );
  3412. }
  3413. template< class T >
  3414. int SwapLumpToDisk( int fieldType, int lumpnum )
  3415. {
  3416. if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 )
  3417. return 0;
  3418. DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
  3419. // lump swap may expand, allocate enough expansion room
  3420. void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
  3421. // CopyLumpInternal will handle the swap on load case
  3422. unsigned int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
  3423. unsigned int count = CopyLumpInternal<T>( fieldType, lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
  3424. g_pBSPHeader->lumps[lumpnum].filelen = count * fieldSize;
  3425. if ( g_bSwapOnWrite )
  3426. {
  3427. // Swap the lump in place before writing
  3428. switch( lumpnum )
  3429. {
  3430. case LUMP_VISIBILITY:
  3431. SwapVisibilityLump( (byte*)pBuffer, (byte*)pBuffer, count );
  3432. break;
  3433. case LUMP_PHYSCOLLIDE:
  3434. // SwapPhyscollideLump may change size
  3435. SwapPhyscollideLump( (byte*)pBuffer, (byte*)pBuffer, count );
  3436. g_pBSPHeader->lumps[lumpnum].filelen = count;
  3437. break;
  3438. case LUMP_PHYSDISP:
  3439. SwapPhysdispLump( (byte*)pBuffer, (byte*)pBuffer, count );
  3440. break;
  3441. default:
  3442. g_Swap.SwapBufferToTargetEndian( (T*)pBuffer, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].filelen / sizeof(T) );
  3443. break;
  3444. }
  3445. }
  3446. SetAlignedLumpPosition( lumpnum );
  3447. SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
  3448. free( pBuffer );
  3449. return g_pBSPHeader->lumps[lumpnum].filelen;
  3450. }
  3451. template< class T >
  3452. int SwapLumpToDisk( int lumpnum )
  3453. {
  3454. if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 || g_Lumps.bLumpParsed[lumpnum] )
  3455. return 0;
  3456. DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
  3457. // lump swap may expand, allocate enough room
  3458. void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
  3459. // CopyLumpInternal will handle the swap on load case
  3460. int count = CopyLumpInternal<T>( lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
  3461. g_pBSPHeader->lumps[lumpnum].filelen = count * sizeof(T);
  3462. if ( g_bSwapOnWrite )
  3463. {
  3464. // Swap the lump in place before writing
  3465. g_Swap.SwapFieldsToTargetEndian( (T*)pBuffer, (T*)pBuffer, count );
  3466. }
  3467. SetAlignedLumpPosition( lumpnum );
  3468. SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
  3469. free( pBuffer );
  3470. return g_pBSPHeader->lumps[lumpnum].filelen;
  3471. }
  3472. void SwapLeafAmbientLightingLumpToDisk()
  3473. {
  3474. if ( HasLump( LUMP_LEAF_AMBIENT_INDEX ) || HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
  3475. {
  3476. // current version, swap in place
  3477. if ( HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
  3478. {
  3479. // write HDR
  3480. SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
  3481. SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX_HDR );
  3482. // cull LDR
  3483. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
  3484. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
  3485. }
  3486. else
  3487. {
  3488. // no HDR, keep LDR version
  3489. SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING );
  3490. SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX );
  3491. }
  3492. }
  3493. else
  3494. {
  3495. // older ambient lighting version (before index)
  3496. // load older ambient lighting into memory and build ambient/index
  3497. // an older leaf version would have already built the new LDR leaf ambient/index
  3498. int numLeafs = g_pBSPHeader->lumps[LUMP_LEAFS].filelen / sizeof( dleaf_t );
  3499. LoadLeafAmbientLighting( numLeafs );
  3500. if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
  3501. {
  3502. DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) );
  3503. DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX_HDR ) );
  3504. // write HDR
  3505. if ( g_bSwapOnWrite )
  3506. {
  3507. g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingHDR.Base(), g_LeafAmbientLightingHDR.Count() );
  3508. g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexHDR.Base(), g_LeafAmbientIndexHDR.Count() );
  3509. }
  3510. SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
  3511. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
  3512. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen = g_LeafAmbientLightingHDR.Count() * sizeof( dleafambientlighting_t );
  3513. SafeWrite( g_hBSPFile, g_LeafAmbientLightingHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen );
  3514. SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX_HDR );
  3515. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen = g_LeafAmbientIndexHDR.Count() * sizeof( dleafambientindex_t );
  3516. SafeWrite( g_hBSPFile, g_LeafAmbientIndexHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen );
  3517. // mark as processed
  3518. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
  3519. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
  3520. // cull LDR
  3521. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
  3522. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
  3523. }
  3524. else
  3525. {
  3526. // no HDR, keep LDR version
  3527. DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING ) );
  3528. DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX ) );
  3529. if ( g_bSwapOnWrite )
  3530. {
  3531. g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingLDR.Base(), g_LeafAmbientLightingLDR.Count() );
  3532. g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexLDR.Base(), g_LeafAmbientIndexLDR.Count() );
  3533. }
  3534. SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING );
  3535. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
  3536. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = g_LeafAmbientLightingLDR.Count() * sizeof( dleafambientlighting_t );
  3537. SafeWrite( g_hBSPFile, g_LeafAmbientLightingLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen );
  3538. SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX );
  3539. g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = g_LeafAmbientIndexLDR.Count() * sizeof( dleafambientindex_t );
  3540. SafeWrite( g_hBSPFile, g_LeafAmbientIndexLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen );
  3541. // mark as processed
  3542. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
  3543. g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
  3544. }
  3545. g_LeafAmbientLightingLDR.Purge();
  3546. g_LeafAmbientIndexLDR.Purge();
  3547. g_LeafAmbientLightingHDR.Purge();
  3548. g_LeafAmbientIndexHDR.Purge();
  3549. }
  3550. }
  3551. void SwapLeafLumpToDisk( void )
  3552. {
  3553. DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAFS ) );
  3554. // load the leafs
  3555. int count = LoadLeafs();
  3556. if ( g_bSwapOnWrite )
  3557. {
  3558. g_Swap.SwapFieldsToTargetEndian( dleafs, count );
  3559. }
  3560. bool bOldLeafVersion = ( LumpVersion( LUMP_LEAFS ) == 0 );
  3561. if ( bOldLeafVersion )
  3562. {
  3563. // version has been converted in the load process
  3564. // not updating the version ye, SwapLeafAmbientLightingLumpToDisk() can detect
  3565. g_pBSPHeader->lumps[LUMP_LEAFS].filelen = count * sizeof( dleaf_t );
  3566. }
  3567. SetAlignedLumpPosition( LUMP_LEAFS );
  3568. SafeWrite( g_hBSPFile, dleafs, g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
  3569. SwapLeafAmbientLightingLumpToDisk();
  3570. if ( bOldLeafVersion )
  3571. {
  3572. // version has been converted in the load process
  3573. // can now safely change
  3574. g_pBSPHeader->lumps[LUMP_LEAFS].version = 1;
  3575. }
  3576. #if defined( BSP_USE_LESS_MEMORY )
  3577. if ( dleafs )
  3578. {
  3579. free( dleafs );
  3580. dleafs = NULL;
  3581. }
  3582. #endif
  3583. }
  3584. void SwapOcclusionLumpToDisk( void )
  3585. {
  3586. DevMsg( "Swapping %s\n", GetLumpName( LUMP_OCCLUSION ) );
  3587. LoadOcclusionLump();
  3588. SetAlignedLumpPosition( LUMP_OCCLUSION );
  3589. AddOcclusionLump();
  3590. }
  3591. void SwapPakfileLumpToDisk( const char *pInFilename )
  3592. {
  3593. DevMsg( "Swapping %s\n", GetLumpName( LUMP_PAKFILE ) );
  3594. byte *pakbuffer = NULL;
  3595. int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
  3596. if ( paksize > 0 )
  3597. {
  3598. GetPakFile()->ActivateByteSwapping( IsX360() );
  3599. GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
  3600. ConvertPakFileContents( pInFilename );
  3601. }
  3602. free( pakbuffer );
  3603. SetAlignedLumpPosition( LUMP_PAKFILE, XBOX_DVD_SECTORSIZE );
  3604. WritePakFileLump();
  3605. ReleasePakFileLumps();
  3606. }
  3607. void SwapGameLumpsToDisk( void )
  3608. {
  3609. DevMsg( "Swapping %s\n", GetLumpName( LUMP_GAME_LUMP ) );
  3610. g_GameLumps.ParseGameLump( g_pBSPHeader );
  3611. SetAlignedLumpPosition( LUMP_GAME_LUMP );
  3612. AddGameLumps();
  3613. }
  3614. //-----------------------------------------------------------------------------
  3615. // Generate a table of all static props, used for resolving static prop lighting
  3616. // files back to their actual mdl.
  3617. //-----------------------------------------------------------------------------
  3618. void BuildStaticPropNameTable()
  3619. {
  3620. g_StaticPropNames.Purge();
  3621. g_StaticPropInstances.Purge();
  3622. g_GameLumps.ParseGameLump( g_pBSPHeader );
  3623. GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
  3624. if ( hGameLump != g_GameLumps.InvalidGameLump() )
  3625. {
  3626. int nVersion = g_GameLumps.GetGameLumpVersion( hGameLump );
  3627. if ( nVersion < 4 )
  3628. {
  3629. // old unsupported version
  3630. return;
  3631. }
  3632. if ( nVersion != 4 && nVersion != 5 && nVersion != 6 )
  3633. {
  3634. Error( "Unknown Static Prop Lump version %d!\n", nVersion );
  3635. }
  3636. byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
  3637. if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
  3638. {
  3639. // get the model dictionary
  3640. int count = ((int *)pGameLumpData)[0];
  3641. pGameLumpData += sizeof( int );
  3642. StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
  3643. for ( int i = 0; i < count; i++ )
  3644. {
  3645. g_StaticPropNames.AddToTail( pStaticPropDictLump[i].m_Name );
  3646. }
  3647. pGameLumpData += count * sizeof( StaticPropDictLump_t );
  3648. // skip the leaf list
  3649. count = ((int *)pGameLumpData)[0];
  3650. pGameLumpData += sizeof( int );
  3651. pGameLumpData += count * sizeof( StaticPropLeafLump_t );
  3652. // get the instances
  3653. count = ((int *)pGameLumpData)[0];
  3654. pGameLumpData += sizeof( int );
  3655. for ( int i = 0; i < count; i++ )
  3656. {
  3657. int propType;
  3658. if ( nVersion == 4 )
  3659. {
  3660. propType = ((StaticPropLumpV4_t *)pGameLumpData)->m_PropType;
  3661. pGameLumpData += sizeof( StaticPropLumpV4_t );
  3662. }
  3663. else if ( nVersion == 5 )
  3664. {
  3665. propType = ((StaticPropLumpV5_t *)pGameLumpData)->m_PropType;
  3666. pGameLumpData += sizeof( StaticPropLumpV5_t );
  3667. }
  3668. else
  3669. {
  3670. propType = ((StaticPropLump_t *)pGameLumpData)->m_PropType;
  3671. pGameLumpData += sizeof( StaticPropLump_t );
  3672. }
  3673. g_StaticPropInstances.AddToTail( propType );
  3674. }
  3675. }
  3676. }
  3677. g_GameLumps.DestroyAllGameLumps();
  3678. }
  3679. int AlignBuffer( CUtlBuffer &buffer, int alignment )
  3680. {
  3681. unsigned int newPosition = AlignValue( buffer.TellPut(), alignment );
  3682. int padLength = newPosition - buffer.TellPut();
  3683. for ( int i = 0; i<padLength; i++ )
  3684. {
  3685. buffer.PutChar( '\0' );
  3686. }
  3687. return buffer.TellPut();
  3688. }
  3689. struct SortedLump_t
  3690. {
  3691. int lumpNum;
  3692. lump_t *pLump;
  3693. };
  3694. int SortLumpsByOffset( const SortedLump_t *pSortedLumpA, const SortedLump_t *pSortedLumpB )
  3695. {
  3696. int fileOffsetA = pSortedLumpA->pLump->fileofs;
  3697. int fileOffsetB = pSortedLumpB->pLump->fileofs;
  3698. int fileSizeA = pSortedLumpA->pLump->filelen;
  3699. int fileSizeB = pSortedLumpB->pLump->filelen;
  3700. // invalid or empty lumps get sorted together
  3701. if ( !fileSizeA )
  3702. {
  3703. fileOffsetA = 0;
  3704. }
  3705. if ( !fileSizeB )
  3706. {
  3707. fileOffsetB = 0;
  3708. }
  3709. // compare by offset, want ascending
  3710. if ( fileOffsetA < fileOffsetB )
  3711. {
  3712. return -1;
  3713. }
  3714. else if ( fileOffsetA > fileOffsetB )
  3715. {
  3716. return 1;
  3717. }
  3718. return 0;
  3719. }
  3720. bool CompressGameLump( dheader_t *pInBSPHeader, dheader_t *pOutBSPHeader, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
  3721. {
  3722. CByteswap byteSwap;
  3723. dgamelumpheader_t* pInGameLumpHeader = (dgamelumpheader_t*)(((byte *)pInBSPHeader) + pInBSPHeader->lumps[LUMP_GAME_LUMP].fileofs);
  3724. dgamelump_t* pInGameLump = (dgamelump_t*)(pInGameLumpHeader + 1);
  3725. if ( IsX360() )
  3726. {
  3727. byteSwap.ActivateByteSwapping( true );
  3728. byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader );
  3729. byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount );
  3730. }
  3731. unsigned int newOffset = outputBuffer.TellPut();
  3732. // Make room for gamelump header and gamelump structs, which we'll write at the end
  3733. outputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, sizeof( dgamelumpheader_t ) );
  3734. outputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
  3735. // Start with input lumps, and fixup
  3736. dgamelumpheader_t sOutGameLumpHeader = *pInGameLumpHeader;
  3737. CUtlBuffer sOutGameLumpBuf;
  3738. sOutGameLumpBuf.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
  3739. dgamelump_t *sOutGameLump = (dgamelump_t *)sOutGameLumpBuf.Base();
  3740. // add a dummy terminal gamelump
  3741. // purposely NOT updating the .filelen to reflect the compressed size, but leaving as original size
  3742. // callers use the next entry offset to determine compressed size
  3743. sOutGameLumpHeader.lumpCount++;
  3744. dgamelump_t dummyLump = { 0 };
  3745. outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) );
  3746. for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ )
  3747. {
  3748. CUtlBuffer inputBuffer;
  3749. CUtlBuffer compressedBuffer;
  3750. sOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 );
  3751. if ( pInGameLump[i].filelen )
  3752. {
  3753. if ( pInGameLump[i].flags & GAMELUMPFLAG_COMPRESSED )
  3754. {
  3755. byte *pCompressedLump = ((byte *)pInBSPHeader) + pInGameLump[i].fileofs;
  3756. if ( CLZMA::IsCompressed( pCompressedLump ) )
  3757. {
  3758. inputBuffer.EnsureCapacity( CLZMA::GetActualSize( pCompressedLump ) );
  3759. unsigned int outSize = CLZMA::Uncompress( pCompressedLump, (unsigned char *)inputBuffer.Base() );
  3760. inputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, outSize );
  3761. if ( outSize != CLZMA::GetActualSize( pCompressedLump ) )
  3762. {
  3763. Warning( "Decompressed size differs from header, BSP may be corrupt\n" );
  3764. }
  3765. }
  3766. else
  3767. {
  3768. Assert( CLZMA::IsCompressed( pCompressedLump ) );
  3769. Warning( "Unsupported BSP: Unrecognized compressed game lump\n" );
  3770. }
  3771. }
  3772. else
  3773. {
  3774. inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs,
  3775. pInGameLump[i].filelen, pInGameLump[i].filelen );
  3776. }
  3777. bool bCompressed = pCompressFunc ? pCompressFunc( inputBuffer, compressedBuffer ) : false;
  3778. if ( bCompressed )
  3779. {
  3780. sOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED;
  3781. outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
  3782. compressedBuffer.Purge();
  3783. }
  3784. else
  3785. {
  3786. // as is, clear compression flag from input lump
  3787. sOutGameLump[i].flags &= ~GAMELUMPFLAG_COMPRESSED;
  3788. outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
  3789. }
  3790. }
  3791. }
  3792. // fix the dummy terminal lump
  3793. int lastLump = sOutGameLumpHeader.lumpCount-1;
  3794. sOutGameLump[lastLump].fileofs = outputBuffer.TellPut();
  3795. if ( IsX360() )
  3796. {
  3797. // fix the output for 360, swapping it back
  3798. byteSwap.SwapFieldsToTargetEndian( sOutGameLump, sOutGameLumpHeader.lumpCount );
  3799. byteSwap.SwapFieldsToTargetEndian( &sOutGameLumpHeader );
  3800. }
  3801. pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset;
  3802. pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset;
  3803. // We set GAMELUMPFLAG_COMPRESSED and handle compression at the sub-lump level, this whole lump is not
  3804. // decompressable as a block.
  3805. pOutBSPHeader->lumps[LUMP_GAME_LUMP].uncompressedSize = 0;
  3806. // Rewind to start and write lump headers
  3807. unsigned int endOffset = outputBuffer.TellPut();
  3808. outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, newOffset );
  3809. outputBuffer.Put( &sOutGameLumpHeader, sizeof( dgamelumpheader_t ) );
  3810. outputBuffer.Put( sOutGameLumpBuf.Base(), sOutGameLumpBuf.TellPut() );
  3811. outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, endOffset );
  3812. return true;
  3813. }
  3814. //-----------------------------------------------------------------------------
  3815. // Compress callback for RepackBSP
  3816. //-----------------------------------------------------------------------------
  3817. bool RepackBSPCallback_LZMA( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer )
  3818. {
  3819. if ( !inputBuffer.TellPut() )
  3820. {
  3821. // nothing to do
  3822. return false;
  3823. }
  3824. unsigned int originalSize = inputBuffer.TellPut() - inputBuffer.TellGet();
  3825. unsigned int compressedSize = 0;
  3826. unsigned char *pCompressedOutput = LZMA_Compress( (unsigned char *)inputBuffer.Base() + inputBuffer.TellGet(),
  3827. originalSize, &compressedSize );
  3828. if ( pCompressedOutput )
  3829. {
  3830. outputBuffer.Put( pCompressedOutput, compressedSize );
  3831. DevMsg( "Compressed bsp lump %u -> %u bytes\n", originalSize, compressedSize );
  3832. free( pCompressedOutput );
  3833. return true;
  3834. }
  3835. return false;
  3836. }
  3837. bool RepackBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc, IZip::eCompressionType packfileCompression )
  3838. {
  3839. dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base();
  3840. // The 360 swaps this header to disk. For some reason.
  3841. if ( pInBSPHeader->ident != ( IsX360() ? BigLong( IDBSPHEADER ) : IDBSPHEADER ) )
  3842. {
  3843. Warning( "RepackBSP given invalid input data\n" );
  3844. return false;
  3845. }
  3846. CByteswap byteSwap;
  3847. if ( IsX360() )
  3848. {
  3849. // bsp is 360, swap the header back
  3850. byteSwap.ActivateByteSwapping( true );
  3851. byteSwap.SwapFieldsToTargetEndian( pInBSPHeader );
  3852. }
  3853. unsigned int headerOffset = outputBuffer.TellPut();
  3854. outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) );
  3855. // This buffer grows dynamically, don't keep pointers to it around. Write out header at end.
  3856. dheader_t sOutBSPHeader = *pInBSPHeader;
  3857. // must adhere to input lump's offset order and process according to that, NOT lump num
  3858. // sort by offset order
  3859. CUtlVector< SortedLump_t > sortedLumps;
  3860. for ( int i = 0; i < HEADER_LUMPS; i++ )
  3861. {
  3862. int iIndex = sortedLumps.AddToTail();
  3863. sortedLumps[iIndex].lumpNum = i;
  3864. sortedLumps[iIndex].pLump = &pInBSPHeader->lumps[i];
  3865. }
  3866. sortedLumps.Sort( SortLumpsByOffset );
  3867. // iterate in sorted order
  3868. for ( int i = 0; i < HEADER_LUMPS; ++i )
  3869. {
  3870. SortedLump_t *pSortedLump = &sortedLumps[i];
  3871. int lumpNum = pSortedLump->lumpNum;
  3872. // Should be set below, don't copy over old data
  3873. sOutBSPHeader.lumps[lumpNum].fileofs = 0;
  3874. sOutBSPHeader.lumps[lumpNum].filelen = 0;
  3875. // Only set by compressed lumps
  3876. sOutBSPHeader.lumps[lumpNum].uncompressedSize = 0;
  3877. if ( pSortedLump->pLump->filelen ) // Otherwise its degenerate
  3878. {
  3879. int alignment = 4;
  3880. if ( lumpNum == LUMP_PAKFILE )
  3881. {
  3882. alignment = 2048;
  3883. }
  3884. unsigned int newOffset = AlignBuffer( outputBuffer, alignment );
  3885. CUtlBuffer inputBuffer;
  3886. if ( pSortedLump->pLump->uncompressedSize )
  3887. {
  3888. byte *pCompressedLump = ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs;
  3889. if ( CLZMA::IsCompressed( pCompressedLump ) && pSortedLump->pLump->uncompressedSize == CLZMA::GetActualSize( pCompressedLump ) )
  3890. {
  3891. inputBuffer.EnsureCapacity( CLZMA::GetActualSize( pCompressedLump ) );
  3892. unsigned int outSize = CLZMA::Uncompress( pCompressedLump, (unsigned char *)inputBuffer.Base() );
  3893. inputBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, outSize );
  3894. if ( outSize != pSortedLump->pLump->uncompressedSize )
  3895. {
  3896. Warning( "Decompressed size differs from header, BSP may be corrupt\n" );
  3897. }
  3898. }
  3899. else
  3900. {
  3901. Assert( CLZMA::IsCompressed( pCompressedLump ) &&
  3902. pSortedLump->pLump->uncompressedSize == CLZMA::GetActualSize( pCompressedLump ) );
  3903. Warning( "Unsupported BSP: Unrecognized compressed lump\n" );
  3904. }
  3905. }
  3906. else
  3907. {
  3908. // Just use input
  3909. inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs,
  3910. pSortedLump->pLump->filelen, pSortedLump->pLump->filelen );
  3911. }
  3912. if ( lumpNum == LUMP_GAME_LUMP )
  3913. {
  3914. // the game lump has to have each of its components individually compressed
  3915. CompressGameLump( pInBSPHeader, &sOutBSPHeader, outputBuffer, pCompressFunc );
  3916. }
  3917. else if ( lumpNum == LUMP_PAKFILE )
  3918. {
  3919. IZip *newPakFile = IZip::CreateZip( NULL );
  3920. IZip *oldPakFile = IZip::CreateZip( NULL );
  3921. oldPakFile->ParseFromBuffer( inputBuffer.Base(), inputBuffer.Size() );
  3922. int id = -1;
  3923. int fileSize;
  3924. while ( 1 )
  3925. {
  3926. char relativeName[MAX_PATH];
  3927. id = GetNextFilename( oldPakFile, id, relativeName, sizeof( relativeName ), fileSize );
  3928. if ( id == -1 )
  3929. break;
  3930. CUtlBuffer sourceBuf;
  3931. CUtlBuffer targetBuf;
  3932. bool bOK = ReadFileFromPak( oldPakFile, relativeName, false, sourceBuf );
  3933. if ( !bOK )
  3934. {
  3935. Error( "Failed to load '%s' from lump pak for repacking.\n", relativeName );
  3936. continue;
  3937. }
  3938. AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false, packfileCompression );
  3939. DevMsg( "Repacking BSP: Created '%s' in lump pak\n", relativeName );
  3940. }
  3941. // save new pack to buffer
  3942. newPakFile->SaveToBuffer( outputBuffer );
  3943. sOutBSPHeader.lumps[lumpNum].fileofs = newOffset;
  3944. sOutBSPHeader.lumps[lumpNum].filelen = outputBuffer.TellPut() - newOffset;
  3945. // Note that this *lump* is uncompressed, it just contains a packfile that uses compression, so we're
  3946. // not setting lumps[lumpNum].uncompressedSize
  3947. IZip::ReleaseZip( oldPakFile );
  3948. IZip::ReleaseZip( newPakFile );
  3949. }
  3950. else
  3951. {
  3952. CUtlBuffer compressedBuffer;
  3953. bool bCompressed = pCompressFunc ? pCompressFunc( inputBuffer, compressedBuffer ) : false;
  3954. if ( bCompressed )
  3955. {
  3956. sOutBSPHeader.lumps[lumpNum].uncompressedSize = inputBuffer.TellPut();
  3957. sOutBSPHeader.lumps[lumpNum].filelen = compressedBuffer.TellPut();
  3958. sOutBSPHeader.lumps[lumpNum].fileofs = newOffset;
  3959. outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
  3960. compressedBuffer.Purge();
  3961. }
  3962. else
  3963. {
  3964. // add as is
  3965. sOutBSPHeader.lumps[lumpNum].fileofs = newOffset;
  3966. sOutBSPHeader.lumps[lumpNum].filelen = inputBuffer.TellPut();
  3967. outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
  3968. }
  3969. }
  3970. }
  3971. }
  3972. if ( IsX360() )
  3973. {
  3974. // fix the output for 360, swapping it back
  3975. byteSwap.SetTargetBigEndian( true );
  3976. byteSwap.SwapFieldsToTargetEndian( &sOutBSPHeader );
  3977. }
  3978. // Write out header
  3979. unsigned int endOffset = outputBuffer.TellPut();
  3980. outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, headerOffset );
  3981. outputBuffer.Put( &sOutBSPHeader, sizeof( sOutBSPHeader ) );
  3982. outputBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, endOffset );
  3983. return true;
  3984. }
  3985. //-----------------------------------------------------------------------------
  3986. // For all lumps in a bsp: Loads the lump from file A, swaps it, writes it to file B.
  3987. // This limits the memory used for the swap process which helps the Xbox 360.
  3988. //
  3989. // NOTE: These lumps will be written to the file in exactly the order they appear here,
  3990. // so they can be shifted around if desired for file access optimization.
  3991. //-----------------------------------------------------------------------------
  3992. bool SwapBSPFile( const char *pInFilename, const char *pOutFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc )
  3993. {
  3994. DevMsg( "Creating %s\n", pOutFilename );
  3995. if ( !g_pFileSystem->FileExists( pInFilename ) )
  3996. {
  3997. Warning( "Error! Couldn't open input file %s - BSP swap failed!\n", pInFilename );
  3998. return false;
  3999. }
  4000. g_hBSPFile = SafeOpenWrite( pOutFilename );
  4001. if ( !g_hBSPFile )
  4002. {
  4003. Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
  4004. return false;
  4005. }
  4006. if ( !pVTFConvertFunc )
  4007. {
  4008. Warning( "Error! Missing VTF Conversion function\n" );
  4009. return false;
  4010. }
  4011. g_pVTFConvertFunc = pVTFConvertFunc;
  4012. // optional VHV fixup
  4013. g_pVHVFixupFunc = pVHVFixupFunc;
  4014. // optional compression callback
  4015. g_pCompressFunc = pCompressFunc;
  4016. // These must be mutually exclusive
  4017. g_bSwapOnLoad = bSwapOnLoad;
  4018. g_bSwapOnWrite = !bSwapOnLoad;
  4019. g_Swap.ActivateByteSwapping( true );
  4020. OpenBSPFile( pInFilename );
  4021. // CRC the bsp first
  4022. CRC32_t mapCRC;
  4023. CRC32_Init(&mapCRC);
  4024. if ( !CRC_MapFile( &mapCRC, pInFilename ) )
  4025. {
  4026. Warning( "Failed to CRC the bsp\n" );
  4027. return false;
  4028. }
  4029. // hold a dictionary of all the static prop names
  4030. // this is needed to properly convert any VHV files inside the pak lump
  4031. BuildStaticPropNameTable();
  4032. // Set the output file pointer after the header
  4033. dheader_t dummyHeader = { 0 };
  4034. SafeWrite( g_hBSPFile, &dummyHeader, sizeof( dheader_t ) );
  4035. // To allow for alignment fixups, the lumps will be written to the
  4036. // output file in the order they appear in this function.
  4037. // NOTE: Flags for 360 !!!MUST!!! be first
  4038. SwapLumpToDisk< dflagslump_t >( LUMP_MAP_FLAGS );
  4039. // complex lump swaps first or for later contingent data
  4040. SwapLeafLumpToDisk();
  4041. SwapOcclusionLumpToDisk();
  4042. SwapGameLumpsToDisk();
  4043. // Strip dead or non relevant lumps
  4044. g_pBSPHeader->lumps[LUMP_DISP_LIGHTMAP_ALPHAS].filelen = 0;
  4045. g_pBSPHeader->lumps[LUMP_FACEIDS].filelen = 0;
  4046. // Strip obsolete LDR in favor of HDR
  4047. if ( SwapLumpToDisk<dface_t>( LUMP_FACES_HDR ) )
  4048. {
  4049. g_pBSPHeader->lumps[LUMP_FACES].filelen = 0;
  4050. }
  4051. else
  4052. {
  4053. // no HDR, keep LDR version
  4054. SwapLumpToDisk<dface_t>( LUMP_FACES );
  4055. }
  4056. if ( SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS_HDR ) )
  4057. {
  4058. g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0;
  4059. }
  4060. else
  4061. {
  4062. // no HDR, keep LDR version
  4063. SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS );
  4064. }
  4065. // Simple lump swaps
  4066. SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSDISP );
  4067. SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE );
  4068. SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_VISIBILITY );
  4069. SwapLumpToDisk<dmodel_t>( LUMP_MODELS );
  4070. SwapLumpToDisk<dvertex_t>( LUMP_VERTEXES );
  4071. SwapLumpToDisk<dplane_t>( LUMP_PLANES );
  4072. SwapLumpToDisk<dnode_t>( LUMP_NODES );
  4073. SwapLumpToDisk<texinfo_t>( LUMP_TEXINFO );
  4074. SwapLumpToDisk<dtexdata_t>( LUMP_TEXDATA );
  4075. SwapLumpToDisk<ddispinfo_t>( LUMP_DISPINFO );
  4076. SwapLumpToDisk<CDispVert>( LUMP_DISP_VERTS );
  4077. SwapLumpToDisk<CDispTri>( LUMP_DISP_TRIS );
  4078. SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
  4079. SwapLumpToDisk<CFaceMacroTextureInfo>( LUMP_FACE_MACRO_TEXTURE_INFO );
  4080. SwapLumpToDisk<dprimitive_t>( LUMP_PRIMITIVES );
  4081. SwapLumpToDisk<dprimvert_t>( LUMP_PRIMVERTS );
  4082. SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_PRIMINDICES );
  4083. SwapLumpToDisk<dface_t>( LUMP_ORIGINALFACES );
  4084. SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFFACES );
  4085. SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFBRUSHES );
  4086. SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_SURFEDGES );
  4087. SwapLumpToDisk<dedge_t>( LUMP_EDGES );
  4088. SwapLumpToDisk<dbrush_t>( LUMP_BRUSHES );
  4089. SwapLumpToDisk<dbrushside_t>( LUMP_BRUSHSIDES );
  4090. SwapLumpToDisk<darea_t>( LUMP_AREAS );
  4091. SwapLumpToDisk<dareaportal_t>( LUMP_AREAPORTALS );
  4092. SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_ENTITIES );
  4093. SwapLumpToDisk<dleafwaterdata_t>( LUMP_LEAFWATERDATA );
  4094. SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_VERTNORMALS );
  4095. SwapLumpToDisk<short>( FIELD_SHORT, LUMP_VERTNORMALINDICES );
  4096. SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_CLIPPORTALVERTS );
  4097. SwapLumpToDisk<dcubemapsample_t>( LUMP_CUBEMAPS );
  4098. SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA );
  4099. SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE );
  4100. SwapLumpToDisk<doverlay_t>( LUMP_OVERLAYS );
  4101. SwapLumpToDisk<dwateroverlay_t>( LUMP_WATEROVERLAYS );
  4102. SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER );
  4103. SwapLumpToDisk<doverlayfade_t>( LUMP_OVERLAY_FADES );
  4104. // NOTE: this data placed at the end for the sake of 360:
  4105. {
  4106. // NOTE: lighting must be the penultimate lump
  4107. // (allows 360 to free this memory part-way through map loading)
  4108. if ( SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) )
  4109. {
  4110. g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0;
  4111. }
  4112. else
  4113. {
  4114. // no HDR, keep LDR version
  4115. SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING );
  4116. }
  4117. // NOTE: Pakfile for 360 !!!MUST!!! be last
  4118. SwapPakfileLumpToDisk( pInFilename );
  4119. }
  4120. // Store the crc in the flags lump version field
  4121. g_pBSPHeader->lumps[LUMP_MAP_FLAGS].version = mapCRC;
  4122. // Pad out the end of the file to a sector boundary for optimal IO
  4123. AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
  4124. // Warn of any lumps that didn't get swapped
  4125. for ( int i = 0; i < HEADER_LUMPS; ++i )
  4126. {
  4127. if ( HasLump( i ) && !g_Lumps.bLumpParsed[i] )
  4128. {
  4129. // a new lump got added that needs to have a swap function
  4130. Warning( "BSP: '%s', %s has no swap or copy function. Discarding!\n", pInFilename, GetLumpName(i) );
  4131. // the data didn't get copied, so don't reference garbage
  4132. g_pBSPHeader->lumps[i].filelen = 0;
  4133. }
  4134. }
  4135. // Write the updated header
  4136. g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
  4137. WriteData( g_pBSPHeader );
  4138. g_pFileSystem->Close( g_hBSPFile );
  4139. g_hBSPFile = 0;
  4140. // Cleanup
  4141. g_Swap.ActivateByteSwapping( false );
  4142. CloseBSPFile();
  4143. g_StaticPropNames.Purge();
  4144. g_StaticPropInstances.Purge();
  4145. DevMsg( "Finished BSP Swap\n" );
  4146. // caller provided compress func will further compress compatible lumps
  4147. if ( pCompressFunc )
  4148. {
  4149. CUtlBuffer inputBuffer;
  4150. if ( !g_pFileSystem->ReadFile( pOutFilename, NULL, inputBuffer ) )
  4151. {
  4152. Warning( "Error! Couldn't read file %s - final BSP compression failed!\n", pOutFilename );
  4153. return false;
  4154. }
  4155. CUtlBuffer outputBuffer;
  4156. if ( !RepackBSP( inputBuffer, outputBuffer, pCompressFunc, IZip::eCompressionType_None ) )
  4157. {
  4158. Warning( "Error! Failed to compress BSP '%s'!\n", pOutFilename );
  4159. return false;
  4160. }
  4161. g_hBSPFile = SafeOpenWrite( pOutFilename );
  4162. if ( !g_hBSPFile )
  4163. {
  4164. Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
  4165. return false;
  4166. }
  4167. SafeWrite( g_hBSPFile, outputBuffer.Base(), outputBuffer.TellPut() );
  4168. g_pFileSystem->Close( g_hBSPFile );
  4169. g_hBSPFile = 0;
  4170. }
  4171. return true;
  4172. }
  4173. //-----------------------------------------------------------------------------
  4174. // Get the pak lump from a BSP
  4175. //-----------------------------------------------------------------------------
  4176. bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize )
  4177. {
  4178. *pPakData = NULL;
  4179. *pPakSize = 0;
  4180. if ( !g_pFileSystem->FileExists( pBSPFilename ) )
  4181. {
  4182. Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
  4183. return false;
  4184. }
  4185. // determine endian nature
  4186. dheader_t *pHeader;
  4187. LoadFile( pBSPFilename, (void **)&pHeader );
  4188. bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
  4189. free( pHeader );
  4190. g_bSwapOnLoad = bSwap;
  4191. g_bSwapOnWrite = !bSwap;
  4192. OpenBSPFile( pBSPFilename );
  4193. if ( g_pBSPHeader->lumps[LUMP_PAKFILE].filelen )
  4194. {
  4195. *pPakSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, pPakData );
  4196. }
  4197. CloseBSPFile();
  4198. return true;
  4199. }
  4200. // compare function for qsort below
  4201. static int LumpOffsetCompare( const void *pElem1, const void *pElem2 )
  4202. {
  4203. int lump1 = *(byte *)pElem1;
  4204. int lump2 = *(byte *)pElem2;
  4205. if ( lump1 != lump2 )
  4206. {
  4207. // force LUMP_MAP_FLAGS to be first, always
  4208. if ( lump1 == LUMP_MAP_FLAGS )
  4209. {
  4210. return -1;
  4211. }
  4212. else if ( lump2 == LUMP_MAP_FLAGS )
  4213. {
  4214. return 1;
  4215. }
  4216. // force LUMP_PAKFILE to be last, always
  4217. if ( lump1 == LUMP_PAKFILE )
  4218. {
  4219. return 1;
  4220. }
  4221. else if ( lump2 == LUMP_PAKFILE )
  4222. {
  4223. return -1;
  4224. }
  4225. }
  4226. int fileOffset1 = g_pBSPHeader->lumps[lump1].fileofs;
  4227. int fileOffset2 = g_pBSPHeader->lumps[lump2].fileofs;
  4228. // invalid or empty lumps will get sorted together
  4229. if ( !g_pBSPHeader->lumps[lump1].filelen )
  4230. {
  4231. fileOffset1 = 0;
  4232. }
  4233. if ( !g_pBSPHeader->lumps[lump2].filelen )
  4234. {
  4235. fileOffset2 = 0;
  4236. }
  4237. // compare by offset
  4238. if ( fileOffset1 < fileOffset2 )
  4239. {
  4240. return -1;
  4241. }
  4242. else if ( fileOffset1 > fileOffset2 )
  4243. {
  4244. return 1;
  4245. }
  4246. return 0;
  4247. }
  4248. //-----------------------------------------------------------------------------
  4249. // Replace the pak lump in a BSP
  4250. //-----------------------------------------------------------------------------
  4251. bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize )
  4252. {
  4253. if ( !g_pFileSystem->FileExists( pBSPFilename ) )
  4254. {
  4255. Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
  4256. return false;
  4257. }
  4258. // determine endian nature
  4259. dheader_t *pHeader;
  4260. LoadFile( pBSPFilename, (void **)&pHeader );
  4261. bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
  4262. free( pHeader );
  4263. g_bSwapOnLoad = bSwap;
  4264. g_bSwapOnWrite = bSwap;
  4265. OpenBSPFile( pBSPFilename );
  4266. // save a copy of the old header
  4267. // generating a new bsp is a destructive operation
  4268. dheader_t oldHeader;
  4269. oldHeader = *g_pBSPHeader;
  4270. g_hBSPFile = SafeOpenWrite( pNewFilename );
  4271. if ( !g_hBSPFile )
  4272. {
  4273. return false;
  4274. }
  4275. // placeholder only, reset at conclusion
  4276. WriteData( &oldHeader );
  4277. // lumps must be reserialized in same relative offset order
  4278. // build sorted order table
  4279. int readOrder[HEADER_LUMPS];
  4280. for ( int i=0; i<HEADER_LUMPS; i++ )
  4281. {
  4282. readOrder[i] = i;
  4283. }
  4284. qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpOffsetCompare );
  4285. for ( int i = 0; i < HEADER_LUMPS; i++ )
  4286. {
  4287. int lump = readOrder[i];
  4288. if ( lump == LUMP_PAKFILE )
  4289. {
  4290. // pak lump always written last, with special alignment
  4291. continue;
  4292. }
  4293. int length = g_pBSPHeader->lumps[lump].filelen;
  4294. if ( length )
  4295. {
  4296. // save the lump data
  4297. int offset = g_pBSPHeader->lumps[lump].fileofs;
  4298. SetAlignedLumpPosition( lump );
  4299. SafeWrite( g_hBSPFile, (byte *)g_pBSPHeader + offset, length );
  4300. }
  4301. else
  4302. {
  4303. g_pBSPHeader->lumps[lump].fileofs = 0;
  4304. }
  4305. }
  4306. // Always write the pak file at the end
  4307. // Pad out the end of the file to a sector boundary for optimal IO
  4308. g_pBSPHeader->lumps[LUMP_PAKFILE].fileofs = AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
  4309. g_pBSPHeader->lumps[LUMP_PAKFILE].filelen = pakSize;
  4310. SafeWrite( g_hBSPFile, pPakData, pakSize );
  4311. // Pad out the end of the file to a sector boundary for optimal IO
  4312. AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
  4313. // Write the updated header
  4314. g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
  4315. WriteData( g_pBSPHeader );
  4316. g_pFileSystem->Close( g_hBSPFile );
  4317. CloseBSPFile();
  4318. return true;
  4319. }
  4320. //-----------------------------------------------------------------------------
  4321. // Build a list of files that BSP owns, world/cubemap materials, static props, etc.
  4322. //-----------------------------------------------------------------------------
  4323. bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList )
  4324. {
  4325. if ( !g_pFileSystem->FileExists( pBSPFilename ) )
  4326. {
  4327. Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
  4328. return false;
  4329. }
  4330. // must be set, but exact hdr not critical for dependant traversal
  4331. SetHDRMode( false );
  4332. LoadBSPFile( pBSPFilename );
  4333. char szBspName[MAX_PATH];
  4334. V_FileBase( pBSPFilename, szBspName, sizeof( szBspName ) );
  4335. V_SetExtension( szBspName, ".bsp", sizeof( szBspName ) );
  4336. // get embedded pak files, and internals
  4337. char szFilename[MAX_PATH];
  4338. int fileSize;
  4339. int fileId = -1;
  4340. for ( ;; )
  4341. {
  4342. fileId = GetPakFile()->GetNextFilename( fileId, szFilename, sizeof( szFilename ), fileSize );
  4343. if ( fileId == -1 )
  4344. {
  4345. break;
  4346. }
  4347. pList->AddToTail( szFilename );
  4348. }
  4349. // get all the world materials
  4350. for ( int i=0; i<numtexdata; i++ )
  4351. {
  4352. const char *pName = TexDataStringTable_GetString( dtexdata[i].nameStringTableID );
  4353. V_ComposeFileName( "materials", pName, szFilename, sizeof( szFilename ) );
  4354. V_SetExtension( szFilename, ".vmt", sizeof( szFilename ) );
  4355. pList->AddToTail( szFilename );
  4356. }
  4357. // get all the static props
  4358. GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
  4359. if ( hGameLump != g_GameLumps.InvalidGameLump() )
  4360. {
  4361. byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
  4362. if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
  4363. {
  4364. int count = ((int *)pGameLumpData)[0];
  4365. pGameLumpData += sizeof( int );
  4366. StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
  4367. for ( int i=0; i<count; i++ )
  4368. {
  4369. pList->AddToTail( pStaticPropDictLump[i].m_Name );
  4370. }
  4371. }
  4372. }
  4373. // get all the detail props
  4374. hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
  4375. if ( hGameLump != g_GameLumps.InvalidGameLump() )
  4376. {
  4377. byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
  4378. if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
  4379. {
  4380. int count = ((int *)pGameLumpData)[0];
  4381. pGameLumpData += sizeof( int );
  4382. DetailObjectDictLump_t *pDetailObjectDictLump = (DetailObjectDictLump_t *)pGameLumpData;
  4383. for ( int i=0; i<count; i++ )
  4384. {
  4385. pList->AddToTail( pDetailObjectDictLump[i].m_Name );
  4386. }
  4387. pGameLumpData += count * sizeof( DetailObjectDictLump_t );
  4388. if ( g_GameLumps.GetGameLumpVersion( hGameLump ) == 4 )
  4389. {
  4390. count = ((int *)pGameLumpData)[0];
  4391. pGameLumpData += sizeof( int );
  4392. if ( count )
  4393. {
  4394. // All detail prop sprites must lie in the material detail/detailsprites
  4395. pList->AddToTail( "materials/detail/detailsprites.vmt" );
  4396. }
  4397. }
  4398. }
  4399. }
  4400. UnloadBSPFile();
  4401. return true;
  4402. }