aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/common/bsplib.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/utils/common/bsplib.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/utils/common/bsplib.cpp')
-rw-r--r--mp/src/utils/common/bsplib.cpp10128
1 files changed, 5064 insertions, 5064 deletions
diff --git a/mp/src/utils/common/bsplib.cpp b/mp/src/utils/common/bsplib.cpp
index 84d1a1d0..c3ad433e 100644
--- a/mp/src/utils/common/bsplib.cpp
+++ b/mp/src/utils/common/bsplib.cpp
@@ -1,5064 +1,5064 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Revision: $
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cmdlib.h"
-#include "mathlib/mathlib.h"
-#include "bsplib.h"
-#include "zip_utils.h"
-#include "scriplib.h"
-#include "utllinkedlist.h"
-#include "bsptreedata.h"
-#include "cmodel.h"
-#include "gamebspfile.h"
-#include "materialsystem/imaterial.h"
-#include "materialsystem/hardwareverts.h"
-#include "utlbuffer.h"
-#include "utlrbtree.h"
-#include "utlsymbol.h"
-#include "utlstring.h"
-#include "checksum_crc.h"
-#include "physdll.h"
-#include "tier0/dbg.h"
-#include "lumpfiles.h"
-#include "vtf/vtf.h"
-
-//=============================================================================
-
-// Boundary each lump should be aligned to
-#define LUMP_ALIGNMENT 4
-
-// Data descriptions for byte swapping - only needed
-// for structures that are written to file for use by the game.
-BEGIN_BYTESWAP_DATADESC( dheader_t )
- DEFINE_FIELD( ident, FIELD_INTEGER ),
- DEFINE_FIELD( version, FIELD_INTEGER ),
- DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ),
- DEFINE_FIELD( mapRevision, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( lump_t )
- DEFINE_FIELD( fileofs, FIELD_INTEGER ),
- DEFINE_FIELD( filelen, FIELD_INTEGER ),
- DEFINE_FIELD( version, FIELD_INTEGER ),
- DEFINE_ARRAY( fourCC, FIELD_CHARACTER, 4 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dflagslump_t )
- DEFINE_FIELD( m_LevelFlags, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dplane_t )
- DEFINE_FIELD( normal, FIELD_VECTOR ),
- DEFINE_FIELD( dist, FIELD_FLOAT ),
- DEFINE_FIELD( type, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleaf_version_0_t )
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( cluster, FIELD_SHORT ),
- DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstleafface, FIELD_SHORT ),
- DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
- DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
- DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
- DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
- DEFINE_EMBEDDED( m_AmbientLighting ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleaf_t )
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( cluster, FIELD_SHORT ),
- DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstleafface, FIELD_SHORT ),
- DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
- DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
- DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
- DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CompressedLightCube ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
- DEFINE_ARRAY( m_Color, FIELD_CHARACTER, 6 * sizeof(ColorRGBExp32) ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafambientindex_t )
- DEFINE_FIELD( ambientSampleCount, FIELD_SHORT ),
- DEFINE_FIELD( firstAmbientSample, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafambientlighting_t ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
- DEFINE_EMBEDDED( cube ),
- DEFINE_FIELD( x, FIELD_CHARACTER ),
- DEFINE_FIELD( y, FIELD_CHARACTER ),
- DEFINE_FIELD( z, FIELD_CHARACTER ),
- DEFINE_FIELD( pad, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dvertex_t )
- DEFINE_FIELD( point, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dnode_t )
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
- DEFINE_ARRAY( children, FIELD_INTEGER, 2 ),
- DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
- DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
- DEFINE_FIELD( firstface, FIELD_SHORT ),
- DEFINE_FIELD( numfaces, FIELD_SHORT ),
- DEFINE_FIELD( area, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( texinfo_t )
- DEFINE_ARRAY( textureVecsTexelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
- DEFINE_ARRAY( lightmapVecsLuxelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( texdata, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dtexdata_t )
- DEFINE_FIELD( reflectivity, FIELD_VECTOR ),
- DEFINE_FIELD( nameStringTableID, FIELD_INTEGER ),
- DEFINE_FIELD( width, FIELD_INTEGER ),
- DEFINE_FIELD( height, FIELD_INTEGER ),
- DEFINE_FIELD( view_width, FIELD_INTEGER ),
- DEFINE_FIELD( view_height, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( ddispinfo_t )
- DEFINE_FIELD( startPosition, FIELD_VECTOR ),
- DEFINE_FIELD( m_iDispVertStart, FIELD_INTEGER ),
- DEFINE_FIELD( m_iDispTriStart, FIELD_INTEGER ),
- DEFINE_FIELD( power, FIELD_INTEGER ),
- DEFINE_FIELD( minTess, FIELD_INTEGER ),
- DEFINE_FIELD( smoothingAngle, FIELD_FLOAT ),
- DEFINE_FIELD( contents, FIELD_INTEGER ),
- DEFINE_FIELD( m_iMapFace, FIELD_SHORT ),
- DEFINE_FIELD( m_iLightmapAlphaStart, FIELD_INTEGER ),
- DEFINE_FIELD( m_iLightmapSamplePositionStart, FIELD_INTEGER ),
- DEFINE_EMBEDDED_ARRAY( m_EdgeNeighbors, 4 ),
- DEFINE_EMBEDDED_ARRAY( m_CornerNeighbors, 4 ),
- DEFINE_ARRAY( m_AllowedVerts, FIELD_INTEGER, ddispinfo_t::ALLOWEDVERTS_SIZE ), // unsigned long
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispNeighbor )
- DEFINE_EMBEDDED_ARRAY( m_SubNeighbors, 2 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispCornerNeighbors )
- DEFINE_ARRAY( m_Neighbors, FIELD_SHORT, MAX_DISP_CORNER_NEIGHBORS ),
- DEFINE_FIELD( m_nNeighbors, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispSubNeighbor )
- DEFINE_FIELD( m_iNeighbor, FIELD_SHORT ),
- DEFINE_FIELD( m_NeighborOrientation, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Span, FIELD_CHARACTER ),
- DEFINE_FIELD( m_NeighborSpan, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispVert )
- DEFINE_FIELD( m_vVector, FIELD_VECTOR ),
- DEFINE_FIELD( m_flDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_flAlpha, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CDispTri )
- DEFINE_FIELD( m_uiTags, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( CFaceMacroTextureInfo )
- DEFINE_FIELD( m_MacroTextureNameID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dprimitive_t )
- DEFINE_FIELD( type, FIELD_CHARACTER ),
- DEFINE_FIELD( firstIndex, FIELD_SHORT ),
- DEFINE_FIELD( indexCount, FIELD_SHORT ),
- DEFINE_FIELD( firstVert, FIELD_SHORT ),
- DEFINE_FIELD( vertCount, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dprimvert_t )
- DEFINE_FIELD( pos, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dface_t )
- DEFINE_FIELD( planenum, FIELD_SHORT ),
- DEFINE_FIELD( side, FIELD_CHARACTER ),
- DEFINE_FIELD( onNode, FIELD_CHARACTER ),
- DEFINE_FIELD( firstedge, FIELD_INTEGER ),
- DEFINE_FIELD( numedges, FIELD_SHORT ),
- DEFINE_FIELD( texinfo, FIELD_SHORT ),
- DEFINE_FIELD( dispinfo, FIELD_SHORT ),
- DEFINE_FIELD( surfaceFogVolumeID, FIELD_SHORT ),
- DEFINE_ARRAY( styles, FIELD_CHARACTER, MAXLIGHTMAPS ),
- DEFINE_FIELD( lightofs, FIELD_INTEGER ),
- DEFINE_FIELD( area, FIELD_FLOAT ),
- DEFINE_ARRAY( m_LightmapTextureMinsInLuxels, FIELD_INTEGER, 2 ),
- DEFINE_ARRAY( m_LightmapTextureSizeInLuxels, FIELD_INTEGER, 2 ),
- DEFINE_FIELD( origFace, FIELD_INTEGER ),
- DEFINE_FIELD( m_NumPrims, FIELD_SHORT ),
- DEFINE_FIELD( firstPrimID, FIELD_SHORT ),
- DEFINE_FIELD( smoothingGroups, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dfaceid_t )
- DEFINE_FIELD( hammerfaceid, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dbrush_t )
- DEFINE_FIELD( firstside, FIELD_INTEGER ),
- DEFINE_FIELD( numsides, FIELD_INTEGER ),
- DEFINE_FIELD( contents, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dbrushside_t )
- DEFINE_FIELD( planenum, FIELD_SHORT ),
- DEFINE_FIELD( texinfo, FIELD_SHORT ),
- DEFINE_FIELD( dispinfo, FIELD_SHORT ),
- DEFINE_FIELD( bevel, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dedge_t )
- DEFINE_ARRAY( v, FIELD_SHORT, 2 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dmodel_t )
- DEFINE_FIELD( mins, FIELD_VECTOR ),
- DEFINE_FIELD( maxs, FIELD_VECTOR ),
- DEFINE_FIELD( origin, FIELD_VECTOR ),
- DEFINE_FIELD( headnode, FIELD_INTEGER ),
- DEFINE_FIELD( firstface, FIELD_INTEGER ),
- DEFINE_FIELD( numfaces, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dphysmodel_t )
- DEFINE_FIELD( modelIndex, FIELD_INTEGER ),
- DEFINE_FIELD( dataSize, FIELD_INTEGER ),
- DEFINE_FIELD( keydataSize, FIELD_INTEGER ),
- DEFINE_FIELD( solidCount, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dphysdisp_t )
- DEFINE_FIELD( numDisplacements, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( darea_t )
- DEFINE_FIELD( numareaportals, FIELD_INTEGER ),
- DEFINE_FIELD( firstareaportal, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dareaportal_t )
- DEFINE_FIELD( m_PortalKey, FIELD_SHORT ),
- DEFINE_FIELD( otherarea, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstClipPortalVert, FIELD_SHORT ),
- DEFINE_FIELD( m_nClipPortalVerts, FIELD_SHORT ),
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dworldlight_t )
- DEFINE_FIELD( origin, FIELD_VECTOR ),
- DEFINE_FIELD( intensity, FIELD_VECTOR ),
- DEFINE_FIELD( normal, FIELD_VECTOR ),
- DEFINE_FIELD( cluster, FIELD_INTEGER ),
- DEFINE_FIELD( type, FIELD_INTEGER ), // enumeration
- DEFINE_FIELD( style, FIELD_INTEGER ),
- DEFINE_FIELD( stopdot, FIELD_FLOAT ),
- DEFINE_FIELD( stopdot2, FIELD_FLOAT ),
- DEFINE_FIELD( exponent, FIELD_FLOAT ),
- DEFINE_FIELD( radius, FIELD_FLOAT ),
- DEFINE_FIELD( constant_attn, FIELD_FLOAT ),
- DEFINE_FIELD( linear_attn, FIELD_FLOAT ),
- DEFINE_FIELD( quadratic_attn, FIELD_FLOAT ),
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( texinfo, FIELD_INTEGER ),
- DEFINE_FIELD( owner, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dleafwaterdata_t )
- DEFINE_FIELD( surfaceZ, FIELD_FLOAT ),
- DEFINE_FIELD( minZ, FIELD_FLOAT ),
- DEFINE_FIELD( surfaceTexInfoID, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doccluderdata_t )
- DEFINE_FIELD( flags, FIELD_INTEGER ),
- DEFINE_FIELD( firstpoly, FIELD_INTEGER ),
- DEFINE_FIELD( polycount, FIELD_INTEGER ),
- DEFINE_FIELD( mins, FIELD_VECTOR ),
- DEFINE_FIELD( maxs, FIELD_VECTOR ),
- DEFINE_FIELD( area, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doccluderpolydata_t )
- DEFINE_FIELD( firstvertexindex, FIELD_INTEGER ),
- DEFINE_FIELD( vertexcount, FIELD_INTEGER ),
- DEFINE_FIELD( planenum, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dcubemapsample_t )
- DEFINE_ARRAY( origin, FIELD_INTEGER, 3 ),
- DEFINE_FIELD( size, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doverlay_t )
- DEFINE_FIELD( nId, FIELD_INTEGER ),
- DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
- DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
- DEFINE_ARRAY( aFaces, FIELD_INTEGER, OVERLAY_BSP_FACE_COUNT ),
- DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
- DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dwateroverlay_t )
- DEFINE_FIELD( nId, FIELD_INTEGER ),
- DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
- DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
- DEFINE_ARRAY( aFaces, FIELD_INTEGER, WATEROVERLAY_BSP_FACE_COUNT ),
- DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
- DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
- DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( doverlayfade_t )
- DEFINE_FIELD( flFadeDistMinSq, FIELD_FLOAT ),
- DEFINE_FIELD( flFadeDistMaxSq, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dgamelumpheader_t )
- DEFINE_FIELD( lumpCount, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( dgamelump_t )
- DEFINE_FIELD( id, FIELD_INTEGER ), // GameLumpId_t
- DEFINE_FIELD( flags, FIELD_SHORT ),
- DEFINE_FIELD( version, FIELD_SHORT ),
- DEFINE_FIELD( fileofs, FIELD_INTEGER ),
- DEFINE_FIELD( filelen, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-// From gamebspfile.h
-BEGIN_BYTESWAP_DATADESC( StaticPropDictLump_t )
- DEFINE_ARRAY( m_Name, FIELD_CHARACTER, STATIC_PROP_NAME_LENGTH ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLump_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
- DEFINE_FIELD( m_nMinDXLevel, FIELD_SHORT ),
- DEFINE_FIELD( m_nMaxDXLevel, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLumpV4_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLumpV5_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_PropType, FIELD_SHORT ),
- DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
- DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
- DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
- DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
- DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
- DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( StaticPropLeafLump_t )
- DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailObjectDictLump_t )
- DEFINE_ARRAY( m_Name, FIELD_CHARACTER, DETAIL_NAME_LENGTH ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailObjectLump_t )
- DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
- DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
- DEFINE_FIELD( m_DetailModel, FIELD_SHORT ),
- DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
- DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
- DEFINE_FIELD( m_LightStyles, FIELD_INTEGER ),
- DEFINE_FIELD( m_LightStyleCount, FIELD_CHARACTER ),
- DEFINE_FIELD( m_SwayAmount, FIELD_CHARACTER ),
- DEFINE_FIELD( m_ShapeAngle, FIELD_CHARACTER ),
- DEFINE_FIELD( m_ShapeSize, FIELD_CHARACTER ),
- DEFINE_FIELD( m_Orientation, FIELD_CHARACTER ),
- DEFINE_ARRAY( m_Padding2, FIELD_CHARACTER, 3 ),
- DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
- DEFINE_ARRAY( m_Padding3, FIELD_CHARACTER, 3 ),
- DEFINE_FIELD( m_flScale, FIELD_FLOAT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailSpriteDictLump_t )
- DEFINE_FIELD( m_UL, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_LR, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_TexUL, FIELD_VECTOR2D ),
- DEFINE_FIELD( m_TexLR, FIELD_VECTOR2D ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( DetailPropLightstylesLump_t )
- DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
- DEFINE_FIELD( m_Style, FIELD_CHARACTER ),
-END_BYTESWAP_DATADESC()
-
-// From vradstaticprops.h
-namespace HardwareVerts
-{
-BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
- DEFINE_FIELD( m_nLod, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
- DEFINE_FIELD( m_nOffset, FIELD_INTEGER ),
- DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC( FileHeader_t )
- DEFINE_FIELD( m_nVersion, FIELD_INTEGER ),
- DEFINE_FIELD( m_nChecksum, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexFlags, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexSize, FIELD_INTEGER ),
- DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
- DEFINE_FIELD( m_nMeshes, FIELD_INTEGER ),
- DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
-END_BYTESWAP_DATADESC()
-} // end namespace
-
-static const char *s_LumpNames[] = {
- "LUMP_ENTITIES", // 0
- "LUMP_PLANES", // 1
- "LUMP_TEXDATA", // 2
- "LUMP_VERTEXES", // 3
- "LUMP_VISIBILITY", // 4
- "LUMP_NODES", // 5
- "LUMP_TEXINFO", // 6
- "LUMP_FACES", // 7
- "LUMP_LIGHTING", // 8
- "LUMP_OCCLUSION", // 9
- "LUMP_LEAFS", // 10
- "LUMP_FACEIDS", // 11
- "LUMP_EDGES", // 12
- "LUMP_SURFEDGES", // 13
- "LUMP_MODELS", // 14
- "LUMP_WORLDLIGHTS", // 15
- "LUMP_LEAFFACES", // 16
- "LUMP_LEAFBRUSHES", // 17
- "LUMP_BRUSHES", // 18
- "LUMP_BRUSHSIDES", // 19
- "LUMP_AREAS", // 20
- "LUMP_AREAPORTALS", // 21
- "LUMP_UNUSED0", // 22
- "LUMP_UNUSED1", // 23
- "LUMP_UNUSED2", // 24
- "LUMP_UNUSED3", // 25
- "LUMP_DISPINFO", // 26
- "LUMP_ORIGINALFACES", // 27
- "LUMP_PHYSDISP", // 28
- "LUMP_PHYSCOLLIDE", // 29
- "LUMP_VERTNORMALS", // 30
- "LUMP_VERTNORMALINDICES", // 31
- "LUMP_DISP_LIGHTMAP_ALPHAS", // 32
- "LUMP_DISP_VERTS", // 33
- "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", // 34
- "LUMP_GAME_LUMP", // 35
- "LUMP_LEAFWATERDATA", // 36
- "LUMP_PRIMITIVES", // 37
- "LUMP_PRIMVERTS", // 38
- "LUMP_PRIMINDICES", // 39
- "LUMP_PAKFILE", // 40
- "LUMP_CLIPPORTALVERTS", // 41
- "LUMP_CUBEMAPS", // 42
- "LUMP_TEXDATA_STRING_DATA", // 43
- "LUMP_TEXDATA_STRING_TABLE", // 44
- "LUMP_OVERLAYS", // 45
- "LUMP_LEAFMINDISTTOWATER", // 46
- "LUMP_FACE_MACRO_TEXTURE_INFO", // 47
- "LUMP_DISP_TRIS", // 48
- "LUMP_PHYSCOLLIDESURFACE", // 49
- "LUMP_WATEROVERLAYS", // 50
- "LUMP_LEAF_AMBIENT_INDEX_HDR", // 51
- "LUMP_LEAF_AMBIENT_INDEX", // 52
- "LUMP_LIGHTING_HDR", // 53
- "LUMP_WORLDLIGHTS_HDR", // 54
- "LUMP_LEAF_AMBIENT_LIGHTING_HDR", // 55
- "LUMP_LEAF_AMBIENT_LIGHTING", // 56
- "LUMP_XZIPPAKFILE", // 57
- "LUMP_FACES_HDR", // 58
- "LUMP_MAP_FLAGS", // 59
- "LUMP_OVERLAY_FADES", // 60
-};
-
-const char *GetLumpName( unsigned int lumpnum )
-{
- if ( lumpnum >= ARRAYSIZE( s_LumpNames ) )
- {
- return "UNKNOWN";
- }
- return s_LumpNames[lumpnum];
-}
-
-// "-hdr" tells us to use the HDR fields (if present) on the light sources. Also, tells us to write
-// out the HDR lumps for lightmaps, ambient leaves, and lights sources.
-bool g_bHDR = false;
-
-// Set to true to generate Xbox360 native output files
-static bool g_bSwapOnLoad = false;
-static bool g_bSwapOnWrite = false;
-
-VTFConvertFunc_t g_pVTFConvertFunc;
-VHVFixupFunc_t g_pVHVFixupFunc;
-CompressFunc_t g_pCompressFunc;
-
-CUtlVector< CUtlString > g_StaticPropNames;
-CUtlVector< int > g_StaticPropInstances;
-
-CByteswap g_Swap;
-
-uint32 g_LevelFlags = 0;
-
-int nummodels;
-dmodel_t dmodels[MAX_MAP_MODELS];
-
-int visdatasize;
-byte dvisdata[MAX_MAP_VISIBILITY];
-dvis_t *dvis = (dvis_t *)dvisdata;
-
-CUtlVector<byte> dlightdataHDR;
-CUtlVector<byte> dlightdataLDR;
-CUtlVector<byte> *pdlightdata = &dlightdataLDR;
-
-CUtlVector<char> dentdata;
-
-int numleafs;
-#if !defined( BSP_USE_LESS_MEMORY )
-dleaf_t dleafs[MAX_MAP_LEAFS];
-#else
-dleaf_t *dleafs;
-#endif
-
-CUtlVector<dleafambientindex_t> g_LeafAmbientIndexLDR;
-CUtlVector<dleafambientindex_t> g_LeafAmbientIndexHDR;
-CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex = NULL;
-CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingLDR;
-CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingHDR;
-CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting = NULL;
-
-unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
-
-int numplanes;
-dplane_t dplanes[MAX_MAP_PLANES];
-
-int numvertexes;
-dvertex_t dvertexes[MAX_MAP_VERTS];
-
-int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
-unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
-
-int g_numvertnormals;
-Vector g_vertnormals[MAX_MAP_VERTNORMALS];
-
-int numnodes;
-dnode_t dnodes[MAX_MAP_NODES];
-
-CUtlVector<texinfo_t> texinfo( MAX_MAP_TEXINFO );
-
-int numtexdata;
-dtexdata_t dtexdata[MAX_MAP_TEXDATA];
-
-//
-// displacement map bsp file info: dispinfo
-//
-CUtlVector<ddispinfo_t> g_dispinfo;
-CUtlVector<CDispVert> g_DispVerts;
-CUtlVector<CDispTri> g_DispTris;
-CUtlVector<unsigned char> g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
-
-int numorigfaces;
-dface_t dorigfaces[MAX_MAP_FACES];
-
-int g_numprimitives = 0;
-dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
-
-int g_numprimverts = 0;
-dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
-
-int g_numprimindices = 0;
-unsigned short g_primindices[MAX_MAP_PRIMINDICES];
-
-int numfaces;
-dface_t dfaces[MAX_MAP_FACES];
-
-int numfaceids;
-CUtlVector<dfaceid_t> dfaceids;
-
-int numfaces_hdr;
-dface_t dfaces_hdr[MAX_MAP_FACES];
-
-int numedges;
-dedge_t dedges[MAX_MAP_EDGES];
-
-int numleaffaces;
-unsigned short dleaffaces[MAX_MAP_LEAFFACES];
-
-int numleafbrushes;
-unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
-
-int numsurfedges;
-int dsurfedges[MAX_MAP_SURFEDGES];
-
-int numbrushes;
-dbrush_t dbrushes[MAX_MAP_BRUSHES];
-
-int numbrushsides;
-dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
-
-int numareas;
-darea_t dareas[MAX_MAP_AREAS];
-
-int numareaportals;
-dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
-
-int numworldlightsLDR;
-dworldlight_t dworldlightsLDR[MAX_MAP_WORLDLIGHTS];
-
-int numworldlightsHDR;
-dworldlight_t dworldlightsHDR[MAX_MAP_WORLDLIGHTS];
-
-int *pNumworldlights = &numworldlightsLDR;
-dworldlight_t *dworldlights = dworldlightsLDR;
-
-int numleafwaterdata = 0;
-dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
-
-CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
-
-Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
-int g_nClipPortalVerts;
-
-dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
-int g_nCubemapSamples = 0;
-
-int g_nOverlayCount;
-doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
-doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS];
-
-int g_nWaterOverlayCount;
-dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
-
-CUtlVector<char> g_TexDataStringData;
-CUtlVector<int> g_TexDataStringTable;
-
-byte *g_pPhysCollide = NULL;
-int g_PhysCollideSize = 0;
-int g_MapRevision = 0;
-
-byte *g_pPhysDisp = NULL;
-int g_PhysDispSize = 0;
-
-CUtlVector<doccluderdata_t> g_OccluderData( 256, 256 );
-CUtlVector<doccluderpolydata_t> g_OccluderPolyData( 1024, 1024 );
-CUtlVector<int> g_OccluderVertexIndices( 2048, 2048 );
-
-template <class T> static void WriteData( T *pData, int count = 1 );
-template <class T> static void WriteData( int fieldType, T *pData, int count = 1 );
-template< class T > static void AddLump( int lumpnum, T *pData, int count, int version = 0 );
-template< class T > static void AddLump( int lumpnum, CUtlVector<T> &data, int version = 0 );
-
-dheader_t *g_pBSPHeader;
-FileHandle_t g_hBSPFile;
-
-struct Lump_t
-{
- void *pLumps[HEADER_LUMPS];
- int size[HEADER_LUMPS];
- bool bLumpParsed[HEADER_LUMPS];
-} g_Lumps;
-
-CGameLump g_GameLumps;
-
-static IZip *s_pakFile = 0;
-
-//-----------------------------------------------------------------------------
-// Keep the file position aligned to an arbitrary boundary.
-// Returns updated file position.
-//-----------------------------------------------------------------------------
-static unsigned int AlignFilePosition( FileHandle_t hFile, int alignment )
-{
- unsigned int currPosition = g_pFileSystem->Tell( hFile );
-
- if ( alignment >= 2 )
- {
- unsigned int newPosition = AlignValue( currPosition, alignment );
- unsigned int count = newPosition - currPosition;
- if ( count )
- {
- char *pBuffer;
- char smallBuffer[4096];
- if ( count > sizeof( smallBuffer ) )
- {
- pBuffer = (char *)malloc( count );
- }
- else
- {
- pBuffer = smallBuffer;
- }
-
- memset( pBuffer, 0, count );
- SafeWrite( hFile, pBuffer, count );
-
- if ( pBuffer != smallBuffer )
- {
- free( pBuffer );
- }
-
- currPosition = newPosition;
- }
- }
-
- return currPosition;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: // Get a pakfile instance
-// Output : IZip*
-//-----------------------------------------------------------------------------
-IZip* GetPakFile( void )
-{
- if ( !s_pakFile )
- {
- s_pakFile = IZip::CreateZip();
- }
- return s_pakFile;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Free the pak files
-//-----------------------------------------------------------------------------
-void ReleasePakFileLumps( void )
-{
- // Release the pak files
- IZip::ReleaseZip( s_pakFile );
- s_pakFile = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the sector alignment for all subsequent zip operations
-//-----------------------------------------------------------------------------
-void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize )
-{
- pak->ForceAlignment( bAlign, bCompatibleFormat, alignmentSize );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Store data back out to .bsp file
-//-----------------------------------------------------------------------------
-static void WritePakFileLump( void )
-{
- CUtlBuffer buf( 0, 0 );
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->SaveToBuffer( buf );
-
- // must respect pak file alignment
- // pad up and ensure lump starts on same aligned boundary
- AlignFilePosition( g_hBSPFile, GetPakFile()->GetAlignment() );
-
- // Now store final buffers out to file
- AddLump( LUMP_PAKFILE, (byte*)buf.Base(), buf.TellPut() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove all entries
-//-----------------------------------------------------------------------------
-void ClearPakFile( IZip *pak )
-{
- pak->Reset();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Add file from disk to .bsp PAK lump
-// Input : *relativename -
-// *fullpath -
-//-----------------------------------------------------------------------------
-void AddFileToPak( IZip *pak, const char *relativename, const char *fullpath )
-{
- pak->AddFileToZip( relativename, fullpath );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Add buffer to .bsp PAK lump as named file
-// Input : *relativename -
-// *data -
-// length -
-//-----------------------------------------------------------------------------
-void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode )
-{
- pak->AddBufferToZip( pRelativeName, data, length, bTextMode );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Check if a file already exists in the pack file.
-// Input : *relativename -
-//-----------------------------------------------------------------------------
-bool FileExistsInPak( IZip *pak, const char *pRelativeName )
-{
- return pak->FileExistsInZip( pRelativeName );
-}
-
-
-//-----------------------------------------------------------------------------
-// Read a file from the pack file
-//-----------------------------------------------------------------------------
-bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
-{
- return pak->ReadFileFromZip( pRelativeName, bTextMode, buf );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove file from .bsp PAK lump
-// Input : *relativename -
-//-----------------------------------------------------------------------------
-void RemoveFileFromPak( IZip *pak, const char *relativename )
-{
- pak->RemoveFileFromZip( relativename );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Get next filename in directory
-// Input : id, -1 to start, returns next id, or -1 at list conclusion
-//-----------------------------------------------------------------------------
-int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize )
-{
- return pak->GetNextFilename( id, pBuffer, bufferSize, fileSize );
-}
-
-//-----------------------------------------------------------------------------
-// Convert four-CC code to a handle + back
-//-----------------------------------------------------------------------------
-GameLumpHandle_t CGameLump::GetGameLumpHandle( GameLumpId_t id )
-{
- // NOTE: I'm also expecting game lump id's to be four-CC codes
- Assert( id > HEADER_LUMPS );
-
- FOR_EACH_LL(m_GameLumps, i)
- {
- if (m_GameLumps[i].m_Id == id)
- return i;
- }
-
- return InvalidGameLump();
-}
-
-GameLumpId_t CGameLump::GetGameLumpId( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Id;
-}
-
-int CGameLump::GetGameLumpFlags( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Flags;
-}
-
-int CGameLump::GetGameLumpVersion( GameLumpHandle_t handle )
-{
- return m_GameLumps[handle].m_Version;
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump accessor methods
-//-----------------------------------------------------------------------------
-
-void* CGameLump::GetGameLump( GameLumpHandle_t id )
-{
- return m_GameLumps[id].m_Memory.Base();
-}
-
-int CGameLump::GameLumpSize( GameLumpHandle_t id )
-{
- return m_GameLumps[id].m_Memory.NumAllocated();
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump iteration methods
-//-----------------------------------------------------------------------------
-
-GameLumpHandle_t CGameLump::FirstGameLump()
-{
- return (m_GameLumps.Count()) ? m_GameLumps.Head() : InvalidGameLump();
-}
-
-GameLumpHandle_t CGameLump::NextGameLump( GameLumpHandle_t handle )
-{
-
- return (m_GameLumps.IsValidIndex(handle)) ? m_GameLumps.Next(handle) : InvalidGameLump();
-}
-
-GameLumpHandle_t CGameLump::InvalidGameLump()
-{
- return 0xFFFF;
-}
-
-
-//-----------------------------------------------------------------------------
-// Game lump creation/destruction method
-//-----------------------------------------------------------------------------
-
-GameLumpHandle_t CGameLump::CreateGameLump( GameLumpId_t id, int size, int flags, int version )
-{
- Assert( GetGameLumpHandle(id) == InvalidGameLump() );
- GameLumpHandle_t handle = m_GameLumps.AddToTail();
- m_GameLumps[handle].m_Id = id;
- m_GameLumps[handle].m_Flags = flags;
- m_GameLumps[handle].m_Version = version;
- m_GameLumps[handle].m_Memory.EnsureCapacity( size );
- return handle;
-}
-
-void CGameLump::DestroyGameLump( GameLumpHandle_t handle )
-{
- m_GameLumps.Remove( handle );
-}
-
-void CGameLump::DestroyAllGameLumps()
-{
- m_GameLumps.RemoveAll();
-}
-
-//-----------------------------------------------------------------------------
-// Compute file size and clump count
-//-----------------------------------------------------------------------------
-
-void CGameLump::ComputeGameLumpSizeAndCount( int& size, int& clumpCount )
-{
- // Figure out total size of the client lumps
- size = 0;
- clumpCount = 0;
- GameLumpHandle_t h;
- for( h = FirstGameLump(); h != InvalidGameLump(); h = NextGameLump( h ) )
- {
- ++clumpCount;
- size += GameLumpSize( h );
- }
-
- // Add on headers
- size += sizeof( dgamelumpheader_t ) + clumpCount * sizeof( dgamelump_t );
-}
-
-
-void CGameLump::SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int length )
-{
- int count = 0;
- switch( id )
- {
- case GAMELUMP_STATIC_PROPS:
- // Swap the static prop model dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (StaticPropDictLump_t*)dest, (StaticPropDictLump_t*)src, count );
- src += sizeof(StaticPropDictLump_t) * count;
- dest += sizeof(StaticPropDictLump_t) * count;
-
- // Swap the leaf list
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (StaticPropLeafLump_t*)dest, (StaticPropLeafLump_t*)src, count );
- src += sizeof(StaticPropLeafLump_t) * count;
- dest += sizeof(StaticPropLeafLump_t) * count;
-
- // Swap the models
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- // The one-at-a-time swap is to compensate for these structures
- // possibly being misaligned, which crashes the Xbox 360.
- if ( version == 4 )
- {
- StaticPropLumpV4_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLumpV4_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLumpV4_t) );
- src += sizeof( StaticPropLumpV4_t );
- dest += sizeof( StaticPropLumpV4_t );
- }
- }
- else if ( version == 5 )
- {
- StaticPropLumpV5_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLumpV5_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLumpV5_t) );
- src += sizeof( StaticPropLumpV5_t );
- dest += sizeof( StaticPropLumpV5_t );
- }
- }
- else
- {
- if ( version != 6 )
- {
- Error( "Unknown Static Prop Lump version %d didn't get swapped!\n", version );
- }
-
- StaticPropLump_t lump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &lump, src, sizeof(StaticPropLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
- Q_memcpy( dest, &lump, sizeof(StaticPropLump_t) );
- src += sizeof( StaticPropLump_t );
- dest += sizeof( StaticPropLump_t );
- }
- }
- break;
-
- case GAMELUMP_DETAIL_PROPS:
- // Swap the detail prop model dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailObjectDictLump_t*)dest, (DetailObjectDictLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
-
- if ( version == 4 )
- {
- // Swap the detail sprite dict
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- DetailSpriteDictLump_t spritelump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &spritelump, src, sizeof(DetailSpriteDictLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &spritelump, &spritelump );
- Q_memcpy( dest, &spritelump, sizeof(DetailSpriteDictLump_t) );
- src += sizeof(DetailSpriteDictLump_t);
- dest += sizeof(DetailSpriteDictLump_t);
- }
-
- // Swap the models
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- DetailObjectLump_t objectlump;
- for ( int i = 0; i < count; ++i )
- {
- Q_memcpy( &objectlump, src, sizeof(DetailObjectLump_t) );
- g_Swap.SwapFieldsToTargetEndian( &objectlump, &objectlump );
- Q_memcpy( dest, &objectlump, sizeof(DetailObjectLump_t) );
- src += sizeof(DetailObjectLump_t);
- dest += sizeof(DetailObjectLump_t);
- }
- }
- break;
-
- case GAMELUMP_DETAIL_PROP_LIGHTING:
- // Swap the LDR light styles
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
- break;
-
- case GAMELUMP_DETAIL_PROP_LIGHTING_HDR:
- // Swap the HDR light styles
- count = *(int*)src;
- g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
- count = g_bSwapOnLoad ? *(int*)dest : count;
- src += sizeof(int);
- dest += sizeof(int);
-
- g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
- src += sizeof(DetailObjectDictLump_t) * count;
- dest += sizeof(DetailObjectDictLump_t) * count;
- break;
-
- default:
- char idchars[5] = {0};
- Q_memcpy( idchars, &id, 4 );
- Warning( "Unknown game lump '%s' didn't get swapped!\n", idchars );
- memcpy ( dest, src, length);
- break;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Game lump file I/O
-//-----------------------------------------------------------------------------
-void CGameLump::ParseGameLump( dheader_t* pHeader )
-{
- g_GameLumps.DestroyAllGameLumps();
-
- g_Lumps.bLumpParsed[LUMP_GAME_LUMP] = true;
-
- int length = pHeader->lumps[LUMP_GAME_LUMP].filelen;
- int ofs = pHeader->lumps[LUMP_GAME_LUMP].fileofs;
-
- if (length > 0)
- {
- // Read dictionary...
- dgamelumpheader_t* pGameLumpHeader = (dgamelumpheader_t*)((byte *)pHeader + ofs);
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( pGameLumpHeader );
- }
- dgamelump_t* pGameLump = (dgamelump_t*)(pGameLumpHeader + 1);
- for (int i = 0; i < pGameLumpHeader->lumpCount; ++i )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pGameLump[i] );
- }
-
- int length = pGameLump[i].filelen;
- GameLumpHandle_t lump = g_GameLumps.CreateGameLump( pGameLump[i].id, length, pGameLump[i].flags, pGameLump[i].version );
- if ( g_bSwapOnLoad )
- {
- SwapGameLump( pGameLump[i].id, pGameLump[i].version, (byte*)g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
- }
- else
- {
- memcpy( g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// String table methods
-//-----------------------------------------------------------------------------
-const char *TexDataStringTable_GetString( int stringID )
-{
- return &g_TexDataStringData[g_TexDataStringTable[stringID]];
-}
-
-int TexDataStringTable_AddOrFindString( const char *pString )
-{
- int i;
- // garymcthack: Make this use an RBTree!
- for( i = 0; i < g_TexDataStringTable.Count(); i++ )
- {
- if( stricmp( pString, &g_TexDataStringData[g_TexDataStringTable[i]] ) == 0 )
- {
- return i;
- }
- }
-
- int len = strlen( pString );
- int outOffset = g_TexDataStringData.AddMultipleToTail( len+1, pString );
- int outIndex = g_TexDataStringTable.AddToTail( outOffset );
- return outIndex;
-}
-
-//-----------------------------------------------------------------------------
-// Adds all game lumps into one big block
-//-----------------------------------------------------------------------------
-
-static void AddGameLumps( )
-{
- // Figure out total size of the client lumps
- int size, clumpCount;
- g_GameLumps.ComputeGameLumpSizeAndCount( size, clumpCount );
-
- // Set up the main lump dictionary entry
- g_Lumps.size[LUMP_GAME_LUMP] = 0; // mark it written
-
- lump_t* lump = &g_pBSPHeader->lumps[LUMP_GAME_LUMP];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = size;
-
- // write header
- dgamelumpheader_t header;
- header.lumpCount = clumpCount;
- WriteData( &header );
-
- // write dictionary
- dgamelump_t dict;
- int offset = lump->fileofs + sizeof(header) + clumpCount * sizeof(dgamelump_t);
- GameLumpHandle_t h;
- for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
- {
- dict.id = g_GameLumps.GetGameLumpId(h);
- dict.version = g_GameLumps.GetGameLumpVersion(h);
- dict.flags = g_GameLumps.GetGameLumpFlags(h);
- dict.fileofs = offset;
- dict.filelen = g_GameLumps.GameLumpSize( h );
- offset += dict.filelen;
-
- WriteData( &dict );
- }
-
- // write lumps..
- for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
- {
- unsigned int lumpsize = g_GameLumps.GameLumpSize(h);
- if ( g_bSwapOnWrite )
- {
- g_GameLumps.SwapGameLump( g_GameLumps.GetGameLumpId(h), g_GameLumps.GetGameLumpVersion(h), (byte*)g_GameLumps.GetGameLump(h), (byte*)g_GameLumps.GetGameLump(h), lumpsize );
- }
- SafeWrite( g_hBSPFile, g_GameLumps.GetGameLump(h), lumpsize );
- }
-
- // align to doubleword
- AlignFilePosition( g_hBSPFile, 4 );
-}
-
-
-//-----------------------------------------------------------------------------
-// Adds the occluder lump...
-//-----------------------------------------------------------------------------
-static void AddOcclusionLump( )
-{
- g_Lumps.size[LUMP_OCCLUSION] = 0; // mark it written
-
- int nOccluderCount = g_OccluderData.Count();
- int nOccluderPolyDataCount = g_OccluderPolyData.Count();
- int nOccluderVertexIndices = g_OccluderVertexIndices.Count();
-
- int nLumpLength = nOccluderCount * sizeof(doccluderdata_t) +
- nOccluderPolyDataCount * sizeof(doccluderpolydata_t) +
- nOccluderVertexIndices * sizeof(int) +
- 3 * sizeof(int);
-
- lump_t *lump = &g_pBSPHeader->lumps[LUMP_OCCLUSION];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = nLumpLength;
- lump->version = LUMP_OCCLUSION_VERSION;
- lump->fourCC[0] = ( char )0;
- lump->fourCC[1] = ( char )0;
- lump->fourCC[2] = ( char )0;
- lump->fourCC[3] = ( char )0;
-
- // Data is swapped in place, so the 'Count' variables aren't safe to use after they're written
- WriteData( FIELD_INTEGER, &nOccluderCount );
- WriteData( (doccluderdata_t*)g_OccluderData.Base(), g_OccluderData.Count() );
- WriteData( FIELD_INTEGER, &nOccluderPolyDataCount );
- WriteData( (doccluderpolydata_t*)g_OccluderPolyData.Base(), g_OccluderPolyData.Count() );
- WriteData( FIELD_INTEGER, &nOccluderVertexIndices );
- WriteData( FIELD_INTEGER, (int*)g_OccluderVertexIndices.Base(), g_OccluderVertexIndices.Count() );
-}
-
-
-//-----------------------------------------------------------------------------
-// Loads the occluder lump...
-//-----------------------------------------------------------------------------
-static void UnserializeOcclusionLumpV2( CUtlBuffer &buf )
-{
- int nCount = buf.GetInt();
- if ( nCount )
- {
- g_OccluderData.SetCount( nCount );
- buf.GetObjects( g_OccluderData.Base(), nCount );
- }
-
- nCount = buf.GetInt();
- if ( nCount )
- {
- g_OccluderPolyData.SetCount( nCount );
- buf.GetObjects( g_OccluderPolyData.Base(), nCount );
- }
-
- nCount = buf.GetInt();
- if ( nCount )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( (int*)buf.PeekGet(), (int*)buf.PeekGet(), nCount );
- }
- g_OccluderVertexIndices.SetCount( nCount );
- buf.Get( g_OccluderVertexIndices.Base(), nCount * sizeof(g_OccluderVertexIndices[0]) );
- }
-}
-
-
-static void LoadOcclusionLump()
-{
- g_OccluderData.RemoveAll();
- g_OccluderPolyData.RemoveAll();
- g_OccluderVertexIndices.RemoveAll();
-
- int length, ofs;
-
- g_Lumps.bLumpParsed[LUMP_OCCLUSION] = true;
-
- length = g_pBSPHeader->lumps[LUMP_OCCLUSION].filelen;
- ofs = g_pBSPHeader->lumps[LUMP_OCCLUSION].fileofs;
-
- CUtlBuffer buf( (byte *)g_pBSPHeader + ofs, length, CUtlBuffer::READ_ONLY );
- buf.ActivateByteSwapping( g_bSwapOnLoad );
- switch ( g_pBSPHeader->lumps[LUMP_OCCLUSION].version )
- {
- case 2:
- UnserializeOcclusionLumpV2( buf );
- break;
-
- case 0:
- break;
-
- default:
- Error("Unknown occlusion lump version!\n");
- break;
- }
-}
-
-
-/*
-===============
-CompressVis
-
-===============
-*/
-int CompressVis (byte *vis, byte *dest)
-{
- int j;
- int rep;
- int visrow;
- byte *dest_p;
-
- dest_p = dest;
-// visrow = (r_numvisleafs + 7)>>3;
- visrow = (dvis->numclusters + 7)>>3;
-
- for (j=0 ; j<visrow ; j++)
- {
- *dest_p++ = vis[j];
- if (vis[j])
- continue;
-
- rep = 1;
- for ( j++; j<visrow ; j++)
- if (vis[j] || rep == 255)
- break;
- else
- rep++;
- *dest_p++ = rep;
- j--;
- }
-
- return dest_p - dest;
-}
-
-
-/*
-===================
-DecompressVis
-===================
-*/
-void DecompressVis (byte *in, byte *decompressed)
-{
- int c;
- byte *out;
- int row;
-
-// row = (r_numvisleafs+7)>>3;
- row = (dvis->numclusters+7)>>3;
- out = decompressed;
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- if (!c)
- Error ("DecompressVis: 0 repeat");
- in += 2;
- if ((out - decompressed) + c > row)
- {
- c = row - (out - decompressed);
- Warning( "warning: Vis decompression overrun\n" );
- }
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-}
-
-//-----------------------------------------------------------------------------
-// Lump-specific swap functions
-//-----------------------------------------------------------------------------
-struct swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int size;
- int vphysicsID;
- short version;
- short modelType;
-};
-
-struct swapcompactsurfaceheader_t : swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int surfaceSize;
- Vector dragAxisAreas;
- int axisMapSize;
-};
-
-struct swapmoppsurfaceheader_t : swapcollideheader_t
-{
- DECLARE_BYTESWAP_DATADESC();
- int moppSize;
-};
-
-BEGIN_BYTESWAP_DATADESC( swapcollideheader_t )
- DEFINE_FIELD( size, FIELD_INTEGER ),
- DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
- DEFINE_FIELD( version, FIELD_SHORT ),
- DEFINE_FIELD( modelType, FIELD_SHORT ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC_( swapcompactsurfaceheader_t, swapcollideheader_t )
- DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
- DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
- DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-BEGIN_BYTESWAP_DATADESC_( swapmoppsurfaceheader_t, swapcollideheader_t )
- DEFINE_FIELD( moppSize, FIELD_INTEGER ),
-END_BYTESWAP_DATADESC()
-
-
-static void SwapPhyscollideLump( byte *pDestBase, byte *pSrcBase, unsigned int &count )
-{
- IPhysicsCollision *physcollision = NULL;
- CSysModule *pPhysicsModule = g_pFullFileSystem->LoadModule( "vphysics.dll" );
- if ( pPhysicsModule )
- {
- CreateInterfaceFn physicsFactory = Sys_GetFactory( pPhysicsModule );
- if ( physicsFactory )
- {
- physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
- }
- }
-
- if ( !physcollision )
- {
- Warning("!!! WARNING: Can't swap the physcollide lump!\n" );
- return;
- }
-
- // physics data is variable length. The last physmodel is a NULL pointer
- // with modelIndex -1, dataSize -1
- dphysmodel_t *pPhysModel;
- byte *pSrc = pSrcBase;
-
- // first the src chunks have to be aligned properly
- // swap increases size, allocate enough expansion room
- byte *pSrcAlignedBase = (byte*)malloc( 2*count );
- byte *basePtr = pSrcAlignedBase;
- byte *pSrcAligned = pSrcAlignedBase;
-
- do
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pSrcAligned, (dphysmodel_t*)pSrc );
- }
- else
- {
- Q_memcpy( pSrcAligned, pSrc, sizeof(dphysmodel_t) );
- }
- pPhysModel = (dphysmodel_t*)pSrcAligned;
-
- pSrc += sizeof(dphysmodel_t);
- pSrcAligned += sizeof(dphysmodel_t);
-
- if ( pPhysModel->dataSize > 0 )
- {
- // Align the collide headers
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- // Get data size
- int size;
- Q_memcpy( &size, pSrc, sizeof(int) );
- if ( g_bSwapOnLoad )
- size = SwapLong( size );
-
- // Fixup size
- int padBytes = 0;
- if ( size % 4 != 0 )
- {
- padBytes = ( 4 - size % 4 );
- count += padBytes;
- pPhysModel->dataSize += padBytes;
- }
-
- // Copy data and size into alligned buffer
- int newsize = size + padBytes;
- if ( g_bSwapOnLoad )
- newsize = SwapLong( newsize );
-
- Q_memcpy( pSrcAligned, &newsize, sizeof(int) );
- Q_memcpy( pSrcAligned + sizeof(int), pSrc + sizeof(int), size );
- pSrcAligned += size + padBytes + sizeof(int);
- pSrc += size + sizeof(int);
- }
-
- int padBytes = 0;
- int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
- Q_memcpy( pSrcAligned, pSrc, pPhysModel->keydataSize );
- pSrc += pPhysModel->keydataSize;
- pSrcAligned += pPhysModel->keydataSize;
- if ( dataSize % 4 != 0 )
- {
- // Next chunk will be unaligned
- padBytes = ( 4 - dataSize % 4 );
- pPhysModel->keydataSize += padBytes;
- count += padBytes;
- Q_memset( pSrcAligned, 0, padBytes );
- pSrcAligned += padBytes;
- }
- }
- } while ( pPhysModel->dataSize > 0 );
-
- // Now the data can be swapped properly
- pSrcBase = pSrcAlignedBase;
- pSrc = pSrcBase;
- byte *pDest = pDestBase;
-
- do
- {
- // src headers are in native format
- pPhysModel = (dphysmodel_t*)pSrc;
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pDest, (dphysmodel_t*)pSrc );
- }
- else
- {
- Q_memcpy( pDest, pSrc, sizeof(dphysmodel_t) );
- }
-
- pSrc += sizeof(dphysmodel_t);
- pDest += sizeof(dphysmodel_t);
-
- pSrcBase = pSrc;
- pDestBase = pDest;
-
- if ( pPhysModel->dataSize > 0 )
- {
- vcollide_t collide = {0};
- int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
-
- if ( g_bSwapOnWrite )
- {
- // Load the collide data
- physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, false );
- }
-
- int *offsets = new int[ pPhysModel->solidCount ];
-
- // Swap the collision data headers
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- int headerSize = 0;
- swapcollideheader_t *baseHdr = (swapcollideheader_t*)pSrc;
- short modelType = baseHdr->modelType;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &modelType );
- }
-
- if ( modelType == 0 ) // COLLIDE_POLY
- {
- headerSize = sizeof(swapcompactsurfaceheader_t);
- swapcompactsurfaceheader_t swapHdr;
- Q_memcpy( &swapHdr, pSrc, headerSize );
- g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
- Q_memcpy( pDest, &swapHdr, headerSize );
- }
- else if ( modelType == 1 ) // COLLIDE_MOPP
- {
- // The PC still unserializes these, but we don't support them
- if ( g_bSwapOnWrite )
- {
- collide.solids[i] = NULL;
- }
-
- headerSize = sizeof(swapmoppsurfaceheader_t);
- swapmoppsurfaceheader_t swapHdr;
- Q_memcpy( &swapHdr, pSrc, headerSize );
- g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
- Q_memcpy( pDest, &swapHdr, headerSize );
-
- }
- else
- {
- // Shouldn't happen
- Assert( 0 );
- }
-
- if ( g_bSwapOnLoad )
- {
- // src needs the native header data to load the vcollides
- Q_memcpy( pSrc, pDest, headerSize );
- }
- // HACK: Need either surfaceSize or moppSize - both sit at the same offset in the structure
- swapmoppsurfaceheader_t *hdr = (swapmoppsurfaceheader_t*)pSrc;
- pSrc += hdr->size + sizeof(int);
- pDest += hdr->size + sizeof(int);
- offsets[i] = hdr->size;
- }
-
- pSrc = pSrcBase;
- pDest = pDestBase;
- if ( g_bSwapOnLoad )
- {
- physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, true );
- }
-
- // Write out the ledge tree data
- for ( int i = 0; i < pPhysModel->solidCount; ++i )
- {
- if ( collide.solids[i] )
- {
- // skip over the size member
- pSrc += sizeof(int);
- pDest += sizeof(int);
- int offset = physcollision->CollideWrite( (char*)pDest, collide.solids[i], g_bSwapOnWrite );
- pSrc += offset;
- pDest += offset;
- }
- else
- {
- pSrc += offsets[i] + sizeof(int);
- pDest += offsets[i] + sizeof(int);
- }
- }
-
- // copy the keyvalues data
- Q_memcpy( pDest, pSrc, pPhysModel->keydataSize );
- pDest += pPhysModel->keydataSize;
- pSrc += pPhysModel->keydataSize;
-
- // Free the memory
- physcollision->VCollideUnload( &collide );
- delete [] offsets;
- }
-
- // avoid infinite loop on badly formed file
- if ( (pSrc - basePtr) > count )
- break;
-
- } while ( pPhysModel->dataSize > 0 );
-
- free( pSrcAlignedBase );
-}
-
-
-// UNDONE: This code is not yet tested.
-static void SwapPhysdispLump( byte *pDest, byte *pSrc, int count )
-{
- // the format of this lump is one unsigned short dispCount, then dispCount unsigned shorts of sizes
- // followed by an array of variable length (each element is the length of the corresponding entry in the
- // previous table) byte-stream data structure of the displacement collision models
- // these byte-stream structs are endian-neutral because each element is byte-sized
- unsigned short dispCount = *(unsigned short*)pSrc;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &dispCount );
- }
- g_Swap.SwapBufferToTargetEndian( (unsigned short*)pDest, (unsigned short*)pSrc, dispCount + 1 );
-
- const int nBytes = (dispCount + 1) * sizeof( unsigned short );
- pSrc += nBytes;
- pDest += nBytes;
- count -= nBytes;
-
- g_Swap.SwapBufferToTargetEndian( pDest, pSrc, count );
-}
-
-
-static void SwapVisibilityLump( byte *pDest, byte *pSrc, int count )
-{
- int firstInt = *(int*)pSrc;
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapBufferToTargetEndian( &firstInt );
- }
- int intCt = firstInt * 2 + 1;
- const int hdrSize = intCt * sizeof(int);
- g_Swap.SwapBufferToTargetEndian( (int*)pDest, (int*)pSrc, intCt );
- g_Swap.SwapBufferToTargetEndian( pDest + hdrSize, pSrc + hdrSize, count - hdrSize );
-}
-
-//=============================================================================
-void Lumps_Init( void )
-{
- memset( &g_Lumps, 0, sizeof(g_Lumps) );
-}
-
-int LumpVersion( int lump )
-{
- return g_pBSPHeader->lumps[lump].version;
-}
-
-bool HasLump( int lump )
-{
- return g_pBSPHeader->lumps[lump].filelen > 0;
-}
-
-void ValidateLump( int lump, int length, int size, int forceVersion )
-{
- if ( length % size )
- {
- Error( "ValidateLump: odd size for lump %d", lump );
- }
-
- if ( forceVersion >= 0 && forceVersion != g_pBSPHeader->lumps[lump].version )
- {
- Error( "ValidateLump: old version for lump %d in map!", lump );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Add Lumps of integral types without datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-int CopyLumpInternal( int fieldType, int lump, T *dest, int forceVersion )
-{
- g_Lumps.bLumpParsed[lump] = true;
-
- // Vectors are passed in as floats
- int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
- unsigned int length = g_pBSPHeader->lumps[lump].filelen;
- unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
-
- // count must be of the integral type
- unsigned int count = length / sizeof(T);
-
- ValidateLump( lump, length, fieldSize, forceVersion );
-
- if ( g_bSwapOnLoad )
- {
- switch( lump )
- {
- case LUMP_VISIBILITY:
- SwapVisibilityLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- break;
-
- case LUMP_PHYSCOLLIDE:
- // SwapPhyscollideLump may change size
- SwapPhyscollideLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- length = count;
- break;
-
- case LUMP_PHYSDISP:
- SwapPhysdispLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
- break;
-
- default:
- g_Swap.SwapBufferToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
- break;
- }
- }
- else
- {
- memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
- }
-
- // Return actual count of elements
- return length / fieldSize;
-}
-
-template< class T >
-int CopyLump( int fieldType, int lump, T *dest, int forceVersion = -1 )
-{
- return CopyLumpInternal( fieldType, lump, dest, forceVersion );
-}
-
-template< class T >
-void CopyLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- Assert( fieldType != FIELD_VECTOR ); // TODO: Support this if necessary
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-void CopyOptionalLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- // not fatal if not present
- if ( !HasLump( lump ) )
- return;
-
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-int CopyVariableLump( int fieldType, int lump, void **dest, int forceVersion = -1 )
-{
- int length = g_pBSPHeader->lumps[lump].filelen;
- *dest = malloc( length );
-
- return CopyLumpInternal<T>( fieldType, lump, (T*)*dest, forceVersion );
-}
-
-//-----------------------------------------------------------------------------
-// Add Lumps of object types with datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-int CopyLumpInternal( int lump, T *dest, int forceVersion )
-{
- g_Lumps.bLumpParsed[lump] = true;
-
- unsigned int length = g_pBSPHeader->lumps[lump].filelen;
- unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
- unsigned int count = length / sizeof(T);
-
- ValidateLump( lump, length, sizeof(T), forceVersion );
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
- }
- else
- {
- memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
- }
-
- return count;
-}
-
-template< class T >
-int CopyLump( int lump, T *dest, int forceVersion = -1 )
-{
- return CopyLumpInternal( lump, dest, forceVersion );
-}
-
-template< class T >
-void CopyLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-void CopyOptionalLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
-{
- // not fatal if not present
- if ( !HasLump( lump ) )
- return;
-
- dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
- CopyLumpInternal( lump, dest.Base(), forceVersion );
-}
-
-template< class T >
-int CopyVariableLump( int lump, void **dest, int forceVersion = -1 )
-{
- int length = g_pBSPHeader->lumps[lump].filelen;
- *dest = malloc( length );
-
- return CopyLumpInternal<T>( lump, (T*)*dest, forceVersion );
-}
-
-//-----------------------------------------------------------------------------
-// Add/Write unknown lumps
-//-----------------------------------------------------------------------------
-void Lumps_Parse( void )
-{
- int i;
-
- for ( i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( !g_Lumps.bLumpParsed[i] && g_pBSPHeader->lumps[i].filelen )
- {
- g_Lumps.size[i] = CopyVariableLump<byte>( FIELD_CHARACTER, i, &g_Lumps.pLumps[i], -1 );
- Msg( "Reading unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
- }
- }
-}
-
-void Lumps_Write( void )
-{
- int i;
-
- for ( i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( g_Lumps.size[i] )
- {
- Msg( "Writing unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
- AddLump( i, (byte*)g_Lumps.pLumps[i], g_Lumps.size[i] );
- }
- if ( g_Lumps.pLumps[i] )
- {
- free( g_Lumps.pLumps[i] );
- g_Lumps.pLumps[i] = NULL;
- }
- }
-}
-
-int LoadLeafs( void )
-{
-#if defined( BSP_USE_LESS_MEMORY )
- dleafs = (dleaf_t*)malloc( g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
-#endif
-
- switch ( LumpVersion( LUMP_LEAFS ) )
- {
- case 0:
- {
- g_Lumps.bLumpParsed[LUMP_LEAFS] = true;
- int length = g_pBSPHeader->lumps[LUMP_LEAFS].filelen;
- int size = sizeof( dleaf_version_0_t );
- if ( length % size )
- {
- Error( "odd size for LUMP_LEAFS\n" );
- }
- int count = length / size;
-
- void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAFS].fileofs );
- dleaf_version_0_t *pSrc = (dleaf_version_0_t *)pSrcBase;
- dleaf_t *pDst = dleafs;
-
- // version 0 predates HDR, build the LDR
- g_LeafAmbientLightingLDR.SetCount( count );
- g_LeafAmbientIndexLDR.SetCount( count );
-
- dleafambientlighting_t *pDstLeafAmbientLighting = &g_LeafAmbientLightingLDR[0];
- for ( int i = 0; i < count; i++ )
- {
- g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( pSrc );
- }
- // pDst is a subset of pSrc;
- *pDst = *( ( dleaf_t * )( void * )pSrc );
- pDstLeafAmbientLighting->cube = pSrc->m_AmbientLighting;
- pDstLeafAmbientLighting->x = pDstLeafAmbientLighting->y = pDstLeafAmbientLighting->z = pDstLeafAmbientLighting->pad = 0;
- pDst++;
- pSrc++;
- pDstLeafAmbientLighting++;
- }
- return count;
- }
-
- case 1:
- return CopyLump( LUMP_LEAFS, dleafs );
-
- default:
- Assert( 0 );
- Error( "Unknown LUMP_LEAFS version\n" );
- return 0;
- }
-}
-
-void LoadLeafAmbientLighting( int numLeafs )
-{
- if ( LumpVersion( LUMP_LEAFS ) == 0 )
- {
- // an older leaf version already built the LDR ambient lighting on load
- return;
- }
-
- // old BSP with ambient, or new BSP with no lighting, convert ambient light to new format or create dummy ambient
- if ( !HasLump( LUMP_LEAF_AMBIENT_INDEX ) )
- {
- // a bunch of legacy maps, have these lumps with garbage versions
- // expect them to be NOT the current version
- if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING) )
- {
- Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- }
- if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING_HDR) )
- {
- Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- }
-
- void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].fileofs );
- CompressedLightCube *pSrc = NULL;
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING ) )
- {
- pSrc = (CompressedLightCube*)pSrcBase;
- }
- g_LeafAmbientIndexLDR.SetCount( numLeafs );
- g_LeafAmbientLightingLDR.SetCount( numLeafs );
-
- void *pSrcBaseHDR = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].fileofs );
- CompressedLightCube *pSrcHDR = NULL;
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
- {
- pSrcHDR = (CompressedLightCube*)pSrcBaseHDR;
- }
- g_LeafAmbientIndexHDR.SetCount( numLeafs );
- g_LeafAmbientLightingHDR.SetCount( numLeafs );
-
- for ( int i = 0; i < numLeafs; i++ )
- {
- g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
- g_LeafAmbientIndexHDR[i].ambientSampleCount = 1;
- g_LeafAmbientIndexHDR[i].firstAmbientSample = i;
-
- Q_memset( &g_LeafAmbientLightingLDR[i], 0, sizeof(g_LeafAmbientLightingLDR[i]) );
- Q_memset( &g_LeafAmbientLightingHDR[i], 0, sizeof(g_LeafAmbientLightingHDR[i]) );
-
- if ( pSrc )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pSrc[i] );
- }
- g_LeafAmbientLightingLDR[i].cube = pSrc[i];
- }
- if ( pSrcHDR )
- {
- if ( g_bSwapOnLoad )
- {
- g_Swap.SwapFieldsToTargetEndian( &pSrcHDR[i] );
- }
- g_LeafAmbientLightingHDR[i].cube = pSrcHDR[i];
- }
- }
-
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
- }
- else
- {
- CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR );
- CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
- }
-}
-
-void ValidateHeader( const char *filename, const dheader_t *pHeader )
-{
- if ( pHeader->ident != IDBSPHEADER )
- {
- Error ("%s is not a IBSP file", filename);
- }
- if ( pHeader->version < MINBSPVERSION || pHeader->version > BSPVERSION )
- {
- Error ("%s is version %i, not %i", filename, pHeader->version, BSPVERSION);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Low level BSP opener for external parsing. Parses headers, but nothing else.
-// You must close the BSP, via CloseBSPFile().
-//-----------------------------------------------------------------------------
-void OpenBSPFile( const char *filename )
-{
- Lumps_Init();
-
- // load the file header
- LoadFile( filename, (void **)&g_pBSPHeader );
-
- if ( g_bSwapOnLoad )
- {
- g_Swap.ActivateByteSwapping( true );
- g_Swap.SwapFieldsToTargetEndian( g_pBSPHeader );
- }
-
- ValidateHeader( filename, g_pBSPHeader );
-
- g_MapRevision = g_pBSPHeader->mapRevision;
-}
-
-//-----------------------------------------------------------------------------
-// CloseBSPFile
-//-----------------------------------------------------------------------------
-void CloseBSPFile( void )
-{
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// LoadBSPFile
-//-----------------------------------------------------------------------------
-void LoadBSPFile( const char *filename )
-{
- OpenBSPFile( filename );
-
- nummodels = CopyLump( LUMP_MODELS, dmodels );
- numvertexes = CopyLump( LUMP_VERTEXES, dvertexes );
- numplanes = CopyLump( LUMP_PLANES, dplanes );
- numleafs = LoadLeafs();
- numnodes = CopyLump( LUMP_NODES, dnodes );
- CopyLump( LUMP_TEXINFO, texinfo );
- numtexdata = CopyLump( LUMP_TEXDATA, dtexdata );
-
- CopyLump( LUMP_DISPINFO, g_dispinfo );
- CopyLump( LUMP_DISP_VERTS, g_DispVerts );
- CopyLump( LUMP_DISP_TRIS, g_DispTris );
- CopyLump( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
- CopyLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
-
- numfaces = CopyLump(LUMP_FACES, dfaces, LUMP_FACES_VERSION);
- if ( HasLump( LUMP_FACES_HDR ) )
- numfaces_hdr = CopyLump( LUMP_FACES_HDR, dfaces_hdr, LUMP_FACES_VERSION );
- else
- numfaces_hdr = 0;
-
- CopyOptionalLump( LUMP_FACEIDS, dfaceids );
-
- g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives );
- g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts );
- g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices );
- numorigfaces = CopyLump( LUMP_ORIGINALFACES, dorigfaces ); // original faces
- numleaffaces = CopyLump( FIELD_SHORT, LUMP_LEAFFACES, dleaffaces );
- numleafbrushes = CopyLump( FIELD_SHORT, LUMP_LEAFBRUSHES, dleafbrushes );
- numsurfedges = CopyLump( FIELD_INTEGER, LUMP_SURFEDGES, dsurfedges );
- numedges = CopyLump( LUMP_EDGES, dedges );
- numbrushes = CopyLump( LUMP_BRUSHES, dbrushes );
- numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides );
- numareas = CopyLump( LUMP_AREAS, dareas );
- numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals );
-
- visdatasize = CopyLump ( FIELD_CHARACTER, LUMP_VISIBILITY, dvisdata );
- CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
- CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
-
- LoadLeafAmbientLighting( numleafs );
-
- CopyLump( FIELD_CHARACTER, LUMP_ENTITIES, dentdata );
- numworldlightsLDR = CopyLump( LUMP_WORLDLIGHTS, dworldlightsLDR );
- numworldlightsHDR = CopyLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR );
-
- numleafwaterdata = CopyLump( LUMP_LEAFWATERDATA, dleafwaterdata );
- g_PhysCollideSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide );
- g_PhysDispSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSDISP, (void**)&g_pPhysDisp );
-
- g_numvertnormals = CopyLump( FIELD_VECTOR, LUMP_VERTNORMALS, (float*)g_vertnormals );
- g_numvertnormalindices = CopyLump( FIELD_SHORT, LUMP_VERTNORMALINDICES, g_vertnormalindices );
-
- g_nClipPortalVerts = CopyLump( FIELD_VECTOR, LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts );
- g_nCubemapSamples = CopyLump( LUMP_CUBEMAPS, g_CubemapSamples );
-
- CopyLump( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
- CopyLump( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
-
- g_nOverlayCount = CopyLump( LUMP_OVERLAYS, g_Overlays );
- g_nWaterOverlayCount = CopyLump( LUMP_WATEROVERLAYS, g_WaterOverlays );
- CopyLump( LUMP_OVERLAY_FADES, g_OverlayFades );
-
- dflagslump_t flags_lump;
-
- if ( HasLump( LUMP_MAP_FLAGS ) )
- CopyLump ( LUMP_MAP_FLAGS, &flags_lump );
- else
- memset( &flags_lump, 0, sizeof( flags_lump ) ); // default flags to 0
-
- g_LevelFlags = flags_lump.m_LevelFlags;
-
- LoadOcclusionLump();
-
- CopyLump( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater );
-
- /*
- int crap;
- for( crap = 0; crap < g_nBSPStringTable; crap++ )
- {
- Msg( "stringtable %d", ( int )crap );
- Msg( " %d:", ( int )g_BSPStringTable[crap] );
- puts( &g_BSPStringData[g_BSPStringTable[crap]] );
- puts( "\n" );
- }
- */
-
- // Load PAK file lump into appropriate data structure
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
- }
- else
- {
- GetPakFile()->Reset();
- }
-
- free( pakbuffer );
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
-
- // NOTE: Do NOT call CopyLump after Lumps_Parse() it parses all un-Copied lumps
- // parse any additional lumps
- Lumps_Parse();
-
- // everything has been copied out
- CloseBSPFile();
-
- g_Swap.ActivateByteSwapping( false );
-}
-
-//-----------------------------------------------------------------------------
-// Reset any state.
-//-----------------------------------------------------------------------------
-void UnloadBSPFile()
-{
- nummodels = 0;
- numvertexes = 0;
- numplanes = 0;
-
- numleafs = 0;
-#if defined( BSP_USE_LESS_MEMORY )
- if ( dleafs )
- {
- free( dleafs );
- dleafs = NULL;
- }
-#endif
-
- numnodes = 0;
- texinfo.Purge();
- numtexdata = 0;
-
- g_dispinfo.Purge();
- g_DispVerts.Purge();
- g_DispTris.Purge();
-
- g_DispLightmapSamplePositions.Purge();
- g_FaceMacroTextureInfos.Purge();
-
- numfaces = 0;
- numfaces_hdr = 0;
-
- dfaceids.Purge();
-
- g_numprimitives = 0;
- g_numprimverts = 0;
- g_numprimindices = 0;
- numorigfaces = 0;
- numleaffaces = 0;
- numleafbrushes = 0;
- numsurfedges = 0;
- numedges = 0;
- numbrushes = 0;
- numbrushsides = 0;
- numareas = 0;
- numareaportals = 0;
-
- visdatasize = 0;
- dlightdataLDR.Purge();
- dlightdataHDR.Purge();
-
- g_LeafAmbientLightingLDR.Purge();
- g_LeafAmbientLightingHDR.Purge();
- g_LeafAmbientIndexHDR.Purge();
- g_LeafAmbientIndexLDR.Purge();
-
- dentdata.Purge();
- numworldlightsLDR = 0;
- numworldlightsHDR = 0;
-
- numleafwaterdata = 0;
-
- if ( g_pPhysCollide )
- {
- free( g_pPhysCollide );
- g_pPhysCollide = NULL;
- }
- g_PhysCollideSize = 0;
-
- if ( g_pPhysDisp )
- {
- free( g_pPhysDisp );
- g_pPhysDisp = NULL;
- }
- g_PhysDispSize = 0;
-
- g_numvertnormals = 0;
- g_numvertnormalindices = 0;
-
- g_nClipPortalVerts = 0;
- g_nCubemapSamples = 0;
-
- g_TexDataStringData.Purge();
- g_TexDataStringTable.Purge();
-
- g_nOverlayCount = 0;
- g_nWaterOverlayCount = 0;
-
- g_LevelFlags = 0;
-
- g_OccluderData.Purge();
- g_OccluderPolyData.Purge();
- g_OccluderVertexIndices.Purge();
-
- g_GameLumps.DestroyAllGameLumps();
-
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- if ( g_Lumps.pLumps[i] )
- {
- free( g_Lumps.pLumps[i] );
- g_Lumps.pLumps[i] = NULL;
- }
- }
-
- ReleasePakFileLumps();
-}
-
-//-----------------------------------------------------------------------------
-// LoadBSPFileFilesystemOnly
-//-----------------------------------------------------------------------------
-void LoadBSPFile_FileSystemOnly( const char *filename )
-{
- Lumps_Init();
-
- //
- // load the file header
- //
- LoadFile( filename, (void **)&g_pBSPHeader );
-
- ValidateHeader( filename, g_pBSPHeader );
-
- // Load PAK file lump into appropriate data structure
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer, 1 );
- if ( paksize > 0 )
- {
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
- }
- else
- {
- GetPakFile()->Reset();
- }
-
- free( pakbuffer );
-
- // everything has been copied out
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName )
-{
- Lumps_Init();
-
- //
- // load the file header
- //
- LoadFile( pBSPFileName, (void **)&g_pBSPHeader);
-
- ValidateHeader( pBSPFileName, g_pBSPHeader );
-
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- FILE *fp;
- fp = fopen( pZipFileName, "wb" );
- if( !fp )
- {
- fprintf( stderr, "can't open %s\n", pZipFileName );
- return;
- }
-
- fwrite( pakbuffer, paksize, 1, fp );
- fclose( fp );
- }
- else
- {
- fprintf( stderr, "zip file is zero length!\n" );
- }
-}
-
-/*
-=============
-LoadBSPFileTexinfo
-
-Only loads the texinfo lump, so qdata can scan for textures
-=============
-*/
-void LoadBSPFileTexinfo( const char *filename )
-{
- FILE *f;
- int length, ofs;
-
- g_pBSPHeader = (dheader_t*)malloc( sizeof(dheader_t) );
-
- f = fopen( filename, "rb" );
- fread( g_pBSPHeader, sizeof(dheader_t), 1, f);
-
- ValidateHeader( filename, g_pBSPHeader );
-
- length = g_pBSPHeader->lumps[LUMP_TEXINFO].filelen;
- ofs = g_pBSPHeader->lumps[LUMP_TEXINFO].fileofs;
-
- int nCount = length / sizeof(texinfo_t);
-
- texinfo.Purge();
- texinfo.AddMultipleToTail( nCount );
-
- fseek( f, ofs, SEEK_SET );
- fread( texinfo.Base(), length, 1, f );
- fclose( f );
-
- // everything has been copied out
- free( g_pBSPHeader );
- g_pBSPHeader = NULL;
-}
-
-static void AddLumpInternal( int lumpnum, void *data, int len, int version )
-{
- lump_t *lump;
-
- g_Lumps.size[lumpnum] = 0; // mark it written
-
- lump = &g_pBSPHeader->lumps[lumpnum];
-
- lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
- lump->filelen = len;
- lump->version = version;
- lump->fourCC[0] = ( char )0;
- lump->fourCC[1] = ( char )0;
- lump->fourCC[2] = ( char )0;
- lump->fourCC[3] = ( char )0;
-
- SafeWrite( g_hBSPFile, data, len );
-
- // pad out to the next dword
- AlignFilePosition( g_hBSPFile, 4 );
-}
-
-template< class T >
-static void SwapInPlace( T *pData, int count )
-{
- if ( !pData )
- return;
-
- // use the datadesc to swap the fields in place
- g_Swap.SwapFieldsToTargetEndian<T>( (T*)pData, pData, count );
-}
-
-template< class T >
-static void SwapInPlace( int fieldType, T *pData, int count )
-{
- if ( !pData )
- return;
-
- // swap the data in place
- g_Swap.SwapBufferToTargetEndian<T>( (T*)pData, (T*)pData, count );
-}
-
-//-----------------------------------------------------------------------------
-// Add raw data chunk to file (not a lump)
-//-----------------------------------------------------------------------------
-template< class T >
-static void WriteData( int fieldType, T *pData, int count )
-{
- if ( g_bSwapOnWrite )
- {
- SwapInPlace( fieldType, pData, count );
- }
- SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
-}
-
-template< class T >
-static void WriteData( T *pData, int count )
-{
- if ( g_bSwapOnWrite )
- {
- SwapInPlace( pData, count );
- }
- SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
-}
-
-//-----------------------------------------------------------------------------
-// Add Lump of object types with datadescs
-//-----------------------------------------------------------------------------
-template< class T >
-static void AddLump( int lumpnum, T *pData, int count, int version )
-{
- AddLumpInternal( lumpnum, pData, count * sizeof(T), version );
-}
-
-template< class T >
-static void AddLump( int lumpnum, CUtlVector<T> &data, int version )
-{
- AddLumpInternal( lumpnum, data.Base(), data.Count() * sizeof(T), version );
-}
-
-/*
-=============
-WriteBSPFile
-
-Swaps the bsp file in place, so it should not be referenced again
-=============
-*/
-void WriteBSPFile( const char *filename, char *pUnused )
-{
- if ( texinfo.Count() > MAX_MAP_TEXINFO )
- {
- Error( "Map has too many texinfos (has %d, can have at most %d)\n", texinfo.Count(), MAX_MAP_TEXINFO );
- return;
- }
-
- dheader_t outHeader;
- g_pBSPHeader = &outHeader;
- memset( g_pBSPHeader, 0, sizeof( dheader_t ) );
-
- g_pBSPHeader->ident = IDBSPHEADER;
- g_pBSPHeader->version = BSPVERSION;
- g_pBSPHeader->mapRevision = g_MapRevision;
-
- g_hBSPFile = SafeOpenWrite( filename );
- WriteData( g_pBSPHeader ); // overwritten later
-
- AddLump( LUMP_PLANES, dplanes, numplanes );
- AddLump( LUMP_LEAFS, dleafs, numleafs, LUMP_LEAFS_VERSION );
- AddLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
- AddLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
- AddLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
- AddLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
-
- AddLump( LUMP_VERTEXES, dvertexes, numvertexes );
- AddLump( LUMP_NODES, dnodes, numnodes );
- AddLump( LUMP_TEXINFO, texinfo );
- AddLump( LUMP_TEXDATA, dtexdata, numtexdata );
-
- AddLump( LUMP_DISPINFO, g_dispinfo );
- AddLump( LUMP_DISP_VERTS, g_DispVerts );
- AddLump( LUMP_DISP_TRIS, g_DispTris );
- AddLump( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
- AddLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
-
- AddLump( LUMP_PRIMITIVES, g_primitives, g_numprimitives );
- AddLump( LUMP_PRIMVERTS, g_primverts, g_numprimverts );
- AddLump( LUMP_PRIMINDICES, g_primindices, g_numprimindices );
- AddLump( LUMP_FACES, dfaces, numfaces, LUMP_FACES_VERSION );
- if (numfaces_hdr)
- AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION );
- AddLump ( LUMP_FACEIDS, dfaceids, numfaceids );
-
- AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump
- AddLump( LUMP_BRUSHES, dbrushes, numbrushes );
- AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides );
- AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces );
- AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes );
- AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges );
- AddLump( LUMP_EDGES, dedges, numedges );
- AddLump( LUMP_MODELS, dmodels, nummodels );
- AddLump( LUMP_AREAS, dareas, numareas );
- AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals );
-
- AddLump( LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
- AddLump( LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
- AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
- AddLump( LUMP_ENTITIES, dentdata );
- AddLump( LUMP_WORLDLIGHTS, dworldlightsLDR, numworldlightsLDR );
- AddLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR, numworldlightsHDR );
- AddLump( LUMP_LEAFWATERDATA, dleafwaterdata, numleafwaterdata );
-
- AddOcclusionLump();
-
- dflagslump_t flags_lump;
- flags_lump.m_LevelFlags = g_LevelFlags;
- AddLump( LUMP_MAP_FLAGS, &flags_lump, 1 );
-
- // NOTE: This is just for debugging, so it is disabled in release maps
-#if 0
- // add the vis portals to the BSP for visualization
- AddLump( LUMP_PORTALS, dportals, numportals );
- AddLump( LUMP_CLUSTERS, dclusters, numclusters );
- AddLump( LUMP_PORTALVERTS, dportalverts, numportalverts );
- AddLump( LUMP_CLUSTERPORTALS, dclusterportals, numclusterportals );
-#endif
-
- AddLump( LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts, g_nClipPortalVerts * 3 );
- AddLump( LUMP_CUBEMAPS, g_CubemapSamples, g_nCubemapSamples );
- AddLump( LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
- AddLump( LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
- AddLump( LUMP_OVERLAYS, g_Overlays, g_nOverlayCount );
- AddLump( LUMP_WATEROVERLAYS, g_WaterOverlays, g_nWaterOverlayCount );
- AddLump( LUMP_OVERLAY_FADES, g_OverlayFades, g_nOverlayCount );
-
- if ( g_pPhysCollide )
- {
- AddLump( LUMP_PHYSCOLLIDE, g_pPhysCollide, g_PhysCollideSize );
- }
-
- if ( g_pPhysDisp )
- {
- AddLump ( LUMP_PHYSDISP, g_pPhysDisp, g_PhysDispSize );
- }
-
- AddLump( LUMP_VERTNORMALS, (float*)g_vertnormals, g_numvertnormals * 3 );
- AddLump( LUMP_VERTNORMALINDICES, g_vertnormalindices, g_numvertnormalindices );
-
- AddLump( LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater, numleafs );
-
- AddGameLumps();
-
- // Write pakfile lump to disk
- WritePakFileLump();
-
- // NOTE: Do NOT call AddLump after Lumps_Write() it writes all un-Added lumps
- // write any additional lumps
- Lumps_Write();
-
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
-}
-
-// Generate the next clear lump filename for the bsp file
-bool GenerateNextLumpFileName( const char *bspfilename, char *lumpfilename, int buffsize )
-{
- for (int i = 0; i < MAX_LUMPFILES; i++)
- {
- GenerateLumpFileName( bspfilename, lumpfilename, buffsize, i );
-
- if ( !g_pFileSystem->FileExists( lumpfilename ) )
- return true;
- }
-
- return false;
-}
-
-void WriteLumpToFile( char *filename, int lump )
-{
- if ( !HasLump(lump) )
- return;
-
- char lumppre[MAX_PATH];
- if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
- {
- Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
- return;
- }
-
- // Open the file
- FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
- if ( !lumpfile )
- {
- Error ("Error opening %s! (Check for write enable)\n",filename);
- return;
- }
-
- int ofs = g_pBSPHeader->lumps[lump].fileofs;
- int length = g_pBSPHeader->lumps[lump].filelen;
-
- // Write the header
- lumpfileheader_t lumpHeader;
- lumpHeader.lumpID = lump;
- lumpHeader.lumpVersion = LumpVersion(lump);
- lumpHeader.lumpLength = length;
- lumpHeader.mapRevision = LittleLong( g_MapRevision );
- lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
- SafeWrite (lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
-
- // Write the lump
- SafeWrite (lumpfile, (byte *)g_pBSPHeader + ofs, length);
-}
-
-void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen )
-{
- char lumppre[MAX_PATH];
- if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
- {
- Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
- return;
- }
-
- // Open the file
- FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
- if ( !lumpfile )
- {
- Error ("Error opening %s! (Check for write enable)\n",filename);
- return;
- }
-
- // Write the header
- lumpfileheader_t lumpHeader;
- lumpHeader.lumpID = lump;
- lumpHeader.lumpVersion = nLumpVersion;
- lumpHeader.lumpLength = nBufLen;
- lumpHeader.mapRevision = LittleLong( g_MapRevision );
- lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
- SafeWrite( lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
-
- // Write the lump
- SafeWrite( lumpfile, pBuffer, nBufLen );
-
- g_pFileSystem->Close( lumpfile );
-}
-
-
-//============================================================================
-#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
-#define ENTRYSIZE(a) (sizeof(*(a)))
-
-int ArrayUsage( const char *szItem, int items, int maxitems, int itemsize )
-{
- float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
-
- Msg("%-17.17s %8i/%-8i %8i/%-8i (%4.1f%%) ",
- szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
- if ( percentage > 80.0 )
- Msg( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- Msg( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- Msg( "SIZE OVERFLOW!!!\n" );
- else
- Msg( "\n" );
- return items * itemsize;
-}
-
-int GlobUsage( const char *szItem, int itemstorage, int maxstorage )
-{
- float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
- Msg("%-17.17s [variable] %8i/%-8i (%4.1f%%) ",
- szItem, itemstorage, maxstorage, percentage );
- if ( percentage > 80.0 )
- Msg( "VERY FULL!\n" );
- else if ( percentage > 95.0 )
- Msg( "SIZE DANGER!\n" );
- else if ( percentage > 99.9 )
- Msg( "SIZE OVERFLOW!!!\n" );
- else
- Msg( "\n" );
- return itemstorage;
-}
-
-/*
-=============
-PrintBSPFileSizes
-
-Dumps info about current file
-=============
-*/
-void PrintBSPFileSizes (void)
-{
- int totalmemory = 0;
-
-// if (!num_entities)
-// ParseEntities ();
-
- Msg("\n");
- Msg( "%-17s %16s %16s %9s \n", "Object names", "Objects/Maxobjs", "Memory / Maxmem", "Fullness" );
- Msg( "%-17s %16s %16s %9s \n", "------------", "---------------", "---------------", "--------" );
-
- totalmemory += ArrayUsage( "models", nummodels, ENTRIES(dmodels), ENTRYSIZE(dmodels) );
- totalmemory += ArrayUsage( "brushes", numbrushes, ENTRIES(dbrushes), ENTRYSIZE(dbrushes) );
- totalmemory += ArrayUsage( "brushsides", numbrushsides, ENTRIES(dbrushsides), ENTRYSIZE(dbrushsides) );
- totalmemory += ArrayUsage( "planes", numplanes, ENTRIES(dplanes), ENTRYSIZE(dplanes) );
- totalmemory += ArrayUsage( "vertexes", numvertexes, ENTRIES(dvertexes), ENTRYSIZE(dvertexes) );
- totalmemory += ArrayUsage( "nodes", numnodes, ENTRIES(dnodes), ENTRYSIZE(dnodes) );
- totalmemory += ArrayUsage( "texinfos", texinfo.Count(),MAX_MAP_TEXINFO, sizeof(texinfo_t) );
- totalmemory += ArrayUsage( "texdata", numtexdata, ENTRIES(dtexdata), ENTRYSIZE(dtexdata) );
-
- totalmemory += ArrayUsage( "dispinfos", g_dispinfo.Count(), 0, sizeof( ddispinfo_t ) );
- totalmemory += ArrayUsage( "disp_verts", g_DispVerts.Count(), 0, sizeof( g_DispVerts[0] ) );
- totalmemory += ArrayUsage( "disp_tris", g_DispTris.Count(), 0, sizeof( g_DispTris[0] ) );
- totalmemory += ArrayUsage( "disp_lmsamples",g_DispLightmapSamplePositions.Count(),0,sizeof( g_DispLightmapSamplePositions[0] ) );
-
- totalmemory += ArrayUsage( "faces", numfaces, ENTRIES(dfaces), ENTRYSIZE(dfaces) );
- totalmemory += ArrayUsage( "hdr faces", numfaces_hdr, ENTRIES(dfaces_hdr), ENTRYSIZE(dfaces_hdr) );
- totalmemory += ArrayUsage( "origfaces", numorigfaces, ENTRIES(dorigfaces), ENTRYSIZE(dorigfaces) ); // original faces
- totalmemory += ArrayUsage( "leaves", numleafs, ENTRIES(dleafs), ENTRYSIZE(dleafs) );
- totalmemory += ArrayUsage( "leaffaces", numleaffaces, ENTRIES(dleaffaces), ENTRYSIZE(dleaffaces) );
- totalmemory += ArrayUsage( "leafbrushes", numleafbrushes, ENTRIES(dleafbrushes), ENTRYSIZE(dleafbrushes) );
- totalmemory += ArrayUsage( "areas", numareas, ENTRIES(dareas), ENTRYSIZE(dareas) );
- totalmemory += ArrayUsage( "surfedges", numsurfedges, ENTRIES(dsurfedges), ENTRYSIZE(dsurfedges) );
- totalmemory += ArrayUsage( "edges", numedges, ENTRIES(dedges), ENTRYSIZE(dedges) );
- totalmemory += ArrayUsage( "LDR worldlights", numworldlightsLDR, ENTRIES(dworldlightsLDR), ENTRYSIZE(dworldlightsLDR) );
- totalmemory += ArrayUsage( "HDR worldlights", numworldlightsHDR, ENTRIES(dworldlightsHDR), ENTRYSIZE(dworldlightsHDR) );
-
- totalmemory += ArrayUsage( "leafwaterdata", numleafwaterdata,ENTRIES(dleafwaterdata), ENTRYSIZE(dleafwaterdata) );
- totalmemory += ArrayUsage( "waterstrips", g_numprimitives,ENTRIES(g_primitives), ENTRYSIZE(g_primitives) );
- totalmemory += ArrayUsage( "waterverts", g_numprimverts, ENTRIES(g_primverts), ENTRYSIZE(g_primverts) );
- totalmemory += ArrayUsage( "waterindices", g_numprimindices,ENTRIES(g_primindices),ENTRYSIZE(g_primindices) );
- totalmemory += ArrayUsage( "cubemapsamples", g_nCubemapSamples,ENTRIES(g_CubemapSamples),ENTRYSIZE(g_CubemapSamples) );
- totalmemory += ArrayUsage( "overlays", g_nOverlayCount, ENTRIES(g_Overlays), ENTRYSIZE(g_Overlays) );
-
- totalmemory += GlobUsage( "LDR lightdata", dlightdataLDR.Count(), 0 );
- totalmemory += GlobUsage( "HDR lightdata", dlightdataHDR.Count(), 0 );
- totalmemory += GlobUsage( "visdata", visdatasize, sizeof(dvisdata) );
- totalmemory += GlobUsage( "entdata", dentdata.Count(), 384*1024 ); // goal is <384K
-
- totalmemory += ArrayUsage( "LDR ambient table", g_LeafAmbientIndexLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexLDR[0] ) );
- totalmemory += ArrayUsage( "HDR ambient table", g_LeafAmbientIndexHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexHDR[0] ) );
- totalmemory += ArrayUsage( "LDR leaf ambient lighting", g_LeafAmbientLightingLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingLDR[0] ) );
- totalmemory += ArrayUsage( "HDR leaf ambient lighting", g_LeafAmbientLightingHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingHDR[0] ) );
-
- totalmemory += ArrayUsage( "occluders", g_OccluderData.Count(), 0, sizeof( g_OccluderData[0] ) );
- totalmemory += ArrayUsage( "occluder polygons", g_OccluderPolyData.Count(), 0, sizeof( g_OccluderPolyData[0] ) );
- totalmemory += ArrayUsage( "occluder vert ind",g_OccluderVertexIndices.Count(),0, sizeof( g_OccluderVertexIndices[0] ) );
-
- GameLumpHandle_t h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "detail props", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING_HDR );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "HDR dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
- h = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if (h != g_GameLumps.InvalidGameLump())
- totalmemory += GlobUsage( "static props", 1, g_GameLumps.GameLumpSize(h) );
-
- totalmemory += GlobUsage( "pakfile", GetPakFile()->EstimateSize(), 0 );
- // HACKHACK: Set physics limit at 4MB, in reality this is totally dynamic
- totalmemory += GlobUsage( "physics", g_PhysCollideSize, 4*1024*1024 );
- totalmemory += GlobUsage( "physics terrain", g_PhysDispSize, 1*1024*1024 );
-
- Msg( "\nLevel flags = %x\n", g_LevelFlags );
-
- Msg( "\n" );
-
- int triangleCount = 0;
-
- for ( int i = 0; i < numfaces; i++ )
- {
- // face tris = numedges - 2
- triangleCount += dfaces[i].numedges - 2;
- }
- Msg("Total triangle count: %d\n", triangleCount );
-
- // UNDONE:
- // areaportals, portals, texdata, clusters, worldlights, portalverts
-}
-
-/*
-=============
-PrintBSPPackDirectory
-
-Dumps a list of files stored in the bsp pack.
-=============
-*/
-void PrintBSPPackDirectory( void )
-{
- GetPakFile()->PrintDirectory();
-}
-
-
-//============================================
-
-int num_entities;
-entity_t entities[MAX_MAP_ENTITIES];
-
-void StripTrailing (char *e)
-{
- char *s;
-
- s = e + strlen(e)-1;
- while (s >= e && *s <= 32)
- {
- *s = 0;
- s--;
- }
-}
-
-/*
-=================
-ParseEpair
-=================
-*/
-epair_t *ParseEpair (void)
-{
- epair_t *e;
-
- e = (epair_t*)malloc (sizeof(epair_t));
- memset (e, 0, sizeof(epair_t));
-
- if (strlen(token) >= MAX_KEY-1)
- Error ("ParseEpar: token too long");
- e->key = copystring(token);
-
- GetToken (false);
- if (strlen(token) >= MAX_VALUE-1)
- Error ("ParseEpar: token too long");
- e->value = copystring(token);
-
- // strip trailing spaces
- StripTrailing (e->key);
- StripTrailing (e->value);
-
- return e;
-}
-
-
-/*
-================
-ParseEntity
-================
-*/
-qboolean ParseEntity (void)
-{
- epair_t *e;
- entity_t *mapent;
-
- if (!GetToken (true))
- return false;
-
- if (Q_stricmp (token, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- mapent = &entities[num_entities];
- num_entities++;
-
- do
- {
- if (!GetToken (true))
- Error ("ParseEntity: EOF without closing brace");
- if (!Q_stricmp (token, "}") )
- break;
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- } while (1);
-
- return true;
-}
-
-/*
-================
-ParseEntities
-
-Parses the dentdata string into entities
-================
-*/
-void ParseEntities (void)
-{
- num_entities = 0;
- ParseFromMemory (dentdata.Base(), dentdata.Count());
-
- while (ParseEntity ())
- {
- }
-}
-
-
-/*
-================
-UnparseEntities
-
-Generates the dentdata string from all the entities
-================
-*/
-void UnparseEntities (void)
-{
- epair_t *ep;
- char line[2048];
- int i;
- char key[1024], value[1024];
-
- CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
- buffer.EnsureCapacity( 256 * 1024 );
-
- for (i=0 ; i<num_entities ; i++)
- {
- ep = entities[i].epairs;
- if (!ep)
- continue; // ent got removed
-
- buffer.PutString( "{\n" );
-
- for (ep = entities[i].epairs ; ep ; ep=ep->next)
- {
- strcpy (key, ep->key);
- StripTrailing (key);
- strcpy (value, ep->value);
- StripTrailing (value);
-
- sprintf(line, "\"%s\" \"%s\"\n", key, value);
- buffer.PutString( line );
- }
- buffer.PutString("}\n");
- }
- int entdatasize = buffer.TellPut()+1;
-
- dentdata.SetSize( entdatasize );
- memcpy( dentdata.Base(), buffer.Base(), entdatasize-1 );
- dentdata[entdatasize-1] = 0;
-}
-
-void PrintEntity (entity_t *ent)
-{
- epair_t *ep;
-
- Msg ("------- entity %p -------\n", ent);
- for (ep=ent->epairs ; ep ; ep=ep->next)
- {
- Msg ("%s = %s\n", ep->key, ep->value);
- }
-
-}
-
-void SetKeyValue(entity_t *ent, const char *key, const char *value)
-{
- epair_t *ep;
-
- for (ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- {
- free (ep->value);
- ep->value = copystring(value);
- return;
- }
- ep = (epair_t*)malloc (sizeof(*ep));
- ep->next = ent->epairs;
- ent->epairs = ep;
- ep->key = copystring(key);
- ep->value = copystring(value);
-}
-
-char *ValueForKey (entity_t *ent, char *key)
-{
- for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- return ep->value;
- return "";
-}
-
-vec_t FloatForKey (entity_t *ent, char *key)
-{
- char *k = ValueForKey (ent, key);
- return atof(k);
-}
-
-vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value)
-{
- for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
- if (!Q_stricmp (ep->key, key) )
- return atof( ep->value );
- return default_value;
-}
-
-
-
-int IntForKey (entity_t *ent, char *key)
-{
- char *k = ValueForKey (ent, key);
- return atol(k);
-}
-
-int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault )
-{
- char *k = ValueForKey (ent, key);
- if ( !k[0] )
- return nDefault;
- return atol(k);
-}
-
-void GetVectorForKey (entity_t *ent, char *key, Vector& vec)
-{
-
- char *k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- double v1, v2, v3;
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- vec[0] = v1;
- vec[1] = v2;
- vec[2] = v3;
-}
-
-void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec)
-{
- double v1, v2;
-
- char *k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = 0;
- sscanf (k, "%lf %lf", &v1, &v2);
- vec[0] = v1;
- vec[1] = v2;
-}
-
-void GetAnglesForKey (entity_t *ent, char *key, QAngle& angle)
-{
- char *k;
- double v1, v2, v3;
-
- k = ValueForKey (ent, key);
-// scanf into doubles, then assign, so it is vec_t size independent
- v1 = v2 = v3 = 0;
- sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
- angle[0] = v1;
- angle[1] = v2;
- angle[2] = v3;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void BuildFaceCalcWindingData( dface_t *pFace, int *points )
-{
- for( int i = 0; i < pFace->numedges; i++ )
- {
- int eIndex = dsurfedges[pFace->firstedge+i];
- if( eIndex < 0 )
- {
- points[i] = dedges[-eIndex].v[1];
- }
- else
- {
- points[i] = dedges[eIndex].v[0];
- }
- }
-}
-
-
-void TriStripToTriList(
- unsigned short const *pTriStripIndices,
- int nTriStripIndices,
- unsigned short **pTriListIndices,
- int *pnTriListIndices )
-{
- int nMaxTriListIndices = (nTriStripIndices - 2) * 3;
- *pTriListIndices = new unsigned short[ nMaxTriListIndices ];
- *pnTriListIndices = 0;
-
- for( int i=0; i < nTriStripIndices - 2; i++ )
- {
- if( pTriStripIndices[i] == pTriStripIndices[i+1] ||
- pTriStripIndices[i] == pTriStripIndices[i+2] ||
- pTriStripIndices[i+1] == pTriStripIndices[i+2] )
- {
- }
- else
- {
- // Flip odd numbered tris..
- if( i & 1 )
- {
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
- }
- else
- {
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
- (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
- }
- }
- }
-}
-
-
-void CalcTextureCoordsAtPoints(
- float const texelsPerWorldUnits[2][4],
- int const subtractOffset[2],
- Vector const *pPoints,
- int const nPoints,
- Vector2D *pCoords )
-{
- for( int i=0; i < nPoints; i++ )
- {
- for( int iCoord=0; iCoord < 2; iCoord++ )
- {
- float *pDestCoord = &pCoords[i][iCoord];
-
- *pDestCoord = 0;
- for( int iDot=0; iDot < 3; iDot++ )
- *pDestCoord += pPoints[i][iDot] * texelsPerWorldUnits[iCoord][iDot];
-
- *pDestCoord += texelsPerWorldUnits[iCoord][3];
- *pDestCoord -= subtractOffset[iCoord];
- }
- }
-}
-
-
-/*
-================
-CalcFaceExtents
-
-Fills in s->texmins[] and s->texsize[]
-================
-*/
-void CalcFaceExtents(dface_t *s, int lightmapTextureMinsInLuxels[2], int lightmapTextureSizeInLuxels[2])
-{
- vec_t mins[2], maxs[2], val=0;
- int i,j, e=0;
- dvertex_t *v=NULL;
- texinfo_t *tex=NULL;
-
- mins[0] = mins[1] = 1e24;
- maxs[0] = maxs[1] = -1e24;
-
- tex = &texinfo[s->texinfo];
-
- for (i=0 ; i<s->numedges ; i++)
- {
- e = dsurfedges[s->firstedge+i];
- if (e >= 0)
- v = dvertexes + dedges[e].v[0];
- else
- v = dvertexes + dedges[-e].v[1];
-
- for (j=0 ; j<2 ; j++)
- {
- val = v->point[0] * tex->lightmapVecsLuxelsPerWorldUnits[j][0] +
- v->point[1] * tex->lightmapVecsLuxelsPerWorldUnits[j][1] +
- v->point[2] * tex->lightmapVecsLuxelsPerWorldUnits[j][2] +
- tex->lightmapVecsLuxelsPerWorldUnits[j][3];
- if (val < mins[j])
- mins[j] = val;
- if (val > maxs[j])
- maxs[j] = val;
- }
- }
-
- int nMaxLightmapDim = (s->dispinfo == -1) ? MAX_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER;
- for (i=0 ; i<2 ; i++)
- {
- mins[i] = ( float )floor( mins[i] );
- maxs[i] = ( float )ceil( maxs[i] );
-
- lightmapTextureMinsInLuxels[i] = ( int )mins[i];
- lightmapTextureSizeInLuxels[i] = ( int )( maxs[i] - mins[i] );
- if( lightmapTextureSizeInLuxels[i] > nMaxLightmapDim + 1 )
- {
- Vector point = vec3_origin;
- for (int j=0 ; j<s->numedges ; j++)
- {
- e = dsurfedges[s->firstedge+j];
- v = (e<0)?dvertexes + dedges[-e].v[1] : dvertexes + dedges[e].v[0];
- point += v->point;
- Warning( "Bad surface extents point: %f %f %f\n", v->point.x, v->point.y, v->point.z );
- }
- point *= 1.0f/s->numedges;
- 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",
- TexDataStringTable_GetString( dtexdata[texinfo[s->texinfo].texdata].nameStringTableID ),
- point.x, point.y, point.z,
- ( int )i,
- ( int )lightmapTextureSizeInLuxels[i],
- ( int )( nMaxLightmapDim + 1 )
- );
- }
- }
-}
-
-
-void UpdateAllFaceLightmapExtents()
-{
- for( int i=0; i < numfaces; i++ )
- {
- dface_t *pFace = &dfaces[i];
-
- if ( texinfo[pFace->texinfo].flags & (SURF_SKY|SURF_NOLIGHT) )
- continue; // non-lit texture
-
- CalcFaceExtents( pFace, pFace->m_LightmapTextureMinsInLuxels, pFace->m_LightmapTextureSizeInLuxels );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//
-// Helper class to iterate over leaves, used by tools
-//
-//-----------------------------------------------------------------------------
-
-#define TEST_EPSILON (0.03125)
-
-
-class CToolBSPTree : public ISpatialQuery
-{
-public:
- // Returns the number of leaves
- int LeafCount() const;
-
- // Enumerates the leaves along a ray, box, etc.
- bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
- bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
-};
-
-
-//-----------------------------------------------------------------------------
-// Returns the number of leaves
-//-----------------------------------------------------------------------------
-
-int CToolBSPTree::LeafCount() const
-{
- return numleafs;
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerates the leaves at a point
-//-----------------------------------------------------------------------------
-
-bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt,
- ISpatialLeafEnumerator* pEnum, int context )
-{
- int node = 0;
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if (DotProduct( pPlane->normal, pt ) <= pPlane->dist)
- {
- node = pNode->children[1];
- }
- else
- {
- node = pNode->children[0];
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerates the leaves in a box
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesInBox_R( int node, Vector const& mins,
- Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
-{
- Vector cornermin, cornermax;
-
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- // Arbitrary split plane here
- for (int i = 0; i < 3; ++i)
- {
- if (pPlane->normal[i] >= 0)
- {
- cornermin[i] = mins[i];
- cornermax[i] = maxs[i];
- }
- else
- {
- cornermin[i] = maxs[i];
- cornermax[i] = mins[i];
- }
- }
-
- if ( (DotProduct( pPlane->normal, cornermax ) - pPlane->dist) <= -TEST_EPSILON )
- {
- node = pNode->children[1];
- }
- else if ( (DotProduct( pPlane->normal, cornermin ) - pPlane->dist) >= TEST_EPSILON )
- {
- node = pNode->children[0];
- }
- else
- {
- if (!EnumerateLeavesInBox_R( pNode->children[0], mins, maxs, pEnum, context ))
- {
- return false;
- }
-
- return EnumerateLeavesInBox_R( pNode->children[1], mins, maxs, pEnum, context );
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs,
- ISpatialLeafEnumerator* pEnum, int context )
-{
- return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
-}
-
-//-----------------------------------------------------------------------------
-// Enumerate leaves within a sphere
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesInSphere_R( int node, Vector const& origin,
- float radius, ISpatialLeafEnumerator* pEnum, int context )
-{
- while( node >= 0 )
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if (DotProduct( pPlane->normal, origin ) + radius - pPlane->dist <= -TEST_EPSILON )
- {
- node = pNode->children[1];
- }
- else if (DotProduct( pPlane->normal, origin ) - radius - pPlane->dist >= TEST_EPSILON )
- {
- node = pNode->children[0];
- }
- else
- {
- if (!EnumerateLeavesInSphere_R( pNode->children[0],
- origin, radius, pEnum, context ))
- {
- return false;
- }
-
- return EnumerateLeavesInSphere_R( pNode->children[1],
- origin, radius, pEnum, context );
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
-{
- return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Enumerate leaves along a ray
-//-----------------------------------------------------------------------------
-
-static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray,
- Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context )
-{
- float front,back;
-
- while (node >= 0)
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if ( pPlane->type <= PLANE_Z )
- {
- front = start[pPlane->type] - pPlane->dist;
- back = end[pPlane->type] - pPlane->dist;
- }
- else
- {
- front = DotProduct(start, pPlane->normal) - pPlane->dist;
- back = DotProduct(end, pPlane->normal) - pPlane->dist;
- }
-
- if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
- {
- node = pNode->children[1];
- }
- else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
- {
- node = pNode->children[0];
- }
- else
- {
- // test the front side first
- bool side = front < 0;
-
- // Compute intersection point based on the original ray
- float splitfrac;
- float denom = DotProduct( ray.m_Delta, pPlane->normal );
- if ( denom == 0.0f )
- {
- splitfrac = 1.0f;
- }
- else
- {
- splitfrac = ( pPlane->dist - DotProduct( ray.m_Start, pPlane->normal ) ) / denom;
- if (splitfrac < 0)
- splitfrac = 0;
- else if (splitfrac > 1)
- splitfrac = 1;
- }
-
- // Compute the split point
- Vector split;
- VectorMA( ray.m_Start, splitfrac, ray.m_Delta, split );
-
- bool r = EnumerateLeavesAlongRay_R (pNode->children[side], ray, start, split, pEnum, context );
- if (!r)
- return r;
- return EnumerateLeavesAlongRay_R (pNode->children[!side], ray, split, end, pEnum, context);
- }
- }
-
- return pEnum->EnumerateLeaf( - node - 1, context );
-}
-
-bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
-{
- if (!ray.m_IsSwept)
- {
- Vector mins, maxs;
- VectorAdd( ray.m_Start, ray.m_Extents, maxs );
- VectorSubtract( ray.m_Start, ray.m_Extents, mins );
-
- return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
- }
-
- // FIXME: Extruded ray not implemented yet
- Assert( ray.m_IsRay );
-
- Vector end;
- VectorAdd( ray.m_Start, ray.m_Delta, end );
- return EnumerateLeavesAlongRay_R( 0, ray, ray.m_Start, end, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Singleton accessor
-//-----------------------------------------------------------------------------
-
-ISpatialQuery* ToolBSPTree()
-{
- static CToolBSPTree s_ToolBSPTree;
- return &s_ToolBSPTree;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Enumerates nodes in front to back order...
-//-----------------------------------------------------------------------------
-
-// FIXME: Do we want this in the IBSPTree interface?
-
-static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end,
- IBSPNodeEnumerator* pEnum, int context )
-{
- float front, back;
- float startDotN, deltaDotN;
-
- while (node >= 0)
- {
- dnode_t* pNode = &dnodes[node];
- dplane_t* pPlane = &dplanes[pNode->planenum];
-
- if ( pPlane->type <= PLANE_Z )
- {
- startDotN = ray.m_Start[pPlane->type];
- deltaDotN = ray.m_Delta[pPlane->type];
- }
- else
- {
- startDotN = DotProduct( ray.m_Start, pPlane->normal );
- deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
- }
-
- front = startDotN + start * deltaDotN - pPlane->dist;
- back = startDotN + end * deltaDotN - pPlane->dist;
-
- if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
- {
- node = pNode->children[1];
- }
- else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
- {
- node = pNode->children[0];
- }
- else
- {
- // test the front side first
- bool side = front < 0;
-
- // Compute intersection point based on the original ray
- float splitfrac;
- if ( deltaDotN == 0.0f )
- {
- splitfrac = 1.0f;
- }
- else
- {
- splitfrac = ( pPlane->dist - startDotN ) / deltaDotN;
- if (splitfrac < 0.0f)
- splitfrac = 0.0f;
- else if (splitfrac > 1.0f)
- splitfrac = 1.0f;
- }
-
- bool r = EnumerateNodesAlongRay_R (pNode->children[side], ray, start, splitfrac, pEnum, context );
- if (!r)
- return r;
-
- // Visit the node...
- if (!pEnum->EnumerateNode( node, ray, splitfrac, context ))
- return false;
-
- return EnumerateNodesAlongRay_R (pNode->children[!side], ray, splitfrac, end, pEnum, context);
- }
- }
-
- // Visit the leaf...
- return pEnum->EnumerateLeaf( - node - 1, ray, start, end, context );
-}
-
-
-bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context )
-{
- Vector end;
- VectorAdd( ray.m_Start, ray.m_Delta, end );
- return EnumerateNodesAlongRay_R( 0, ray, 0.0f, 1.0f, pEnum, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Helps us find all leaves associated with a particular cluster
-//-----------------------------------------------------------------------------
-CUtlVector<clusterlist_t> g_ClusterLeaves;
-
-void BuildClusterTable( void )
-{
- int i, j;
- int leafCount;
- int leafList[MAX_MAP_LEAFS];
-
- g_ClusterLeaves.SetCount( dvis->numclusters );
- for ( i = 0; i < dvis->numclusters; i++ )
- {
- leafCount = 0;
- for ( j = 0; j < numleafs; j++ )
- {
- if ( dleafs[j].cluster == i )
- {
- leafList[ leafCount ] = j;
- leafCount++;
- }
- }
-
- g_ClusterLeaves[i].leafCount = leafCount;
- if ( leafCount )
- {
- g_ClusterLeaves[i].leafs.SetCount( leafCount );
- memcpy( g_ClusterLeaves[i].leafs.Base(), leafList, sizeof(int) * leafCount );
- }
- }
-}
-
-// There's a version of this in host.cpp!!! Make sure that they match.
-void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength )
-{
- Q_StripExtension( pMapPath, pPlatformMapPath, maxLength );
-
-// if( dxlevel <= 60 )
-// {
-// Q_strncat( pPlatformMapPath, "_dx60", maxLength, COPY_ALL_CHARACTERS );
-// }
-
- Q_strncat( pPlatformMapPath, ".bsp", maxLength, COPY_ALL_CHARACTERS );
-}
-
-// There's a version of this in checksum_engine.cpp!!! Make sure that they match.
-static bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
-{
- byte chunk[1024];
- lump_t *curLump;
-
- FileHandle_t fp = g_pFileSystem->Open( pszFileName, "rb" );
- if ( !fp )
- return false;
-
- // CRC across all lumps except for the Entities lump
- for ( int l = 0; l < HEADER_LUMPS; ++l )
- {
- if (l == LUMP_ENTITIES)
- continue;
-
- curLump = &g_pBSPHeader->lumps[l];
- unsigned int nSize = curLump->filelen;
-
- g_pFileSystem->Seek( fp, curLump->fileofs, FILESYSTEM_SEEK_HEAD );
-
- // Now read in 1K chunks
- while ( nSize > 0 )
- {
- int nBytesRead = 0;
-
- if ( nSize > 1024 )
- nBytesRead = g_pFileSystem->Read( chunk, 1024, fp );
- else
- nBytesRead = g_pFileSystem->Read( chunk, nSize, fp );
-
- // If any data was received, CRC it.
- if ( nBytesRead > 0 )
- {
- nSize -= nBytesRead;
- CRC32_ProcessBuffer( crcvalue, chunk, nBytesRead );
- }
- else
- {
- g_pFileSystem->Close( fp );
- return false;
- }
- }
- }
-
- g_pFileSystem->Close( fp );
- return true;
-}
-
-
-void SetHDRMode( bool bHDR )
-{
- g_bHDR = bHDR;
- if ( bHDR )
- {
- pdlightdata = &dlightdataHDR;
- g_pLeafAmbientLighting = &g_LeafAmbientLightingHDR;
- g_pLeafAmbientIndex = &g_LeafAmbientIndexHDR;
- pNumworldlights = &numworldlightsHDR;
- dworldlights = dworldlightsHDR;
-#ifdef VRAD
- extern void VRadDetailProps_SetHDRMode( bool bHDR );
- VRadDetailProps_SetHDRMode( bHDR );
-#endif
- }
- else
- {
- pdlightdata = &dlightdataLDR;
- g_pLeafAmbientLighting = &g_LeafAmbientLightingLDR;
- g_pLeafAmbientIndex = &g_LeafAmbientIndexLDR;
- pNumworldlights = &numworldlightsLDR;
- dworldlights = dworldlightsLDR;
-#ifdef VRAD
- extern void VRadDetailProps_SetHDRMode( bool bHDR );
- VRadDetailProps_SetHDRMode( bHDR );
-#endif
- }
-}
-
-bool SwapVHV( void *pDestBase, void *pSrcBase )
-{
- byte *pDest = (byte*)pDestBase;
- byte *pSrc = (byte*)pSrcBase;
-
- HardwareVerts::FileHeader_t *pHdr = (HardwareVerts::FileHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
- g_Swap.SwapFieldsToTargetEndian<HardwareVerts::FileHeader_t>( (HardwareVerts::FileHeader_t*)pDest, (HardwareVerts::FileHeader_t*)pSrc );
- pSrc += sizeof(HardwareVerts::FileHeader_t);
- pDest += sizeof(HardwareVerts::FileHeader_t);
-
- // This swap is pretty format specific
- Assert( pHdr->m_nVersion == VHV_VERSION );
- if ( pHdr->m_nVersion != VHV_VERSION )
- return false;
-
- HardwareVerts::MeshHeader_t *pSrcMesh = (HardwareVerts::MeshHeader_t*)pSrc;
- HardwareVerts::MeshHeader_t *pDestMesh = (HardwareVerts::MeshHeader_t*)pDest;
- HardwareVerts::MeshHeader_t *pMesh = (HardwareVerts::MeshHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
- for ( int i = 0; i < pHdr->m_nMeshes; ++i, ++pMesh, ++pSrcMesh, ++pDestMesh )
- {
- g_Swap.SwapFieldsToTargetEndian( pDestMesh, pSrcMesh );
-
- pSrc = (byte*)pSrcBase + pMesh->m_nOffset;
- pDest = (byte*)pDestBase + pMesh->m_nOffset;
-
- // Swap as a buffer of integers
- // (source is bgra for an Intel swap to argb. PowerPC won't swap, so we need argb source.
- g_Swap.SwapBufferToTargetEndian<int>( (int*)pDest, (int*)pSrc, pMesh->m_nVertexes );
- }
- return true;
-}
-
-const char *ResolveStaticPropToModel( const char *pPropName )
-{
- // resolve back to static prop
- int iProp = -1;
-
- // filename should be sp_???.vhv or sp_hdr_???.vhv
- if ( V_strnicmp( pPropName, "sp_", 3 ) )
- {
- return NULL;
- }
- const char *pPropNumber = V_strrchr( pPropName, '_' );
- if ( pPropNumber )
- {
- sscanf( pPropNumber+1, "%d.vhv", &iProp );
- }
- else
- {
- return NULL;
- }
-
- // look up the prop to get to the actual model
- if ( iProp < 0 || iProp >= g_StaticPropInstances.Count() )
- {
- // prop out of range
- return NULL;
- }
- int iModel = g_StaticPropInstances[iProp];
- if ( iModel < 0 || iModel >= g_StaticPropNames.Count() )
- {
- // model out of range
- return NULL;
- }
-
- return g_StaticPropNames[iModel].String();
-}
-
-//-----------------------------------------------------------------------------
-// Iterate files in pak file, distribute to converters
-// pak file will be ready for serialization upon completion
-//-----------------------------------------------------------------------------
-void ConvertPakFileContents( const char *pInFilename )
-{
- IZip *newPakFile = IZip::CreateZip( NULL );
-
- CUtlBuffer sourceBuf;
- CUtlBuffer targetBuf;
- bool bConverted;
- CUtlVector< CUtlString > hdrFiles;
-
- int id = -1;
- int fileSize;
- while ( 1 )
- {
- char relativeName[MAX_PATH];
- id = GetNextFilename( GetPakFile(), id, relativeName, sizeof( relativeName ), fileSize );
- if ( id == -1)
- break;
-
- bConverted = false;
- sourceBuf.Purge();
- targetBuf.Purge();
-
- const char* pExtension = V_GetFileExtension( relativeName );
- const char* pExt = 0;
-
- bool bOK = ReadFileFromPak( GetPakFile(), relativeName, false, sourceBuf );
- if ( !bOK )
- {
- Warning( "Failed to load '%s' from lump pak for conversion or copy in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- if ( pExtension && !V_stricmp( pExtension, "vtf" ) )
- {
- bOK = g_pVTFConvertFunc( relativeName, sourceBuf, targetBuf, g_pCompressFunc );
- if ( !bOK )
- {
- Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- bConverted = true;
- pExt = ".vtf";
- }
- else if ( pExtension && !V_stricmp( pExtension, "vhv" ) )
- {
- CUtlBuffer tempBuffer;
- if ( g_pVHVFixupFunc )
- {
- // caller supplied a fixup
- const char *pModelName = ResolveStaticPropToModel( relativeName );
- if ( !pModelName )
- {
- Warning( "Static Prop '%s' failed to resolve actual model in '%s'.\n", relativeName, pInFilename );
- continue;
- }
-
- // output temp buffer may shrink, must use TellPut() to determine size
- bOK = g_pVHVFixupFunc( relativeName, pModelName, sourceBuf, tempBuffer );
- if ( !bOK )
- {
- Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
- }
- else
- {
- // use the source buffer as-is
- tempBuffer.EnsureCapacity( sourceBuf.TellMaxPut() );
- tempBuffer.Put( sourceBuf.Base(), sourceBuf.TellMaxPut() );
- }
-
- // swap the VHV
- targetBuf.EnsureCapacity( tempBuffer.TellPut() );
- bOK = SwapVHV( targetBuf.Base(), tempBuffer.Base() );
- if ( !bOK )
- {
- Warning( "Failed to swap '%s' in '%s'.\n", relativeName, pInFilename );
- continue;
- }
- targetBuf.SeekPut( CUtlBuffer::SEEK_HEAD, tempBuffer.TellPut() );
-
- if ( g_pCompressFunc )
- {
- CUtlBuffer compressedBuffer;
- targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, sizeof( HardwareVerts::FileHeader_t ) );
- bool bCompressed = g_pCompressFunc( targetBuf, compressedBuffer );
- if ( bCompressed )
- {
- // copy all the header data off
- CUtlBuffer headerBuffer;
- headerBuffer.EnsureCapacity( sizeof( HardwareVerts::FileHeader_t ) );
- headerBuffer.Put( targetBuf.Base(), sizeof( HardwareVerts::FileHeader_t ) );
-
- // reform the target with the header and then the compressed data
- targetBuf.Clear();
- targetBuf.Put( headerBuffer.Base(), sizeof( HardwareVerts::FileHeader_t ) );
- targetBuf.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- }
-
- targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
- }
-
- bConverted = true;
- pExt = ".vhv";
- }
-
- if ( !bConverted )
- {
- // straight copy
- AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false );
- }
- else
- {
- // converted filename
- V_StripExtension( relativeName, relativeName, sizeof( relativeName ) );
- V_strcat( relativeName, ".360", sizeof( relativeName ) );
- V_strcat( relativeName, pExt, sizeof( relativeName ) );
- AddBufferToPak( newPakFile, relativeName, targetBuf.Base(), targetBuf.TellMaxPut(), false );
- }
-
- if ( V_stristr( relativeName, ".hdr" ) || V_stristr( relativeName, "_hdr" ) )
- {
- hdrFiles.AddToTail( relativeName );
- }
-
- DevMsg( "Created '%s' in lump pak in '%s'.\n", relativeName, pInFilename );
- }
-
- // strip ldr version of hdr files
- for ( int i=0; i<hdrFiles.Count(); i++ )
- {
- char ldrFileName[MAX_PATH];
-
- strcpy( ldrFileName, hdrFiles[i].String() );
-
- char *pHDRExtension = V_stristr( ldrFileName, ".hdr" );
- if ( !pHDRExtension )
- {
- pHDRExtension = V_stristr( ldrFileName, "_hdr" );
- }
-
- if ( pHDRExtension )
- {
- // strip .hdr or _hdr to get ldr filename
- memcpy( pHDRExtension, pHDRExtension+4, strlen( pHDRExtension+4 )+1 );
-
- DevMsg( "Stripping LDR: %s\n", ldrFileName );
- newPakFile->RemoveFileFromZip( ldrFileName );
- }
- }
-
- // discard old pak in favor of new pak
- IZip::ReleaseZip( s_pakFile );
- s_pakFile = newPakFile;
-}
-
-void SetAlignedLumpPosition( int lumpnum, int alignment = LUMP_ALIGNMENT )
-{
- g_pBSPHeader->lumps[lumpnum].fileofs = AlignFilePosition( g_hBSPFile, alignment );
-}
-
-template< class T >
-int SwapLumpToDisk( int fieldType, int lumpnum )
-{
- if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 )
- return 0;
-
- DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
-
- // lump swap may expand, allocate enough expansion room
- void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
-
- // CopyLumpInternal will handle the swap on load case
- unsigned int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
- unsigned int count = CopyLumpInternal<T>( fieldType, lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
- g_pBSPHeader->lumps[lumpnum].filelen = count * fieldSize;
-
- if ( g_bSwapOnWrite )
- {
- // Swap the lump in place before writing
- switch( lumpnum )
- {
- case LUMP_VISIBILITY:
- SwapVisibilityLump( (byte*)pBuffer, (byte*)pBuffer, count );
- break;
-
- case LUMP_PHYSCOLLIDE:
- // SwapPhyscollideLump may change size
- SwapPhyscollideLump( (byte*)pBuffer, (byte*)pBuffer, count );
- g_pBSPHeader->lumps[lumpnum].filelen = count;
- break;
-
- case LUMP_PHYSDISP:
- SwapPhysdispLump( (byte*)pBuffer, (byte*)pBuffer, count );
- break;
-
- default:
- g_Swap.SwapBufferToTargetEndian( (T*)pBuffer, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].filelen / sizeof(T) );
- break;
- }
- }
-
- SetAlignedLumpPosition( lumpnum );
- SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
-
- free( pBuffer );
-
- return g_pBSPHeader->lumps[lumpnum].filelen;
-}
-
-template< class T >
-int SwapLumpToDisk( int lumpnum )
-{
- if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 || g_Lumps.bLumpParsed[lumpnum] )
- return 0;
-
- DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
-
- // lump swap may expand, allocate enough room
- void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
-
- // CopyLumpInternal will handle the swap on load case
- int count = CopyLumpInternal<T>( lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
- g_pBSPHeader->lumps[lumpnum].filelen = count * sizeof(T);
-
- if ( g_bSwapOnWrite )
- {
- // Swap the lump in place before writing
- g_Swap.SwapFieldsToTargetEndian( (T*)pBuffer, (T*)pBuffer, count );
- }
-
- SetAlignedLumpPosition( lumpnum );
- SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
- free( pBuffer );
-
- return g_pBSPHeader->lumps[lumpnum].filelen;
-}
-
-void SwapLeafAmbientLightingLumpToDisk()
-{
- if ( HasLump( LUMP_LEAF_AMBIENT_INDEX ) || HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
- {
- // current version, swap in place
- if ( HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
- {
- // write HDR
- SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
- SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX_HDR );
-
- // cull LDR
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING );
- SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX );
- }
- }
- else
- {
- // older ambient lighting version (before index)
- // load older ambient lighting into memory and build ambient/index
- // an older leaf version would have already built the new LDR leaf ambient/index
- int numLeafs = g_pBSPHeader->lumps[LUMP_LEAFS].filelen / sizeof( dleaf_t );
- LoadLeafAmbientLighting( numLeafs );
-
- if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
- {
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) );
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX_HDR ) );
-
- // write HDR
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingHDR.Base(), g_LeafAmbientLightingHDR.Count() );
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexHDR.Base(), g_LeafAmbientIndexHDR.Count() );
- }
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen = g_LeafAmbientLightingHDR.Count() * sizeof( dleafambientlighting_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientLightingHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen );
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX_HDR );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen = g_LeafAmbientIndexHDR.Count() * sizeof( dleafambientindex_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientIndexHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen );
-
- // mark as processed
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
-
- // cull LDR
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING ) );
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX ) );
-
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingLDR.Base(), g_LeafAmbientLightingLDR.Count() );
- g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexLDR.Base(), g_LeafAmbientIndexLDR.Count() );
- }
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = g_LeafAmbientLightingLDR.Count() * sizeof( dleafambientlighting_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientLightingLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen );
-
- SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX );
- g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = g_LeafAmbientIndexLDR.Count() * sizeof( dleafambientindex_t );
- SafeWrite( g_hBSPFile, g_LeafAmbientIndexLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen );
-
- // mark as processed
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
- g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
- }
-
- g_LeafAmbientLightingLDR.Purge();
- g_LeafAmbientIndexLDR.Purge();
- g_LeafAmbientLightingHDR.Purge();
- g_LeafAmbientIndexHDR.Purge();
- }
-}
-
-void SwapLeafLumpToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAFS ) );
-
- // load the leafs
- int count = LoadLeafs();
- if ( g_bSwapOnWrite )
- {
- g_Swap.SwapFieldsToTargetEndian( dleafs, count );
- }
-
- bool bOldLeafVersion = ( LumpVersion( LUMP_LEAFS ) == 0 );
- if ( bOldLeafVersion )
- {
- // version has been converted in the load process
- // not updating the version ye, SwapLeafAmbientLightingLumpToDisk() can detect
- g_pBSPHeader->lumps[LUMP_LEAFS].filelen = count * sizeof( dleaf_t );
- }
-
- SetAlignedLumpPosition( LUMP_LEAFS );
- SafeWrite( g_hBSPFile, dleafs, g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
-
- SwapLeafAmbientLightingLumpToDisk();
-
- if ( bOldLeafVersion )
- {
- // version has been converted in the load process
- // can now safely change
- g_pBSPHeader->lumps[LUMP_LEAFS].version = 1;
- }
-
-#if defined( BSP_USE_LESS_MEMORY )
- if ( dleafs )
- {
- free( dleafs );
- dleafs = NULL;
- }
-#endif
-}
-
-void SwapOcclusionLumpToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_OCCLUSION ) );
-
- LoadOcclusionLump();
- SetAlignedLumpPosition( LUMP_OCCLUSION );
- AddOcclusionLump();
-}
-
-void SwapPakfileLumpToDisk( const char *pInFilename )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_PAKFILE ) );
-
- byte *pakbuffer = NULL;
- int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
- if ( paksize > 0 )
- {
- GetPakFile()->ActivateByteSwapping( IsX360() );
- GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
-
- ConvertPakFileContents( pInFilename );
- }
- free( pakbuffer );
-
- SetAlignedLumpPosition( LUMP_PAKFILE, XBOX_DVD_SECTORSIZE );
- WritePakFileLump();
-
- ReleasePakFileLumps();
-}
-
-void SwapGameLumpsToDisk( void )
-{
- DevMsg( "Swapping %s\n", GetLumpName( LUMP_GAME_LUMP ) );
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
- SetAlignedLumpPosition( LUMP_GAME_LUMP );
- AddGameLumps();
-}
-
-//-----------------------------------------------------------------------------
-// Generate a table of all static props, used for resolving static prop lighting
-// files back to their actual mdl.
-//-----------------------------------------------------------------------------
-void BuildStaticPropNameTable()
-{
- g_StaticPropNames.Purge();
- g_StaticPropInstances.Purge();
-
- g_GameLumps.ParseGameLump( g_pBSPHeader );
-
- GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- int nVersion = g_GameLumps.GetGameLumpVersion( hGameLump );
- if ( nVersion < 4 )
- {
- // old unsupported version
- return;
- }
-
- if ( nVersion != 4 && nVersion != 5 && nVersion != 6 )
- {
- Error( "Unknown Static Prop Lump version %d!\n", nVersion );
- }
-
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- // get the model dictionary
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
- for ( int i = 0; i < count; i++ )
- {
- g_StaticPropNames.AddToTail( pStaticPropDictLump[i].m_Name );
- }
- pGameLumpData += count * sizeof( StaticPropDictLump_t );
-
- // skip the leaf list
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- pGameLumpData += count * sizeof( StaticPropLeafLump_t );
-
- // get the instances
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- for ( int i = 0; i < count; i++ )
- {
- int propType;
- if ( nVersion == 4 )
- {
- propType = ((StaticPropLumpV4_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLumpV4_t );
- }
- else if ( nVersion == 5 )
- {
- propType = ((StaticPropLumpV5_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLumpV5_t );
- }
- else
- {
- propType = ((StaticPropLump_t *)pGameLumpData)->m_PropType;
- pGameLumpData += sizeof( StaticPropLump_t );
- }
- g_StaticPropInstances.AddToTail( propType );
- }
- }
- }
-
- g_GameLumps.DestroyAllGameLumps();
-}
-
-int AlignBuffer( CUtlBuffer &buffer, int alignment )
-{
- unsigned int newPosition = AlignValue( buffer.TellPut(), alignment );
- int padLength = newPosition - buffer.TellPut();
- for ( int i = 0; i<padLength; i++ )
- {
- buffer.PutChar( '\0' );
- }
- return buffer.TellPut();
-}
-
-struct SortedLump_t
-{
- int lumpNum;
- lump_t *pLump;
-};
-
-int SortLumpsByOffset( const SortedLump_t *pSortedLumpA, const SortedLump_t *pSortedLumpB )
-{
- int fileOffsetA = pSortedLumpA->pLump->fileofs;
- int fileOffsetB = pSortedLumpB->pLump->fileofs;
-
- int fileSizeA = pSortedLumpA->pLump->filelen;
- int fileSizeB = pSortedLumpB->pLump->filelen;
-
- // invalid or empty lumps get sorted together
- if ( !fileSizeA )
- {
- fileOffsetA = 0;
- }
- if ( !fileSizeB )
- {
- fileOffsetB = 0;
- }
-
- // compare by offset, want ascending
- if ( fileOffsetA < fileOffsetB )
- {
- return -1;
- }
- else if ( fileOffsetA > fileOffsetB )
- {
- return 1;
- }
-
- return 0;
-}
-
-bool CompressGameLump( dheader_t *pInBSPHeader, dheader_t *pOutBSPHeader, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
-{
- CByteswap byteSwap;
-
- dgamelumpheader_t* pInGameLumpHeader = (dgamelumpheader_t*)(((byte *)pInBSPHeader) + pInBSPHeader->lumps[LUMP_GAME_LUMP].fileofs);
- dgamelump_t* pInGameLump = (dgamelump_t*)(pInGameLumpHeader + 1);
-
- byteSwap.ActivateByteSwapping( true );
- byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader );
- byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount );
-
- unsigned int newOffset = outputBuffer.TellPut();
- outputBuffer.Put( pInGameLumpHeader, sizeof( dgamelumpheader_t ) );
- outputBuffer.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
-
- dgamelumpheader_t* pOutGameLumpHeader = (dgamelumpheader_t*)((byte *)outputBuffer.Base() + newOffset);
- dgamelump_t* pOutGameLump = (dgamelump_t*)(pOutGameLumpHeader + 1);
-
- // add a dummy terminal gamelump
- // purposely NOT updating the .filelen to reflect the compressed size, but leaving as original size
- // callers use the next entry offset to determine compressed size
- pOutGameLumpHeader->lumpCount++;
- dgamelump_t dummyLump = { 0 };
- outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) );
-
- for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ )
- {
- CUtlBuffer inputBuffer;
- CUtlBuffer compressedBuffer;
-
- pOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 );
-
- if ( pInGameLump[i].filelen )
- {
- inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs, pInGameLump[i].filelen, pInGameLump[i].filelen );
-
- bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
- if ( bCompressed )
- {
- pOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED;
-
- outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- compressedBuffer.Purge();
- }
- else
- {
- // as is
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- }
- }
-
- // fix the dummy terminal lump
- int lastLump = pOutGameLumpHeader->lumpCount-1;
- pOutGameLump[lastLump].fileofs = outputBuffer.TellPut();
-
- // fix the output for 360, swapping it back
- byteSwap.SwapFieldsToTargetEndian( pOutGameLump, pOutGameLumpHeader->lumpCount );
- byteSwap.SwapFieldsToTargetEndian( pOutGameLumpHeader );
-
- pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset;
- pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset;
-
- return true;
-}
-
-bool CompressBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
-{
- CByteswap byteSwap;
-
- dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base();
- if ( pInBSPHeader->ident != BigLong( IDBSPHEADER ) || !pCompressFunc )
- {
- // only compress 360 bsp's
- return false;
- }
-
- // bsp is 360, swap the header back
- byteSwap.ActivateByteSwapping( true );
- byteSwap.SwapFieldsToTargetEndian( pInBSPHeader );
-
- // output will be smaller, use input size as upper bound
- outputBuffer.EnsureCapacity( inputBuffer.TellMaxPut() );
- outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) );
-
- dheader_t *pOutBSPHeader = (dheader_t *)outputBuffer.Base();
-
- // must adhere to input lump's offset order and process according to that, NOT lump num
- // sort by offset order
- CUtlVector< SortedLump_t > sortedLumps;
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- int iIndex = sortedLumps.AddToTail();
- sortedLumps[iIndex].lumpNum = i;
- sortedLumps[iIndex].pLump = &pInBSPHeader->lumps[i];
- }
- sortedLumps.Sort( SortLumpsByOffset );
-
- // iterate in sorted order
- for ( int i = 0; i < HEADER_LUMPS; ++i )
- {
- SortedLump_t *pSortedLump = &sortedLumps[i];
- int lumpNum = pSortedLump->lumpNum;
-
- if ( !pSortedLump->pLump->filelen )
- {
- // degenerate
- pOutBSPHeader->lumps[lumpNum].fileofs = 0;
- }
- else
- {
- int alignment = 4;
- if ( lumpNum == LUMP_PAKFILE )
- {
- alignment = 2048;
- }
- unsigned int newOffset = AlignBuffer( outputBuffer, alignment );
-
- // only set by compressed lumps, hides the uncompressed size
- *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = 0;
-
- CUtlBuffer inputBuffer;
- inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs, pSortedLump->pLump->filelen, pSortedLump->pLump->filelen );
-
- if ( lumpNum == LUMP_GAME_LUMP )
- {
- // the game lump has to have each of its components individually compressed
- CompressGameLump( pInBSPHeader, pOutBSPHeader, outputBuffer, pCompressFunc );
- }
- else if ( lumpNum == LUMP_PAKFILE )
- {
- // add as is
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- else
- {
- CUtlBuffer compressedBuffer;
- bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
- if ( bCompressed )
- {
- // placing the uncompressed size in the unused fourCC, will decode at runtime
- *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = BigLong( inputBuffer.TellPut() );
- pOutBSPHeader->lumps[lumpNum].filelen = compressedBuffer.TellPut();
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
- compressedBuffer.Purge();
- }
- else
- {
- // add as is
- pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
- outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
- }
- }
- }
- }
-
- // fix the output for 360, swapping it back
- byteSwap.SetTargetBigEndian( true );
- byteSwap.SwapFieldsToTargetEndian( pOutBSPHeader );
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// For all lumps in a bsp: Loads the lump from file A, swaps it, writes it to file B.
-// This limits the memory used for the swap process which helps the Xbox 360.
-//
-// NOTE: These lumps will be written to the file in exactly the order they appear here,
-// so they can be shifted around if desired for file access optimization.
-//-----------------------------------------------------------------------------
-bool SwapBSPFile( const char *pInFilename, const char *pOutFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc )
-{
- DevMsg( "Creating %s\n", pOutFilename );
-
- if ( !g_pFileSystem->FileExists( pInFilename ) )
- {
- Warning( "Error! Couldn't open input file %s - BSP swap failed!\n", pInFilename );
- return false;
- }
-
- g_hBSPFile = SafeOpenWrite( pOutFilename );
- if ( !g_hBSPFile )
- {
- Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
- return false;
- }
-
- if ( !pVTFConvertFunc )
- {
- Warning( "Error! Missing VTF Conversion function\n" );
- return false;
- }
- g_pVTFConvertFunc = pVTFConvertFunc;
-
- // optional VHV fixup
- g_pVHVFixupFunc = pVHVFixupFunc;
-
- // optional compression callback
- g_pCompressFunc = pCompressFunc;
-
- // These must be mutually exclusive
- g_bSwapOnLoad = bSwapOnLoad;
- g_bSwapOnWrite = !bSwapOnLoad;
-
- g_Swap.ActivateByteSwapping( true );
-
- OpenBSPFile( pInFilename );
-
- // CRC the bsp first
- CRC32_t mapCRC;
- CRC32_Init(&mapCRC);
- if ( !CRC_MapFile( &mapCRC, pInFilename ) )
- {
- Warning( "Failed to CRC the bsp\n" );
- return false;
- }
-
- // hold a dictionary of all the static prop names
- // this is needed to properly convert any VHV files inside the pak lump
- BuildStaticPropNameTable();
-
- // Set the output file pointer after the header
- dheader_t dummyHeader = { 0 };
- SafeWrite( g_hBSPFile, &dummyHeader, sizeof( dheader_t ) );
-
- // To allow for alignment fixups, the lumps will be written to the
- // output file in the order they appear in this function.
-
- // NOTE: Flags for 360 !!!MUST!!! be first
- SwapLumpToDisk< dflagslump_t >( LUMP_MAP_FLAGS );
-
- // complex lump swaps first or for later contingent data
- SwapLeafLumpToDisk();
- SwapOcclusionLumpToDisk();
- SwapGameLumpsToDisk();
-
- // Strip dead or non relevant lumps
- g_pBSPHeader->lumps[LUMP_DISP_LIGHTMAP_ALPHAS].filelen = 0;
- g_pBSPHeader->lumps[LUMP_FACEIDS].filelen = 0;
-
- // Strip obsolete LDR in favor of HDR
- if ( SwapLumpToDisk<dface_t>( LUMP_FACES_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_FACES].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<dface_t>( LUMP_FACES );
- }
-
- if ( SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS );
- }
-
- // Simple lump swaps
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSDISP );
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE );
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_VISIBILITY );
- SwapLumpToDisk<dmodel_t>( LUMP_MODELS );
- SwapLumpToDisk<dvertex_t>( LUMP_VERTEXES );
- SwapLumpToDisk<dplane_t>( LUMP_PLANES );
- SwapLumpToDisk<dnode_t>( LUMP_NODES );
- SwapLumpToDisk<texinfo_t>( LUMP_TEXINFO );
- SwapLumpToDisk<dtexdata_t>( LUMP_TEXDATA );
- SwapLumpToDisk<ddispinfo_t>( LUMP_DISPINFO );
- SwapLumpToDisk<CDispVert>( LUMP_DISP_VERTS );
- SwapLumpToDisk<CDispTri>( LUMP_DISP_TRIS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
- SwapLumpToDisk<CFaceMacroTextureInfo>( LUMP_FACE_MACRO_TEXTURE_INFO );
- SwapLumpToDisk<dprimitive_t>( LUMP_PRIMITIVES );
- SwapLumpToDisk<dprimvert_t>( LUMP_PRIMVERTS );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_PRIMINDICES );
- SwapLumpToDisk<dface_t>( LUMP_ORIGINALFACES );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFFACES );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFBRUSHES );
- SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_SURFEDGES );
- SwapLumpToDisk<dedge_t>( LUMP_EDGES );
- SwapLumpToDisk<dbrush_t>( LUMP_BRUSHES );
- SwapLumpToDisk<dbrushside_t>( LUMP_BRUSHSIDES );
- SwapLumpToDisk<darea_t>( LUMP_AREAS );
- SwapLumpToDisk<dareaportal_t>( LUMP_AREAPORTALS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_ENTITIES );
- SwapLumpToDisk<dleafwaterdata_t>( LUMP_LEAFWATERDATA );
- SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_VERTNORMALS );
- SwapLumpToDisk<short>( FIELD_SHORT, LUMP_VERTNORMALINDICES );
- SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_CLIPPORTALVERTS );
- SwapLumpToDisk<dcubemapsample_t>( LUMP_CUBEMAPS );
- SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA );
- SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE );
- SwapLumpToDisk<doverlay_t>( LUMP_OVERLAYS );
- SwapLumpToDisk<dwateroverlay_t>( LUMP_WATEROVERLAYS );
- SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER );
- SwapLumpToDisk<doverlayfade_t>( LUMP_OVERLAY_FADES );
-
-
- // NOTE: this data placed at the end for the sake of 360:
- {
- // NOTE: lighting must be the penultimate lump
- // (allows 360 to free this memory part-way through map loading)
- if ( SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) )
- {
- g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0;
- }
- else
- {
- // no HDR, keep LDR version
- SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING );
- }
- // NOTE: Pakfile for 360 !!!MUST!!! be last
- SwapPakfileLumpToDisk( pInFilename );
- }
-
-
- // Store the crc in the flags lump version field
- g_pBSPHeader->lumps[LUMP_MAP_FLAGS].version = mapCRC;
-
- // Pad out the end of the file to a sector boundary for optimal IO
- AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
-
- // Warn of any lumps that didn't get swapped
- for ( int i = 0; i < HEADER_LUMPS; ++i )
- {
- if ( HasLump( i ) && !g_Lumps.bLumpParsed[i] )
- {
- // a new lump got added that needs to have a swap function
- Warning( "BSP: '%s', %s has no swap or copy function. Discarding!\n", pInFilename, GetLumpName(i) );
-
- // the data didn't get copied, so don't reference garbage
- g_pBSPHeader->lumps[i].filelen = 0;
- }
- }
-
- // Write the updated header
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
- g_hBSPFile = 0;
-
- // Cleanup
- g_Swap.ActivateByteSwapping( false );
-
- CloseBSPFile();
-
- g_StaticPropNames.Purge();
- g_StaticPropInstances.Purge();
-
- DevMsg( "Finished BSP Swap\n" );
-
- // caller provided compress func will further compress compatible lumps
- if ( pCompressFunc )
- {
- CUtlBuffer inputBuffer;
- if ( !g_pFileSystem->ReadFile( pOutFilename, NULL, inputBuffer ) )
- {
- Warning( "Error! Couldn't read file %s - final BSP compression failed!\n", pOutFilename );
- return false;
- }
-
- CUtlBuffer outputBuffer;
- if ( !CompressBSP( inputBuffer, outputBuffer, pCompressFunc ) )
- {
- Warning( "Error! Failed to compress BSP '%s'!\n", pOutFilename );
- return false;
- }
-
- g_hBSPFile = SafeOpenWrite( pOutFilename );
- if ( !g_hBSPFile )
- {
- Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
- return false;
- }
- SafeWrite( g_hBSPFile, outputBuffer.Base(), outputBuffer.TellPut() );
- g_pFileSystem->Close( g_hBSPFile );
- g_hBSPFile = 0;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Get the pak lump from a BSP
-//-----------------------------------------------------------------------------
-bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize )
-{
- *pPakData = NULL;
- *pPakSize = 0;
-
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // determine endian nature
- dheader_t *pHeader;
- LoadFile( pBSPFilename, (void **)&pHeader );
- bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
- free( pHeader );
-
- g_bSwapOnLoad = bSwap;
- g_bSwapOnWrite = !bSwap;
-
- OpenBSPFile( pBSPFilename );
-
- if ( g_pBSPHeader->lumps[LUMP_PAKFILE].filelen )
- {
- *pPakSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, pPakData );
- }
-
- CloseBSPFile();
-
- return true;
-}
-
-// compare function for qsort below
-static int LumpOffsetCompare( const void *pElem1, const void *pElem2 )
-{
- int lump1 = *(byte *)pElem1;
- int lump2 = *(byte *)pElem2;
-
- if ( lump1 != lump2 )
- {
- // force LUMP_MAP_FLAGS to be first, always
- if ( lump1 == LUMP_MAP_FLAGS )
- {
- return -1;
- }
- else if ( lump2 == LUMP_MAP_FLAGS )
- {
- return 1;
- }
-
- // force LUMP_PAKFILE to be last, always
- if ( lump1 == LUMP_PAKFILE )
- {
- return 1;
- }
- else if ( lump2 == LUMP_PAKFILE )
- {
- return -1;
- }
- }
-
- int fileOffset1 = g_pBSPHeader->lumps[lump1].fileofs;
- int fileOffset2 = g_pBSPHeader->lumps[lump2].fileofs;
-
- // invalid or empty lumps will get sorted together
- if ( !g_pBSPHeader->lumps[lump1].filelen )
- {
- fileOffset1 = 0;
- }
-
- if ( !g_pBSPHeader->lumps[lump2].filelen )
- {
- fileOffset2 = 0;
- }
-
- // compare by offset
- if ( fileOffset1 < fileOffset2 )
- {
- return -1;
- }
- else if ( fileOffset1 > fileOffset2 )
- {
- return 1;
- }
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Replace the pak lump in a BSP
-//-----------------------------------------------------------------------------
-bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize )
-{
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // determine endian nature
- dheader_t *pHeader;
- LoadFile( pBSPFilename, (void **)&pHeader );
- bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
- free( pHeader );
-
- g_bSwapOnLoad = bSwap;
- g_bSwapOnWrite = bSwap;
-
- OpenBSPFile( pBSPFilename );
-
- // save a copy of the old header
- // generating a new bsp is a destructive operation
- dheader_t oldHeader;
- oldHeader = *g_pBSPHeader;
-
- g_hBSPFile = SafeOpenWrite( pNewFilename );
- if ( !g_hBSPFile )
- {
- return false;
- }
-
- // placeholder only, reset at conclusion
- WriteData( &oldHeader );
-
- // lumps must be reserialized in same relative offset order
- // build sorted order table
- int readOrder[HEADER_LUMPS];
- for ( int i=0; i<HEADER_LUMPS; i++ )
- {
- readOrder[i] = i;
- }
- qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpOffsetCompare );
-
- for ( int i = 0; i < HEADER_LUMPS; i++ )
- {
- int lump = readOrder[i];
-
- if ( lump == LUMP_PAKFILE )
- {
- // pak lump always written last, with special alignment
- continue;
- }
-
- int length = g_pBSPHeader->lumps[lump].filelen;
- if ( length )
- {
- // save the lump data
- int offset = g_pBSPHeader->lumps[lump].fileofs;
- SetAlignedLumpPosition( lump );
- SafeWrite( g_hBSPFile, (byte *)g_pBSPHeader + offset, length );
- }
- else
- {
- g_pBSPHeader->lumps[lump].fileofs = 0;
- }
- }
-
- // Always write the pak file at the end
- // Pad out the end of the file to a sector boundary for optimal IO
- g_pBSPHeader->lumps[LUMP_PAKFILE].fileofs = AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
- g_pBSPHeader->lumps[LUMP_PAKFILE].filelen = pakSize;
- SafeWrite( g_hBSPFile, pPakData, pakSize );
-
- // Pad out the end of the file to a sector boundary for optimal IO
- AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
-
- // Write the updated header
- g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
- WriteData( g_pBSPHeader );
- g_pFileSystem->Close( g_hBSPFile );
-
- CloseBSPFile();
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Build a list of files that BSP owns, world/cubemap materials, static props, etc.
-//-----------------------------------------------------------------------------
-bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList )
-{
- if ( !g_pFileSystem->FileExists( pBSPFilename ) )
- {
- Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
- return false;
- }
-
- // must be set, but exact hdr not critical for dependant traversal
- SetHDRMode( false );
-
- LoadBSPFile( pBSPFilename );
-
- char szBspName[MAX_PATH];
- V_FileBase( pBSPFilename, szBspName, sizeof( szBspName ) );
- V_SetExtension( szBspName, ".bsp", sizeof( szBspName ) );
-
- // get embedded pak files, and internals
- char szFilename[MAX_PATH];
- int fileSize;
- int fileId = -1;
- for ( ;; )
- {
- fileId = GetPakFile()->GetNextFilename( fileId, szFilename, sizeof( szFilename ), fileSize );
- if ( fileId == -1 )
- {
- break;
- }
- pList->AddToTail( szFilename );
- }
-
- // get all the world materials
- for ( int i=0; i<numtexdata; i++ )
- {
- const char *pName = TexDataStringTable_GetString( dtexdata[i].nameStringTableID );
- V_ComposeFileName( "materials", pName, szFilename, sizeof( szFilename ) );
- V_SetExtension( szFilename, ".vmt", sizeof( szFilename ) );
- pList->AddToTail( szFilename );
- }
-
- // get all the static props
- GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
-
- StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
- for ( int i=0; i<count; i++ )
- {
- pList->AddToTail( pStaticPropDictLump[i].m_Name );
- }
- }
- }
-
- // get all the detail props
- hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
- if ( hGameLump != g_GameLumps.InvalidGameLump() )
- {
- byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
- if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
- {
- int count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
-
- DetailObjectDictLump_t *pDetailObjectDictLump = (DetailObjectDictLump_t *)pGameLumpData;
- for ( int i=0; i<count; i++ )
- {
- pList->AddToTail( pDetailObjectDictLump[i].m_Name );
- }
- pGameLumpData += count * sizeof( DetailObjectDictLump_t );
-
- if ( g_GameLumps.GetGameLumpVersion( hGameLump ) == 4 )
- {
- count = ((int *)pGameLumpData)[0];
- pGameLumpData += sizeof( int );
- if ( count )
- {
- // All detail prop sprites must lie in the material detail/detailsprites
- pList->AddToTail( "materials/detail/detailsprites.vmt" );
- }
- }
- }
- }
-
- UnloadBSPFile();
-
- return true;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cmdlib.h"
+#include "mathlib/mathlib.h"
+#include "bsplib.h"
+#include "zip_utils.h"
+#include "scriplib.h"
+#include "utllinkedlist.h"
+#include "bsptreedata.h"
+#include "cmodel.h"
+#include "gamebspfile.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/hardwareverts.h"
+#include "utlbuffer.h"
+#include "utlrbtree.h"
+#include "utlsymbol.h"
+#include "utlstring.h"
+#include "checksum_crc.h"
+#include "physdll.h"
+#include "tier0/dbg.h"
+#include "lumpfiles.h"
+#include "vtf/vtf.h"
+
+//=============================================================================
+
+// Boundary each lump should be aligned to
+#define LUMP_ALIGNMENT 4
+
+// Data descriptions for byte swapping - only needed
+// for structures that are written to file for use by the game.
+BEGIN_BYTESWAP_DATADESC( dheader_t )
+ DEFINE_FIELD( ident, FIELD_INTEGER ),
+ DEFINE_FIELD( version, FIELD_INTEGER ),
+ DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ),
+ DEFINE_FIELD( mapRevision, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( lump_t )
+ DEFINE_FIELD( fileofs, FIELD_INTEGER ),
+ DEFINE_FIELD( filelen, FIELD_INTEGER ),
+ DEFINE_FIELD( version, FIELD_INTEGER ),
+ DEFINE_ARRAY( fourCC, FIELD_CHARACTER, 4 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dflagslump_t )
+ DEFINE_FIELD( m_LevelFlags, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dplane_t )
+ DEFINE_FIELD( normal, FIELD_VECTOR ),
+ DEFINE_FIELD( dist, FIELD_FLOAT ),
+ DEFINE_FIELD( type, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleaf_version_0_t )
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( cluster, FIELD_SHORT ),
+ DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstleafface, FIELD_SHORT ),
+ DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
+ DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
+ DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
+ DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
+ DEFINE_EMBEDDED( m_AmbientLighting ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleaf_t )
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( cluster, FIELD_SHORT ),
+ DEFINE_BITFIELD( bf, FIELD_SHORT, 16 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstleafface, FIELD_SHORT ),
+ DEFINE_FIELD( numleaffaces, FIELD_SHORT ),
+ DEFINE_FIELD( firstleafbrush, FIELD_SHORT ),
+ DEFINE_FIELD( numleafbrushes, FIELD_SHORT ),
+ DEFINE_FIELD( leafWaterDataID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CompressedLightCube ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
+ DEFINE_ARRAY( m_Color, FIELD_CHARACTER, 6 * sizeof(ColorRGBExp32) ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafambientindex_t )
+ DEFINE_FIELD( ambientSampleCount, FIELD_SHORT ),
+ DEFINE_FIELD( firstAmbientSample, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafambientlighting_t ) // array of 6 ColorRGBExp32 (3 bytes and 1 char)
+ DEFINE_EMBEDDED( cube ),
+ DEFINE_FIELD( x, FIELD_CHARACTER ),
+ DEFINE_FIELD( y, FIELD_CHARACTER ),
+ DEFINE_FIELD( z, FIELD_CHARACTER ),
+ DEFINE_FIELD( pad, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dvertex_t )
+ DEFINE_FIELD( point, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dnode_t )
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+ DEFINE_ARRAY( children, FIELD_INTEGER, 2 ),
+ DEFINE_ARRAY( mins, FIELD_SHORT, 3 ),
+ DEFINE_ARRAY( maxs, FIELD_SHORT, 3 ),
+ DEFINE_FIELD( firstface, FIELD_SHORT ),
+ DEFINE_FIELD( numfaces, FIELD_SHORT ),
+ DEFINE_FIELD( area, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( texinfo_t )
+ DEFINE_ARRAY( textureVecsTexelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
+ DEFINE_ARRAY( lightmapVecsLuxelsPerWorldUnits, FIELD_FLOAT, 2 * 4 ),
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( texdata, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dtexdata_t )
+ DEFINE_FIELD( reflectivity, FIELD_VECTOR ),
+ DEFINE_FIELD( nameStringTableID, FIELD_INTEGER ),
+ DEFINE_FIELD( width, FIELD_INTEGER ),
+ DEFINE_FIELD( height, FIELD_INTEGER ),
+ DEFINE_FIELD( view_width, FIELD_INTEGER ),
+ DEFINE_FIELD( view_height, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( ddispinfo_t )
+ DEFINE_FIELD( startPosition, FIELD_VECTOR ),
+ DEFINE_FIELD( m_iDispVertStart, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iDispTriStart, FIELD_INTEGER ),
+ DEFINE_FIELD( power, FIELD_INTEGER ),
+ DEFINE_FIELD( minTess, FIELD_INTEGER ),
+ DEFINE_FIELD( smoothingAngle, FIELD_FLOAT ),
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iMapFace, FIELD_SHORT ),
+ DEFINE_FIELD( m_iLightmapAlphaStart, FIELD_INTEGER ),
+ DEFINE_FIELD( m_iLightmapSamplePositionStart, FIELD_INTEGER ),
+ DEFINE_EMBEDDED_ARRAY( m_EdgeNeighbors, 4 ),
+ DEFINE_EMBEDDED_ARRAY( m_CornerNeighbors, 4 ),
+ DEFINE_ARRAY( m_AllowedVerts, FIELD_INTEGER, ddispinfo_t::ALLOWEDVERTS_SIZE ), // unsigned long
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispNeighbor )
+ DEFINE_EMBEDDED_ARRAY( m_SubNeighbors, 2 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispCornerNeighbors )
+ DEFINE_ARRAY( m_Neighbors, FIELD_SHORT, MAX_DISP_CORNER_NEIGHBORS ),
+ DEFINE_FIELD( m_nNeighbors, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispSubNeighbor )
+ DEFINE_FIELD( m_iNeighbor, FIELD_SHORT ),
+ DEFINE_FIELD( m_NeighborOrientation, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Span, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_NeighborSpan, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispVert )
+ DEFINE_FIELD( m_vVector, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_flAlpha, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CDispTri )
+ DEFINE_FIELD( m_uiTags, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( CFaceMacroTextureInfo )
+ DEFINE_FIELD( m_MacroTextureNameID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dprimitive_t )
+ DEFINE_FIELD( type, FIELD_CHARACTER ),
+ DEFINE_FIELD( firstIndex, FIELD_SHORT ),
+ DEFINE_FIELD( indexCount, FIELD_SHORT ),
+ DEFINE_FIELD( firstVert, FIELD_SHORT ),
+ DEFINE_FIELD( vertCount, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dprimvert_t )
+ DEFINE_FIELD( pos, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dface_t )
+ DEFINE_FIELD( planenum, FIELD_SHORT ),
+ DEFINE_FIELD( side, FIELD_CHARACTER ),
+ DEFINE_FIELD( onNode, FIELD_CHARACTER ),
+ DEFINE_FIELD( firstedge, FIELD_INTEGER ),
+ DEFINE_FIELD( numedges, FIELD_SHORT ),
+ DEFINE_FIELD( texinfo, FIELD_SHORT ),
+ DEFINE_FIELD( dispinfo, FIELD_SHORT ),
+ DEFINE_FIELD( surfaceFogVolumeID, FIELD_SHORT ),
+ DEFINE_ARRAY( styles, FIELD_CHARACTER, MAXLIGHTMAPS ),
+ DEFINE_FIELD( lightofs, FIELD_INTEGER ),
+ DEFINE_FIELD( area, FIELD_FLOAT ),
+ DEFINE_ARRAY( m_LightmapTextureMinsInLuxels, FIELD_INTEGER, 2 ),
+ DEFINE_ARRAY( m_LightmapTextureSizeInLuxels, FIELD_INTEGER, 2 ),
+ DEFINE_FIELD( origFace, FIELD_INTEGER ),
+ DEFINE_FIELD( m_NumPrims, FIELD_SHORT ),
+ DEFINE_FIELD( firstPrimID, FIELD_SHORT ),
+ DEFINE_FIELD( smoothingGroups, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dfaceid_t )
+ DEFINE_FIELD( hammerfaceid, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dbrush_t )
+ DEFINE_FIELD( firstside, FIELD_INTEGER ),
+ DEFINE_FIELD( numsides, FIELD_INTEGER ),
+ DEFINE_FIELD( contents, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dbrushside_t )
+ DEFINE_FIELD( planenum, FIELD_SHORT ),
+ DEFINE_FIELD( texinfo, FIELD_SHORT ),
+ DEFINE_FIELD( dispinfo, FIELD_SHORT ),
+ DEFINE_FIELD( bevel, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dedge_t )
+ DEFINE_ARRAY( v, FIELD_SHORT, 2 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dmodel_t )
+ DEFINE_FIELD( mins, FIELD_VECTOR ),
+ DEFINE_FIELD( maxs, FIELD_VECTOR ),
+ DEFINE_FIELD( origin, FIELD_VECTOR ),
+ DEFINE_FIELD( headnode, FIELD_INTEGER ),
+ DEFINE_FIELD( firstface, FIELD_INTEGER ),
+ DEFINE_FIELD( numfaces, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dphysmodel_t )
+ DEFINE_FIELD( modelIndex, FIELD_INTEGER ),
+ DEFINE_FIELD( dataSize, FIELD_INTEGER ),
+ DEFINE_FIELD( keydataSize, FIELD_INTEGER ),
+ DEFINE_FIELD( solidCount, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dphysdisp_t )
+ DEFINE_FIELD( numDisplacements, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( darea_t )
+ DEFINE_FIELD( numareaportals, FIELD_INTEGER ),
+ DEFINE_FIELD( firstareaportal, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dareaportal_t )
+ DEFINE_FIELD( m_PortalKey, FIELD_SHORT ),
+ DEFINE_FIELD( otherarea, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstClipPortalVert, FIELD_SHORT ),
+ DEFINE_FIELD( m_nClipPortalVerts, FIELD_SHORT ),
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dworldlight_t )
+ DEFINE_FIELD( origin, FIELD_VECTOR ),
+ DEFINE_FIELD( intensity, FIELD_VECTOR ),
+ DEFINE_FIELD( normal, FIELD_VECTOR ),
+ DEFINE_FIELD( cluster, FIELD_INTEGER ),
+ DEFINE_FIELD( type, FIELD_INTEGER ), // enumeration
+ DEFINE_FIELD( style, FIELD_INTEGER ),
+ DEFINE_FIELD( stopdot, FIELD_FLOAT ),
+ DEFINE_FIELD( stopdot2, FIELD_FLOAT ),
+ DEFINE_FIELD( exponent, FIELD_FLOAT ),
+ DEFINE_FIELD( radius, FIELD_FLOAT ),
+ DEFINE_FIELD( constant_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( linear_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( quadratic_attn, FIELD_FLOAT ),
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( texinfo, FIELD_INTEGER ),
+ DEFINE_FIELD( owner, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dleafwaterdata_t )
+ DEFINE_FIELD( surfaceZ, FIELD_FLOAT ),
+ DEFINE_FIELD( minZ, FIELD_FLOAT ),
+ DEFINE_FIELD( surfaceTexInfoID, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doccluderdata_t )
+ DEFINE_FIELD( flags, FIELD_INTEGER ),
+ DEFINE_FIELD( firstpoly, FIELD_INTEGER ),
+ DEFINE_FIELD( polycount, FIELD_INTEGER ),
+ DEFINE_FIELD( mins, FIELD_VECTOR ),
+ DEFINE_FIELD( maxs, FIELD_VECTOR ),
+ DEFINE_FIELD( area, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doccluderpolydata_t )
+ DEFINE_FIELD( firstvertexindex, FIELD_INTEGER ),
+ DEFINE_FIELD( vertexcount, FIELD_INTEGER ),
+ DEFINE_FIELD( planenum, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dcubemapsample_t )
+ DEFINE_ARRAY( origin, FIELD_INTEGER, 3 ),
+ DEFINE_FIELD( size, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doverlay_t )
+ DEFINE_FIELD( nId, FIELD_INTEGER ),
+ DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
+ DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
+ DEFINE_ARRAY( aFaces, FIELD_INTEGER, OVERLAY_BSP_FACE_COUNT ),
+ DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
+ DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dwateroverlay_t )
+ DEFINE_FIELD( nId, FIELD_INTEGER ),
+ DEFINE_FIELD( nTexInfo, FIELD_SHORT ),
+ DEFINE_FIELD( m_nFaceCountAndRenderOrder, FIELD_SHORT ),
+ DEFINE_ARRAY( aFaces, FIELD_INTEGER, WATEROVERLAY_BSP_FACE_COUNT ),
+ DEFINE_ARRAY( flU, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( flV, FIELD_FLOAT, 2 ),
+ DEFINE_ARRAY( vecUVPoints, FIELD_VECTOR, 4 ),
+ DEFINE_FIELD( vecOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( vecBasisNormal, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( doverlayfade_t )
+ DEFINE_FIELD( flFadeDistMinSq, FIELD_FLOAT ),
+ DEFINE_FIELD( flFadeDistMaxSq, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dgamelumpheader_t )
+ DEFINE_FIELD( lumpCount, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( dgamelump_t )
+ DEFINE_FIELD( id, FIELD_INTEGER ), // GameLumpId_t
+ DEFINE_FIELD( flags, FIELD_SHORT ),
+ DEFINE_FIELD( version, FIELD_SHORT ),
+ DEFINE_FIELD( fileofs, FIELD_INTEGER ),
+ DEFINE_FIELD( filelen, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+// From gamebspfile.h
+BEGIN_BYTESWAP_DATADESC( StaticPropDictLump_t )
+ DEFINE_ARRAY( m_Name, FIELD_CHARACTER, STATIC_PROP_NAME_LENGTH ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLump_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
+ DEFINE_FIELD( m_nMinDXLevel, FIELD_SHORT ),
+ DEFINE_FIELD( m_nMaxDXLevel, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLumpV4_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLumpV5_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_PropType, FIELD_SHORT ),
+ DEFINE_FIELD( m_FirstLeaf, FIELD_SHORT ),
+ DEFINE_FIELD( m_LeafCount, FIELD_SHORT ),
+ DEFINE_FIELD( m_Solid, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Skin, FIELD_INTEGER ),
+ DEFINE_FIELD( m_FadeMinDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_FadeMaxDist, FIELD_FLOAT ),
+ DEFINE_FIELD( m_LightingOrigin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flForcedFadeScale, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( StaticPropLeafLump_t )
+ DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailObjectDictLump_t )
+ DEFINE_ARRAY( m_Name, FIELD_CHARACTER, DETAIL_NAME_LENGTH ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailObjectLump_t )
+ DEFINE_FIELD( m_Origin, FIELD_VECTOR ),
+ DEFINE_FIELD( m_Angles, FIELD_VECTOR ), // QAngle
+ DEFINE_FIELD( m_DetailModel, FIELD_SHORT ),
+ DEFINE_FIELD( m_Leaf, FIELD_SHORT ),
+ DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
+ DEFINE_FIELD( m_LightStyles, FIELD_INTEGER ),
+ DEFINE_FIELD( m_LightStyleCount, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_SwayAmount, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_ShapeAngle, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_ShapeSize, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_Orientation, FIELD_CHARACTER ),
+ DEFINE_ARRAY( m_Padding2, FIELD_CHARACTER, 3 ),
+ DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
+ DEFINE_ARRAY( m_Padding3, FIELD_CHARACTER, 3 ),
+ DEFINE_FIELD( m_flScale, FIELD_FLOAT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailSpriteDictLump_t )
+ DEFINE_FIELD( m_UL, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_LR, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_TexUL, FIELD_VECTOR2D ),
+ DEFINE_FIELD( m_TexLR, FIELD_VECTOR2D ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( DetailPropLightstylesLump_t )
+ DEFINE_ARRAY( m_Lighting, FIELD_CHARACTER, 4 ), // ColorRGBExp32
+ DEFINE_FIELD( m_Style, FIELD_CHARACTER ),
+END_BYTESWAP_DATADESC()
+
+// From vradstaticprops.h
+namespace HardwareVerts
+{
+BEGIN_BYTESWAP_DATADESC( MeshHeader_t )
+ DEFINE_FIELD( m_nLod, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nOffset, FIELD_INTEGER ),
+ DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC( FileHeader_t )
+ DEFINE_FIELD( m_nVersion, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nChecksum, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexFlags, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexSize, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nVertexes, FIELD_INTEGER ),
+ DEFINE_FIELD( m_nMeshes, FIELD_INTEGER ),
+ DEFINE_ARRAY( m_nUnused, FIELD_INTEGER, 4 ),
+END_BYTESWAP_DATADESC()
+} // end namespace
+
+static const char *s_LumpNames[] = {
+ "LUMP_ENTITIES", // 0
+ "LUMP_PLANES", // 1
+ "LUMP_TEXDATA", // 2
+ "LUMP_VERTEXES", // 3
+ "LUMP_VISIBILITY", // 4
+ "LUMP_NODES", // 5
+ "LUMP_TEXINFO", // 6
+ "LUMP_FACES", // 7
+ "LUMP_LIGHTING", // 8
+ "LUMP_OCCLUSION", // 9
+ "LUMP_LEAFS", // 10
+ "LUMP_FACEIDS", // 11
+ "LUMP_EDGES", // 12
+ "LUMP_SURFEDGES", // 13
+ "LUMP_MODELS", // 14
+ "LUMP_WORLDLIGHTS", // 15
+ "LUMP_LEAFFACES", // 16
+ "LUMP_LEAFBRUSHES", // 17
+ "LUMP_BRUSHES", // 18
+ "LUMP_BRUSHSIDES", // 19
+ "LUMP_AREAS", // 20
+ "LUMP_AREAPORTALS", // 21
+ "LUMP_UNUSED0", // 22
+ "LUMP_UNUSED1", // 23
+ "LUMP_UNUSED2", // 24
+ "LUMP_UNUSED3", // 25
+ "LUMP_DISPINFO", // 26
+ "LUMP_ORIGINALFACES", // 27
+ "LUMP_PHYSDISP", // 28
+ "LUMP_PHYSCOLLIDE", // 29
+ "LUMP_VERTNORMALS", // 30
+ "LUMP_VERTNORMALINDICES", // 31
+ "LUMP_DISP_LIGHTMAP_ALPHAS", // 32
+ "LUMP_DISP_VERTS", // 33
+ "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", // 34
+ "LUMP_GAME_LUMP", // 35
+ "LUMP_LEAFWATERDATA", // 36
+ "LUMP_PRIMITIVES", // 37
+ "LUMP_PRIMVERTS", // 38
+ "LUMP_PRIMINDICES", // 39
+ "LUMP_PAKFILE", // 40
+ "LUMP_CLIPPORTALVERTS", // 41
+ "LUMP_CUBEMAPS", // 42
+ "LUMP_TEXDATA_STRING_DATA", // 43
+ "LUMP_TEXDATA_STRING_TABLE", // 44
+ "LUMP_OVERLAYS", // 45
+ "LUMP_LEAFMINDISTTOWATER", // 46
+ "LUMP_FACE_MACRO_TEXTURE_INFO", // 47
+ "LUMP_DISP_TRIS", // 48
+ "LUMP_PHYSCOLLIDESURFACE", // 49
+ "LUMP_WATEROVERLAYS", // 50
+ "LUMP_LEAF_AMBIENT_INDEX_HDR", // 51
+ "LUMP_LEAF_AMBIENT_INDEX", // 52
+ "LUMP_LIGHTING_HDR", // 53
+ "LUMP_WORLDLIGHTS_HDR", // 54
+ "LUMP_LEAF_AMBIENT_LIGHTING_HDR", // 55
+ "LUMP_LEAF_AMBIENT_LIGHTING", // 56
+ "LUMP_XZIPPAKFILE", // 57
+ "LUMP_FACES_HDR", // 58
+ "LUMP_MAP_FLAGS", // 59
+ "LUMP_OVERLAY_FADES", // 60
+};
+
+const char *GetLumpName( unsigned int lumpnum )
+{
+ if ( lumpnum >= ARRAYSIZE( s_LumpNames ) )
+ {
+ return "UNKNOWN";
+ }
+ return s_LumpNames[lumpnum];
+}
+
+// "-hdr" tells us to use the HDR fields (if present) on the light sources. Also, tells us to write
+// out the HDR lumps for lightmaps, ambient leaves, and lights sources.
+bool g_bHDR = false;
+
+// Set to true to generate Xbox360 native output files
+static bool g_bSwapOnLoad = false;
+static bool g_bSwapOnWrite = false;
+
+VTFConvertFunc_t g_pVTFConvertFunc;
+VHVFixupFunc_t g_pVHVFixupFunc;
+CompressFunc_t g_pCompressFunc;
+
+CUtlVector< CUtlString > g_StaticPropNames;
+CUtlVector< int > g_StaticPropInstances;
+
+CByteswap g_Swap;
+
+uint32 g_LevelFlags = 0;
+
+int nummodels;
+dmodel_t dmodels[MAX_MAP_MODELS];
+
+int visdatasize;
+byte dvisdata[MAX_MAP_VISIBILITY];
+dvis_t *dvis = (dvis_t *)dvisdata;
+
+CUtlVector<byte> dlightdataHDR;
+CUtlVector<byte> dlightdataLDR;
+CUtlVector<byte> *pdlightdata = &dlightdataLDR;
+
+CUtlVector<char> dentdata;
+
+int numleafs;
+#if !defined( BSP_USE_LESS_MEMORY )
+dleaf_t dleafs[MAX_MAP_LEAFS];
+#else
+dleaf_t *dleafs;
+#endif
+
+CUtlVector<dleafambientindex_t> g_LeafAmbientIndexLDR;
+CUtlVector<dleafambientindex_t> g_LeafAmbientIndexHDR;
+CUtlVector<dleafambientindex_t> *g_pLeafAmbientIndex = NULL;
+CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingLDR;
+CUtlVector<dleafambientlighting_t> g_LeafAmbientLightingHDR;
+CUtlVector<dleafambientlighting_t> *g_pLeafAmbientLighting = NULL;
+
+unsigned short g_LeafMinDistToWater[MAX_MAP_LEAFS];
+
+int numplanes;
+dplane_t dplanes[MAX_MAP_PLANES];
+
+int numvertexes;
+dvertex_t dvertexes[MAX_MAP_VERTS];
+
+int g_numvertnormalindices; // dfaces reference these. These index g_vertnormals.
+unsigned short g_vertnormalindices[MAX_MAP_VERTNORMALS];
+
+int g_numvertnormals;
+Vector g_vertnormals[MAX_MAP_VERTNORMALS];
+
+int numnodes;
+dnode_t dnodes[MAX_MAP_NODES];
+
+CUtlVector<texinfo_t> texinfo( MAX_MAP_TEXINFO );
+
+int numtexdata;
+dtexdata_t dtexdata[MAX_MAP_TEXDATA];
+
+//
+// displacement map bsp file info: dispinfo
+//
+CUtlVector<ddispinfo_t> g_dispinfo;
+CUtlVector<CDispVert> g_DispVerts;
+CUtlVector<CDispTri> g_DispTris;
+CUtlVector<unsigned char> g_DispLightmapSamplePositions; // LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS
+
+int numorigfaces;
+dface_t dorigfaces[MAX_MAP_FACES];
+
+int g_numprimitives = 0;
+dprimitive_t g_primitives[MAX_MAP_PRIMITIVES];
+
+int g_numprimverts = 0;
+dprimvert_t g_primverts[MAX_MAP_PRIMVERTS];
+
+int g_numprimindices = 0;
+unsigned short g_primindices[MAX_MAP_PRIMINDICES];
+
+int numfaces;
+dface_t dfaces[MAX_MAP_FACES];
+
+int numfaceids;
+CUtlVector<dfaceid_t> dfaceids;
+
+int numfaces_hdr;
+dface_t dfaces_hdr[MAX_MAP_FACES];
+
+int numedges;
+dedge_t dedges[MAX_MAP_EDGES];
+
+int numleaffaces;
+unsigned short dleaffaces[MAX_MAP_LEAFFACES];
+
+int numleafbrushes;
+unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int numsurfedges;
+int dsurfedges[MAX_MAP_SURFEDGES];
+
+int numbrushes;
+dbrush_t dbrushes[MAX_MAP_BRUSHES];
+
+int numbrushsides;
+dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
+
+int numareas;
+darea_t dareas[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t dareaportals[MAX_MAP_AREAPORTALS];
+
+int numworldlightsLDR;
+dworldlight_t dworldlightsLDR[MAX_MAP_WORLDLIGHTS];
+
+int numworldlightsHDR;
+dworldlight_t dworldlightsHDR[MAX_MAP_WORLDLIGHTS];
+
+int *pNumworldlights = &numworldlightsLDR;
+dworldlight_t *dworldlights = dworldlightsLDR;
+
+int numleafwaterdata = 0;
+dleafwaterdata_t dleafwaterdata[MAX_MAP_LEAFWATERDATA];
+
+CUtlVector<CFaceMacroTextureInfo> g_FaceMacroTextureInfos;
+
+Vector g_ClipPortalVerts[MAX_MAP_PORTALVERTS];
+int g_nClipPortalVerts;
+
+dcubemapsample_t g_CubemapSamples[MAX_MAP_CUBEMAPSAMPLES];
+int g_nCubemapSamples = 0;
+
+int g_nOverlayCount;
+doverlay_t g_Overlays[MAX_MAP_OVERLAYS];
+doverlayfade_t g_OverlayFades[MAX_MAP_OVERLAYS];
+
+int g_nWaterOverlayCount;
+dwateroverlay_t g_WaterOverlays[MAX_MAP_WATEROVERLAYS];
+
+CUtlVector<char> g_TexDataStringData;
+CUtlVector<int> g_TexDataStringTable;
+
+byte *g_pPhysCollide = NULL;
+int g_PhysCollideSize = 0;
+int g_MapRevision = 0;
+
+byte *g_pPhysDisp = NULL;
+int g_PhysDispSize = 0;
+
+CUtlVector<doccluderdata_t> g_OccluderData( 256, 256 );
+CUtlVector<doccluderpolydata_t> g_OccluderPolyData( 1024, 1024 );
+CUtlVector<int> g_OccluderVertexIndices( 2048, 2048 );
+
+template <class T> static void WriteData( T *pData, int count = 1 );
+template <class T> static void WriteData( int fieldType, T *pData, int count = 1 );
+template< class T > static void AddLump( int lumpnum, T *pData, int count, int version = 0 );
+template< class T > static void AddLump( int lumpnum, CUtlVector<T> &data, int version = 0 );
+
+dheader_t *g_pBSPHeader;
+FileHandle_t g_hBSPFile;
+
+struct Lump_t
+{
+ void *pLumps[HEADER_LUMPS];
+ int size[HEADER_LUMPS];
+ bool bLumpParsed[HEADER_LUMPS];
+} g_Lumps;
+
+CGameLump g_GameLumps;
+
+static IZip *s_pakFile = 0;
+
+//-----------------------------------------------------------------------------
+// Keep the file position aligned to an arbitrary boundary.
+// Returns updated file position.
+//-----------------------------------------------------------------------------
+static unsigned int AlignFilePosition( FileHandle_t hFile, int alignment )
+{
+ unsigned int currPosition = g_pFileSystem->Tell( hFile );
+
+ if ( alignment >= 2 )
+ {
+ unsigned int newPosition = AlignValue( currPosition, alignment );
+ unsigned int count = newPosition - currPosition;
+ if ( count )
+ {
+ char *pBuffer;
+ char smallBuffer[4096];
+ if ( count > sizeof( smallBuffer ) )
+ {
+ pBuffer = (char *)malloc( count );
+ }
+ else
+ {
+ pBuffer = smallBuffer;
+ }
+
+ memset( pBuffer, 0, count );
+ SafeWrite( hFile, pBuffer, count );
+
+ if ( pBuffer != smallBuffer )
+ {
+ free( pBuffer );
+ }
+
+ currPosition = newPosition;
+ }
+ }
+
+ return currPosition;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: // Get a pakfile instance
+// Output : IZip*
+//-----------------------------------------------------------------------------
+IZip* GetPakFile( void )
+{
+ if ( !s_pakFile )
+ {
+ s_pakFile = IZip::CreateZip();
+ }
+ return s_pakFile;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Free the pak files
+//-----------------------------------------------------------------------------
+void ReleasePakFileLumps( void )
+{
+ // Release the pak files
+ IZip::ReleaseZip( s_pakFile );
+ s_pakFile = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the sector alignment for all subsequent zip operations
+//-----------------------------------------------------------------------------
+void ForceAlignment( IZip *pak, bool bAlign, bool bCompatibleFormat, unsigned int alignmentSize )
+{
+ pak->ForceAlignment( bAlign, bCompatibleFormat, alignmentSize );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Store data back out to .bsp file
+//-----------------------------------------------------------------------------
+static void WritePakFileLump( void )
+{
+ CUtlBuffer buf( 0, 0 );
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->SaveToBuffer( buf );
+
+ // must respect pak file alignment
+ // pad up and ensure lump starts on same aligned boundary
+ AlignFilePosition( g_hBSPFile, GetPakFile()->GetAlignment() );
+
+ // Now store final buffers out to file
+ AddLump( LUMP_PAKFILE, (byte*)buf.Base(), buf.TellPut() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all entries
+//-----------------------------------------------------------------------------
+void ClearPakFile( IZip *pak )
+{
+ pak->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add file from disk to .bsp PAK lump
+// Input : *relativename -
+// *fullpath -
+//-----------------------------------------------------------------------------
+void AddFileToPak( IZip *pak, const char *relativename, const char *fullpath )
+{
+ pak->AddFileToZip( relativename, fullpath );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add buffer to .bsp PAK lump as named file
+// Input : *relativename -
+// *data -
+// length -
+//-----------------------------------------------------------------------------
+void AddBufferToPak( IZip *pak, const char *pRelativeName, void *data, int length, bool bTextMode )
+{
+ pak->AddBufferToZip( pRelativeName, data, length, bTextMode );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if a file already exists in the pack file.
+// Input : *relativename -
+//-----------------------------------------------------------------------------
+bool FileExistsInPak( IZip *pak, const char *pRelativeName )
+{
+ return pak->FileExistsInZip( pRelativeName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Read a file from the pack file
+//-----------------------------------------------------------------------------
+bool ReadFileFromPak( IZip *pak, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
+{
+ return pak->ReadFileFromZip( pRelativeName, bTextMode, buf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove file from .bsp PAK lump
+// Input : *relativename -
+//-----------------------------------------------------------------------------
+void RemoveFileFromPak( IZip *pak, const char *relativename )
+{
+ pak->RemoveFileFromZip( relativename );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get next filename in directory
+// Input : id, -1 to start, returns next id, or -1 at list conclusion
+//-----------------------------------------------------------------------------
+int GetNextFilename( IZip *pak, int id, char *pBuffer, int bufferSize, int &fileSize )
+{
+ return pak->GetNextFilename( id, pBuffer, bufferSize, fileSize );
+}
+
+//-----------------------------------------------------------------------------
+// Convert four-CC code to a handle + back
+//-----------------------------------------------------------------------------
+GameLumpHandle_t CGameLump::GetGameLumpHandle( GameLumpId_t id )
+{
+ // NOTE: I'm also expecting game lump id's to be four-CC codes
+ Assert( id > HEADER_LUMPS );
+
+ FOR_EACH_LL(m_GameLumps, i)
+ {
+ if (m_GameLumps[i].m_Id == id)
+ return i;
+ }
+
+ return InvalidGameLump();
+}
+
+GameLumpId_t CGameLump::GetGameLumpId( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Id;
+}
+
+int CGameLump::GetGameLumpFlags( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Flags;
+}
+
+int CGameLump::GetGameLumpVersion( GameLumpHandle_t handle )
+{
+ return m_GameLumps[handle].m_Version;
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump accessor methods
+//-----------------------------------------------------------------------------
+
+void* CGameLump::GetGameLump( GameLumpHandle_t id )
+{
+ return m_GameLumps[id].m_Memory.Base();
+}
+
+int CGameLump::GameLumpSize( GameLumpHandle_t id )
+{
+ return m_GameLumps[id].m_Memory.NumAllocated();
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump iteration methods
+//-----------------------------------------------------------------------------
+
+GameLumpHandle_t CGameLump::FirstGameLump()
+{
+ return (m_GameLumps.Count()) ? m_GameLumps.Head() : InvalidGameLump();
+}
+
+GameLumpHandle_t CGameLump::NextGameLump( GameLumpHandle_t handle )
+{
+
+ return (m_GameLumps.IsValidIndex(handle)) ? m_GameLumps.Next(handle) : InvalidGameLump();
+}
+
+GameLumpHandle_t CGameLump::InvalidGameLump()
+{
+ return 0xFFFF;
+}
+
+
+//-----------------------------------------------------------------------------
+// Game lump creation/destruction method
+//-----------------------------------------------------------------------------
+
+GameLumpHandle_t CGameLump::CreateGameLump( GameLumpId_t id, int size, int flags, int version )
+{
+ Assert( GetGameLumpHandle(id) == InvalidGameLump() );
+ GameLumpHandle_t handle = m_GameLumps.AddToTail();
+ m_GameLumps[handle].m_Id = id;
+ m_GameLumps[handle].m_Flags = flags;
+ m_GameLumps[handle].m_Version = version;
+ m_GameLumps[handle].m_Memory.EnsureCapacity( size );
+ return handle;
+}
+
+void CGameLump::DestroyGameLump( GameLumpHandle_t handle )
+{
+ m_GameLumps.Remove( handle );
+}
+
+void CGameLump::DestroyAllGameLumps()
+{
+ m_GameLumps.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Compute file size and clump count
+//-----------------------------------------------------------------------------
+
+void CGameLump::ComputeGameLumpSizeAndCount( int& size, int& clumpCount )
+{
+ // Figure out total size of the client lumps
+ size = 0;
+ clumpCount = 0;
+ GameLumpHandle_t h;
+ for( h = FirstGameLump(); h != InvalidGameLump(); h = NextGameLump( h ) )
+ {
+ ++clumpCount;
+ size += GameLumpSize( h );
+ }
+
+ // Add on headers
+ size += sizeof( dgamelumpheader_t ) + clumpCount * sizeof( dgamelump_t );
+}
+
+
+void CGameLump::SwapGameLump( GameLumpId_t id, int version, byte *dest, byte *src, int length )
+{
+ int count = 0;
+ switch( id )
+ {
+ case GAMELUMP_STATIC_PROPS:
+ // Swap the static prop model dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (StaticPropDictLump_t*)dest, (StaticPropDictLump_t*)src, count );
+ src += sizeof(StaticPropDictLump_t) * count;
+ dest += sizeof(StaticPropDictLump_t) * count;
+
+ // Swap the leaf list
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (StaticPropLeafLump_t*)dest, (StaticPropLeafLump_t*)src, count );
+ src += sizeof(StaticPropLeafLump_t) * count;
+ dest += sizeof(StaticPropLeafLump_t) * count;
+
+ // Swap the models
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ // The one-at-a-time swap is to compensate for these structures
+ // possibly being misaligned, which crashes the Xbox 360.
+ if ( version == 4 )
+ {
+ StaticPropLumpV4_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLumpV4_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLumpV4_t) );
+ src += sizeof( StaticPropLumpV4_t );
+ dest += sizeof( StaticPropLumpV4_t );
+ }
+ }
+ else if ( version == 5 )
+ {
+ StaticPropLumpV5_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLumpV5_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLumpV5_t) );
+ src += sizeof( StaticPropLumpV5_t );
+ dest += sizeof( StaticPropLumpV5_t );
+ }
+ }
+ else
+ {
+ if ( version != 6 )
+ {
+ Error( "Unknown Static Prop Lump version %d didn't get swapped!\n", version );
+ }
+
+ StaticPropLump_t lump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &lump, src, sizeof(StaticPropLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &lump, &lump );
+ Q_memcpy( dest, &lump, sizeof(StaticPropLump_t) );
+ src += sizeof( StaticPropLump_t );
+ dest += sizeof( StaticPropLump_t );
+ }
+ }
+ break;
+
+ case GAMELUMP_DETAIL_PROPS:
+ // Swap the detail prop model dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailObjectDictLump_t*)dest, (DetailObjectDictLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+
+ if ( version == 4 )
+ {
+ // Swap the detail sprite dict
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ DetailSpriteDictLump_t spritelump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &spritelump, src, sizeof(DetailSpriteDictLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &spritelump, &spritelump );
+ Q_memcpy( dest, &spritelump, sizeof(DetailSpriteDictLump_t) );
+ src += sizeof(DetailSpriteDictLump_t);
+ dest += sizeof(DetailSpriteDictLump_t);
+ }
+
+ // Swap the models
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ DetailObjectLump_t objectlump;
+ for ( int i = 0; i < count; ++i )
+ {
+ Q_memcpy( &objectlump, src, sizeof(DetailObjectLump_t) );
+ g_Swap.SwapFieldsToTargetEndian( &objectlump, &objectlump );
+ Q_memcpy( dest, &objectlump, sizeof(DetailObjectLump_t) );
+ src += sizeof(DetailObjectLump_t);
+ dest += sizeof(DetailObjectLump_t);
+ }
+ }
+ break;
+
+ case GAMELUMP_DETAIL_PROP_LIGHTING:
+ // Swap the LDR light styles
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+ break;
+
+ case GAMELUMP_DETAIL_PROP_LIGHTING_HDR:
+ // Swap the HDR light styles
+ count = *(int*)src;
+ g_Swap.SwapBufferToTargetEndian( (int*)dest, (int*)src );
+ count = g_bSwapOnLoad ? *(int*)dest : count;
+ src += sizeof(int);
+ dest += sizeof(int);
+
+ g_Swap.SwapFieldsToTargetEndian( (DetailPropLightstylesLump_t*)dest, (DetailPropLightstylesLump_t*)src, count );
+ src += sizeof(DetailObjectDictLump_t) * count;
+ dest += sizeof(DetailObjectDictLump_t) * count;
+ break;
+
+ default:
+ char idchars[5] = {0};
+ Q_memcpy( idchars, &id, 4 );
+ Warning( "Unknown game lump '%s' didn't get swapped!\n", idchars );
+ memcpy ( dest, src, length);
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Game lump file I/O
+//-----------------------------------------------------------------------------
+void CGameLump::ParseGameLump( dheader_t* pHeader )
+{
+ g_GameLumps.DestroyAllGameLumps();
+
+ g_Lumps.bLumpParsed[LUMP_GAME_LUMP] = true;
+
+ int length = pHeader->lumps[LUMP_GAME_LUMP].filelen;
+ int ofs = pHeader->lumps[LUMP_GAME_LUMP].fileofs;
+
+ if (length > 0)
+ {
+ // Read dictionary...
+ dgamelumpheader_t* pGameLumpHeader = (dgamelumpheader_t*)((byte *)pHeader + ofs);
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pGameLumpHeader );
+ }
+ dgamelump_t* pGameLump = (dgamelump_t*)(pGameLumpHeader + 1);
+ for (int i = 0; i < pGameLumpHeader->lumpCount; ++i )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pGameLump[i] );
+ }
+
+ int length = pGameLump[i].filelen;
+ GameLumpHandle_t lump = g_GameLumps.CreateGameLump( pGameLump[i].id, length, pGameLump[i].flags, pGameLump[i].version );
+ if ( g_bSwapOnLoad )
+ {
+ SwapGameLump( pGameLump[i].id, pGameLump[i].version, (byte*)g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
+ }
+ else
+ {
+ memcpy( g_GameLumps.GetGameLump(lump), (byte *)pHeader + pGameLump[i].fileofs, length );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// String table methods
+//-----------------------------------------------------------------------------
+const char *TexDataStringTable_GetString( int stringID )
+{
+ return &g_TexDataStringData[g_TexDataStringTable[stringID]];
+}
+
+int TexDataStringTable_AddOrFindString( const char *pString )
+{
+ int i;
+ // garymcthack: Make this use an RBTree!
+ for( i = 0; i < g_TexDataStringTable.Count(); i++ )
+ {
+ if( stricmp( pString, &g_TexDataStringData[g_TexDataStringTable[i]] ) == 0 )
+ {
+ return i;
+ }
+ }
+
+ int len = strlen( pString );
+ int outOffset = g_TexDataStringData.AddMultipleToTail( len+1, pString );
+ int outIndex = g_TexDataStringTable.AddToTail( outOffset );
+ return outIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Adds all game lumps into one big block
+//-----------------------------------------------------------------------------
+
+static void AddGameLumps( )
+{
+ // Figure out total size of the client lumps
+ int size, clumpCount;
+ g_GameLumps.ComputeGameLumpSizeAndCount( size, clumpCount );
+
+ // Set up the main lump dictionary entry
+ g_Lumps.size[LUMP_GAME_LUMP] = 0; // mark it written
+
+ lump_t* lump = &g_pBSPHeader->lumps[LUMP_GAME_LUMP];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = size;
+
+ // write header
+ dgamelumpheader_t header;
+ header.lumpCount = clumpCount;
+ WriteData( &header );
+
+ // write dictionary
+ dgamelump_t dict;
+ int offset = lump->fileofs + sizeof(header) + clumpCount * sizeof(dgamelump_t);
+ GameLumpHandle_t h;
+ for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
+ {
+ dict.id = g_GameLumps.GetGameLumpId(h);
+ dict.version = g_GameLumps.GetGameLumpVersion(h);
+ dict.flags = g_GameLumps.GetGameLumpFlags(h);
+ dict.fileofs = offset;
+ dict.filelen = g_GameLumps.GameLumpSize( h );
+ offset += dict.filelen;
+
+ WriteData( &dict );
+ }
+
+ // write lumps..
+ for( h = g_GameLumps.FirstGameLump(); h != g_GameLumps.InvalidGameLump(); h = g_GameLumps.NextGameLump( h ) )
+ {
+ unsigned int lumpsize = g_GameLumps.GameLumpSize(h);
+ if ( g_bSwapOnWrite )
+ {
+ g_GameLumps.SwapGameLump( g_GameLumps.GetGameLumpId(h), g_GameLumps.GetGameLumpVersion(h), (byte*)g_GameLumps.GetGameLump(h), (byte*)g_GameLumps.GetGameLump(h), lumpsize );
+ }
+ SafeWrite( g_hBSPFile, g_GameLumps.GetGameLump(h), lumpsize );
+ }
+
+ // align to doubleword
+ AlignFilePosition( g_hBSPFile, 4 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds the occluder lump...
+//-----------------------------------------------------------------------------
+static void AddOcclusionLump( )
+{
+ g_Lumps.size[LUMP_OCCLUSION] = 0; // mark it written
+
+ int nOccluderCount = g_OccluderData.Count();
+ int nOccluderPolyDataCount = g_OccluderPolyData.Count();
+ int nOccluderVertexIndices = g_OccluderVertexIndices.Count();
+
+ int nLumpLength = nOccluderCount * sizeof(doccluderdata_t) +
+ nOccluderPolyDataCount * sizeof(doccluderpolydata_t) +
+ nOccluderVertexIndices * sizeof(int) +
+ 3 * sizeof(int);
+
+ lump_t *lump = &g_pBSPHeader->lumps[LUMP_OCCLUSION];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = nLumpLength;
+ lump->version = LUMP_OCCLUSION_VERSION;
+ lump->fourCC[0] = ( char )0;
+ lump->fourCC[1] = ( char )0;
+ lump->fourCC[2] = ( char )0;
+ lump->fourCC[3] = ( char )0;
+
+ // Data is swapped in place, so the 'Count' variables aren't safe to use after they're written
+ WriteData( FIELD_INTEGER, &nOccluderCount );
+ WriteData( (doccluderdata_t*)g_OccluderData.Base(), g_OccluderData.Count() );
+ WriteData( FIELD_INTEGER, &nOccluderPolyDataCount );
+ WriteData( (doccluderpolydata_t*)g_OccluderPolyData.Base(), g_OccluderPolyData.Count() );
+ WriteData( FIELD_INTEGER, &nOccluderVertexIndices );
+ WriteData( FIELD_INTEGER, (int*)g_OccluderVertexIndices.Base(), g_OccluderVertexIndices.Count() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the occluder lump...
+//-----------------------------------------------------------------------------
+static void UnserializeOcclusionLumpV2( CUtlBuffer &buf )
+{
+ int nCount = buf.GetInt();
+ if ( nCount )
+ {
+ g_OccluderData.SetCount( nCount );
+ buf.GetObjects( g_OccluderData.Base(), nCount );
+ }
+
+ nCount = buf.GetInt();
+ if ( nCount )
+ {
+ g_OccluderPolyData.SetCount( nCount );
+ buf.GetObjects( g_OccluderPolyData.Base(), nCount );
+ }
+
+ nCount = buf.GetInt();
+ if ( nCount )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( (int*)buf.PeekGet(), (int*)buf.PeekGet(), nCount );
+ }
+ g_OccluderVertexIndices.SetCount( nCount );
+ buf.Get( g_OccluderVertexIndices.Base(), nCount * sizeof(g_OccluderVertexIndices[0]) );
+ }
+}
+
+
+static void LoadOcclusionLump()
+{
+ g_OccluderData.RemoveAll();
+ g_OccluderPolyData.RemoveAll();
+ g_OccluderVertexIndices.RemoveAll();
+
+ int length, ofs;
+
+ g_Lumps.bLumpParsed[LUMP_OCCLUSION] = true;
+
+ length = g_pBSPHeader->lumps[LUMP_OCCLUSION].filelen;
+ ofs = g_pBSPHeader->lumps[LUMP_OCCLUSION].fileofs;
+
+ CUtlBuffer buf( (byte *)g_pBSPHeader + ofs, length, CUtlBuffer::READ_ONLY );
+ buf.ActivateByteSwapping( g_bSwapOnLoad );
+ switch ( g_pBSPHeader->lumps[LUMP_OCCLUSION].version )
+ {
+ case 2:
+ UnserializeOcclusionLumpV2( buf );
+ break;
+
+ case 0:
+ break;
+
+ default:
+ Error("Unknown occlusion lump version!\n");
+ break;
+ }
+}
+
+
+/*
+===============
+CompressVis
+
+===============
+*/
+int CompressVis (byte *vis, byte *dest)
+{
+ int j;
+ int rep;
+ int visrow;
+ byte *dest_p;
+
+ dest_p = dest;
+// visrow = (r_numvisleafs + 7)>>3;
+ visrow = (dvis->numclusters + 7)>>3;
+
+ for (j=0 ; j<visrow ; j++)
+ {
+ *dest_p++ = vis[j];
+ if (vis[j])
+ continue;
+
+ rep = 1;
+ for ( j++; j<visrow ; j++)
+ if (vis[j] || rep == 255)
+ break;
+ else
+ rep++;
+ *dest_p++ = rep;
+ j--;
+ }
+
+ return dest_p - dest;
+}
+
+
+/*
+===================
+DecompressVis
+===================
+*/
+void DecompressVis (byte *in, byte *decompressed)
+{
+ int c;
+ byte *out;
+ int row;
+
+// row = (r_numvisleafs+7)>>3;
+ row = (dvis->numclusters+7)>>3;
+ out = decompressed;
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ if (!c)
+ Error ("DecompressVis: 0 repeat");
+ in += 2;
+ if ((out - decompressed) + c > row)
+ {
+ c = row - (out - decompressed);
+ Warning( "warning: Vis decompression overrun\n" );
+ }
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+}
+
+//-----------------------------------------------------------------------------
+// Lump-specific swap functions
+//-----------------------------------------------------------------------------
+struct swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int size;
+ int vphysicsID;
+ short version;
+ short modelType;
+};
+
+struct swapcompactsurfaceheader_t : swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int surfaceSize;
+ Vector dragAxisAreas;
+ int axisMapSize;
+};
+
+struct swapmoppsurfaceheader_t : swapcollideheader_t
+{
+ DECLARE_BYTESWAP_DATADESC();
+ int moppSize;
+};
+
+BEGIN_BYTESWAP_DATADESC( swapcollideheader_t )
+ DEFINE_FIELD( size, FIELD_INTEGER ),
+ DEFINE_FIELD( vphysicsID, FIELD_INTEGER ),
+ DEFINE_FIELD( version, FIELD_SHORT ),
+ DEFINE_FIELD( modelType, FIELD_SHORT ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC_( swapcompactsurfaceheader_t, swapcollideheader_t )
+ DEFINE_FIELD( surfaceSize, FIELD_INTEGER ),
+ DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ),
+ DEFINE_FIELD( axisMapSize, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+BEGIN_BYTESWAP_DATADESC_( swapmoppsurfaceheader_t, swapcollideheader_t )
+ DEFINE_FIELD( moppSize, FIELD_INTEGER ),
+END_BYTESWAP_DATADESC()
+
+
+static void SwapPhyscollideLump( byte *pDestBase, byte *pSrcBase, unsigned int &count )
+{
+ IPhysicsCollision *physcollision = NULL;
+ CSysModule *pPhysicsModule = g_pFullFileSystem->LoadModule( "vphysics.dll" );
+ if ( pPhysicsModule )
+ {
+ CreateInterfaceFn physicsFactory = Sys_GetFactory( pPhysicsModule );
+ if ( physicsFactory )
+ {
+ physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
+ }
+ }
+
+ if ( !physcollision )
+ {
+ Warning("!!! WARNING: Can't swap the physcollide lump!\n" );
+ return;
+ }
+
+ // physics data is variable length. The last physmodel is a NULL pointer
+ // with modelIndex -1, dataSize -1
+ dphysmodel_t *pPhysModel;
+ byte *pSrc = pSrcBase;
+
+ // first the src chunks have to be aligned properly
+ // swap increases size, allocate enough expansion room
+ byte *pSrcAlignedBase = (byte*)malloc( 2*count );
+ byte *basePtr = pSrcAlignedBase;
+ byte *pSrcAligned = pSrcAlignedBase;
+
+ do
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pSrcAligned, (dphysmodel_t*)pSrc );
+ }
+ else
+ {
+ Q_memcpy( pSrcAligned, pSrc, sizeof(dphysmodel_t) );
+ }
+ pPhysModel = (dphysmodel_t*)pSrcAligned;
+
+ pSrc += sizeof(dphysmodel_t);
+ pSrcAligned += sizeof(dphysmodel_t);
+
+ if ( pPhysModel->dataSize > 0 )
+ {
+ // Align the collide headers
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ // Get data size
+ int size;
+ Q_memcpy( &size, pSrc, sizeof(int) );
+ if ( g_bSwapOnLoad )
+ size = SwapLong( size );
+
+ // Fixup size
+ int padBytes = 0;
+ if ( size % 4 != 0 )
+ {
+ padBytes = ( 4 - size % 4 );
+ count += padBytes;
+ pPhysModel->dataSize += padBytes;
+ }
+
+ // Copy data and size into alligned buffer
+ int newsize = size + padBytes;
+ if ( g_bSwapOnLoad )
+ newsize = SwapLong( newsize );
+
+ Q_memcpy( pSrcAligned, &newsize, sizeof(int) );
+ Q_memcpy( pSrcAligned + sizeof(int), pSrc + sizeof(int), size );
+ pSrcAligned += size + padBytes + sizeof(int);
+ pSrc += size + sizeof(int);
+ }
+
+ int padBytes = 0;
+ int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
+ Q_memcpy( pSrcAligned, pSrc, pPhysModel->keydataSize );
+ pSrc += pPhysModel->keydataSize;
+ pSrcAligned += pPhysModel->keydataSize;
+ if ( dataSize % 4 != 0 )
+ {
+ // Next chunk will be unaligned
+ padBytes = ( 4 - dataSize % 4 );
+ pPhysModel->keydataSize += padBytes;
+ count += padBytes;
+ Q_memset( pSrcAligned, 0, padBytes );
+ pSrcAligned += padBytes;
+ }
+ }
+ } while ( pPhysModel->dataSize > 0 );
+
+ // Now the data can be swapped properly
+ pSrcBase = pSrcAlignedBase;
+ pSrc = pSrcBase;
+ byte *pDest = pDestBase;
+
+ do
+ {
+ // src headers are in native format
+ pPhysModel = (dphysmodel_t*)pSrc;
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( (dphysmodel_t*)pDest, (dphysmodel_t*)pSrc );
+ }
+ else
+ {
+ Q_memcpy( pDest, pSrc, sizeof(dphysmodel_t) );
+ }
+
+ pSrc += sizeof(dphysmodel_t);
+ pDest += sizeof(dphysmodel_t);
+
+ pSrcBase = pSrc;
+ pDestBase = pDest;
+
+ if ( pPhysModel->dataSize > 0 )
+ {
+ vcollide_t collide = {0};
+ int dataSize = pPhysModel->dataSize + pPhysModel->keydataSize;
+
+ if ( g_bSwapOnWrite )
+ {
+ // Load the collide data
+ physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, false );
+ }
+
+ int *offsets = new int[ pPhysModel->solidCount ];
+
+ // Swap the collision data headers
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ int headerSize = 0;
+ swapcollideheader_t *baseHdr = (swapcollideheader_t*)pSrc;
+ short modelType = baseHdr->modelType;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &modelType );
+ }
+
+ if ( modelType == 0 ) // COLLIDE_POLY
+ {
+ headerSize = sizeof(swapcompactsurfaceheader_t);
+ swapcompactsurfaceheader_t swapHdr;
+ Q_memcpy( &swapHdr, pSrc, headerSize );
+ g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
+ Q_memcpy( pDest, &swapHdr, headerSize );
+ }
+ else if ( modelType == 1 ) // COLLIDE_MOPP
+ {
+ // The PC still unserializes these, but we don't support them
+ if ( g_bSwapOnWrite )
+ {
+ collide.solids[i] = NULL;
+ }
+
+ headerSize = sizeof(swapmoppsurfaceheader_t);
+ swapmoppsurfaceheader_t swapHdr;
+ Q_memcpy( &swapHdr, pSrc, headerSize );
+ g_Swap.SwapFieldsToTargetEndian( &swapHdr, &swapHdr );
+ Q_memcpy( pDest, &swapHdr, headerSize );
+
+ }
+ else
+ {
+ // Shouldn't happen
+ Assert( 0 );
+ }
+
+ if ( g_bSwapOnLoad )
+ {
+ // src needs the native header data to load the vcollides
+ Q_memcpy( pSrc, pDest, headerSize );
+ }
+ // HACK: Need either surfaceSize or moppSize - both sit at the same offset in the structure
+ swapmoppsurfaceheader_t *hdr = (swapmoppsurfaceheader_t*)pSrc;
+ pSrc += hdr->size + sizeof(int);
+ pDest += hdr->size + sizeof(int);
+ offsets[i] = hdr->size;
+ }
+
+ pSrc = pSrcBase;
+ pDest = pDestBase;
+ if ( g_bSwapOnLoad )
+ {
+ physcollision->VCollideLoad( &collide, pPhysModel->solidCount, (const char *)pSrc, dataSize, true );
+ }
+
+ // Write out the ledge tree data
+ for ( int i = 0; i < pPhysModel->solidCount; ++i )
+ {
+ if ( collide.solids[i] )
+ {
+ // skip over the size member
+ pSrc += sizeof(int);
+ pDest += sizeof(int);
+ int offset = physcollision->CollideWrite( (char*)pDest, collide.solids[i], g_bSwapOnWrite );
+ pSrc += offset;
+ pDest += offset;
+ }
+ else
+ {
+ pSrc += offsets[i] + sizeof(int);
+ pDest += offsets[i] + sizeof(int);
+ }
+ }
+
+ // copy the keyvalues data
+ Q_memcpy( pDest, pSrc, pPhysModel->keydataSize );
+ pDest += pPhysModel->keydataSize;
+ pSrc += pPhysModel->keydataSize;
+
+ // Free the memory
+ physcollision->VCollideUnload( &collide );
+ delete [] offsets;
+ }
+
+ // avoid infinite loop on badly formed file
+ if ( (pSrc - basePtr) > count )
+ break;
+
+ } while ( pPhysModel->dataSize > 0 );
+
+ free( pSrcAlignedBase );
+}
+
+
+// UNDONE: This code is not yet tested.
+static void SwapPhysdispLump( byte *pDest, byte *pSrc, int count )
+{
+ // the format of this lump is one unsigned short dispCount, then dispCount unsigned shorts of sizes
+ // followed by an array of variable length (each element is the length of the corresponding entry in the
+ // previous table) byte-stream data structure of the displacement collision models
+ // these byte-stream structs are endian-neutral because each element is byte-sized
+ unsigned short dispCount = *(unsigned short*)pSrc;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &dispCount );
+ }
+ g_Swap.SwapBufferToTargetEndian( (unsigned short*)pDest, (unsigned short*)pSrc, dispCount + 1 );
+
+ const int nBytes = (dispCount + 1) * sizeof( unsigned short );
+ pSrc += nBytes;
+ pDest += nBytes;
+ count -= nBytes;
+
+ g_Swap.SwapBufferToTargetEndian( pDest, pSrc, count );
+}
+
+
+static void SwapVisibilityLump( byte *pDest, byte *pSrc, int count )
+{
+ int firstInt = *(int*)pSrc;
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapBufferToTargetEndian( &firstInt );
+ }
+ int intCt = firstInt * 2 + 1;
+ const int hdrSize = intCt * sizeof(int);
+ g_Swap.SwapBufferToTargetEndian( (int*)pDest, (int*)pSrc, intCt );
+ g_Swap.SwapBufferToTargetEndian( pDest + hdrSize, pSrc + hdrSize, count - hdrSize );
+}
+
+//=============================================================================
+void Lumps_Init( void )
+{
+ memset( &g_Lumps, 0, sizeof(g_Lumps) );
+}
+
+int LumpVersion( int lump )
+{
+ return g_pBSPHeader->lumps[lump].version;
+}
+
+bool HasLump( int lump )
+{
+ return g_pBSPHeader->lumps[lump].filelen > 0;
+}
+
+void ValidateLump( int lump, int length, int size, int forceVersion )
+{
+ if ( length % size )
+ {
+ Error( "ValidateLump: odd size for lump %d", lump );
+ }
+
+ if ( forceVersion >= 0 && forceVersion != g_pBSPHeader->lumps[lump].version )
+ {
+ Error( "ValidateLump: old version for lump %d in map!", lump );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Add Lumps of integral types without datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+int CopyLumpInternal( int fieldType, int lump, T *dest, int forceVersion )
+{
+ g_Lumps.bLumpParsed[lump] = true;
+
+ // Vectors are passed in as floats
+ int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
+ unsigned int length = g_pBSPHeader->lumps[lump].filelen;
+ unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
+
+ // count must be of the integral type
+ unsigned int count = length / sizeof(T);
+
+ ValidateLump( lump, length, fieldSize, forceVersion );
+
+ if ( g_bSwapOnLoad )
+ {
+ switch( lump )
+ {
+ case LUMP_VISIBILITY:
+ SwapVisibilityLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ break;
+
+ case LUMP_PHYSCOLLIDE:
+ // SwapPhyscollideLump may change size
+ SwapPhyscollideLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ length = count;
+ break;
+
+ case LUMP_PHYSDISP:
+ SwapPhysdispLump( (byte*)dest, ((byte*)g_pBSPHeader + ofs), count );
+ break;
+
+ default:
+ g_Swap.SwapBufferToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
+ break;
+ }
+ }
+ else
+ {
+ memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
+ }
+
+ // Return actual count of elements
+ return length / fieldSize;
+}
+
+template< class T >
+int CopyLump( int fieldType, int lump, T *dest, int forceVersion = -1 )
+{
+ return CopyLumpInternal( fieldType, lump, dest, forceVersion );
+}
+
+template< class T >
+void CopyLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ Assert( fieldType != FIELD_VECTOR ); // TODO: Support this if necessary
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+void CopyOptionalLump( int fieldType, int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ // not fatal if not present
+ if ( !HasLump( lump ) )
+ return;
+
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( fieldType, lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+int CopyVariableLump( int fieldType, int lump, void **dest, int forceVersion = -1 )
+{
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ *dest = malloc( length );
+
+ return CopyLumpInternal<T>( fieldType, lump, (T*)*dest, forceVersion );
+}
+
+//-----------------------------------------------------------------------------
+// Add Lumps of object types with datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+int CopyLumpInternal( int lump, T *dest, int forceVersion )
+{
+ g_Lumps.bLumpParsed[lump] = true;
+
+ unsigned int length = g_pBSPHeader->lumps[lump].filelen;
+ unsigned int ofs = g_pBSPHeader->lumps[lump].fileofs;
+ unsigned int count = length / sizeof(T);
+
+ ValidateLump( lump, length, sizeof(T), forceVersion );
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( dest, (T*)((byte*)g_pBSPHeader + ofs), count );
+ }
+ else
+ {
+ memcpy( dest, (byte*)g_pBSPHeader + ofs, length );
+ }
+
+ return count;
+}
+
+template< class T >
+int CopyLump( int lump, T *dest, int forceVersion = -1 )
+{
+ return CopyLumpInternal( lump, dest, forceVersion );
+}
+
+template< class T >
+void CopyLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+void CopyOptionalLump( int lump, CUtlVector<T> &dest, int forceVersion = -1 )
+{
+ // not fatal if not present
+ if ( !HasLump( lump ) )
+ return;
+
+ dest.SetSize( g_pBSPHeader->lumps[lump].filelen / sizeof(T) );
+ CopyLumpInternal( lump, dest.Base(), forceVersion );
+}
+
+template< class T >
+int CopyVariableLump( int lump, void **dest, int forceVersion = -1 )
+{
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ *dest = malloc( length );
+
+ return CopyLumpInternal<T>( lump, (T*)*dest, forceVersion );
+}
+
+//-----------------------------------------------------------------------------
+// Add/Write unknown lumps
+//-----------------------------------------------------------------------------
+void Lumps_Parse( void )
+{
+ int i;
+
+ for ( i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( !g_Lumps.bLumpParsed[i] && g_pBSPHeader->lumps[i].filelen )
+ {
+ g_Lumps.size[i] = CopyVariableLump<byte>( FIELD_CHARACTER, i, &g_Lumps.pLumps[i], -1 );
+ Msg( "Reading unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
+ }
+ }
+}
+
+void Lumps_Write( void )
+{
+ int i;
+
+ for ( i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( g_Lumps.size[i] )
+ {
+ Msg( "Writing unknown lump #%d (%d bytes)\n", i, g_Lumps.size[i] );
+ AddLump( i, (byte*)g_Lumps.pLumps[i], g_Lumps.size[i] );
+ }
+ if ( g_Lumps.pLumps[i] )
+ {
+ free( g_Lumps.pLumps[i] );
+ g_Lumps.pLumps[i] = NULL;
+ }
+ }
+}
+
+int LoadLeafs( void )
+{
+#if defined( BSP_USE_LESS_MEMORY )
+ dleafs = (dleaf_t*)malloc( g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
+#endif
+
+ switch ( LumpVersion( LUMP_LEAFS ) )
+ {
+ case 0:
+ {
+ g_Lumps.bLumpParsed[LUMP_LEAFS] = true;
+ int length = g_pBSPHeader->lumps[LUMP_LEAFS].filelen;
+ int size = sizeof( dleaf_version_0_t );
+ if ( length % size )
+ {
+ Error( "odd size for LUMP_LEAFS\n" );
+ }
+ int count = length / size;
+
+ void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAFS].fileofs );
+ dleaf_version_0_t *pSrc = (dleaf_version_0_t *)pSrcBase;
+ dleaf_t *pDst = dleafs;
+
+ // version 0 predates HDR, build the LDR
+ g_LeafAmbientLightingLDR.SetCount( count );
+ g_LeafAmbientIndexLDR.SetCount( count );
+
+ dleafambientlighting_t *pDstLeafAmbientLighting = &g_LeafAmbientLightingLDR[0];
+ for ( int i = 0; i < count; i++ )
+ {
+ g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pSrc );
+ }
+ // pDst is a subset of pSrc;
+ *pDst = *( ( dleaf_t * )( void * )pSrc );
+ pDstLeafAmbientLighting->cube = pSrc->m_AmbientLighting;
+ pDstLeafAmbientLighting->x = pDstLeafAmbientLighting->y = pDstLeafAmbientLighting->z = pDstLeafAmbientLighting->pad = 0;
+ pDst++;
+ pSrc++;
+ pDstLeafAmbientLighting++;
+ }
+ return count;
+ }
+
+ case 1:
+ return CopyLump( LUMP_LEAFS, dleafs );
+
+ default:
+ Assert( 0 );
+ Error( "Unknown LUMP_LEAFS version\n" );
+ return 0;
+ }
+}
+
+void LoadLeafAmbientLighting( int numLeafs )
+{
+ if ( LumpVersion( LUMP_LEAFS ) == 0 )
+ {
+ // an older leaf version already built the LDR ambient lighting on load
+ return;
+ }
+
+ // old BSP with ambient, or new BSP with no lighting, convert ambient light to new format or create dummy ambient
+ if ( !HasLump( LUMP_LEAF_AMBIENT_INDEX ) )
+ {
+ // a bunch of legacy maps, have these lumps with garbage versions
+ // expect them to be NOT the current version
+ if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING) )
+ {
+ Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ }
+ if ( HasLump(LUMP_LEAF_AMBIENT_LIGHTING_HDR) )
+ {
+ Assert( LumpVersion( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) != LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ }
+
+ void *pSrcBase = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].fileofs );
+ CompressedLightCube *pSrc = NULL;
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING ) )
+ {
+ pSrc = (CompressedLightCube*)pSrcBase;
+ }
+ g_LeafAmbientIndexLDR.SetCount( numLeafs );
+ g_LeafAmbientLightingLDR.SetCount( numLeafs );
+
+ void *pSrcBaseHDR = ( ( byte * )g_pBSPHeader + g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].fileofs );
+ CompressedLightCube *pSrcHDR = NULL;
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
+ {
+ pSrcHDR = (CompressedLightCube*)pSrcBaseHDR;
+ }
+ g_LeafAmbientIndexHDR.SetCount( numLeafs );
+ g_LeafAmbientLightingHDR.SetCount( numLeafs );
+
+ for ( int i = 0; i < numLeafs; i++ )
+ {
+ g_LeafAmbientIndexLDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexLDR[i].firstAmbientSample = i;
+ g_LeafAmbientIndexHDR[i].ambientSampleCount = 1;
+ g_LeafAmbientIndexHDR[i].firstAmbientSample = i;
+
+ Q_memset( &g_LeafAmbientLightingLDR[i], 0, sizeof(g_LeafAmbientLightingLDR[i]) );
+ Q_memset( &g_LeafAmbientLightingHDR[i], 0, sizeof(g_LeafAmbientLightingHDR[i]) );
+
+ if ( pSrc )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pSrc[i] );
+ }
+ g_LeafAmbientLightingLDR[i].cube = pSrc[i];
+ }
+ if ( pSrcHDR )
+ {
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.SwapFieldsToTargetEndian( &pSrcHDR[i] );
+ }
+ g_LeafAmbientLightingHDR[i].cube = pSrcHDR[i];
+ }
+ }
+
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
+ }
+ else
+ {
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR );
+ CopyOptionalLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
+ }
+}
+
+void ValidateHeader( const char *filename, const dheader_t *pHeader )
+{
+ if ( pHeader->ident != IDBSPHEADER )
+ {
+ Error ("%s is not a IBSP file", filename);
+ }
+ if ( pHeader->version < MINBSPVERSION || pHeader->version > BSPVERSION )
+ {
+ Error ("%s is version %i, not %i", filename, pHeader->version, BSPVERSION);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Low level BSP opener for external parsing. Parses headers, but nothing else.
+// You must close the BSP, via CloseBSPFile().
+//-----------------------------------------------------------------------------
+void OpenBSPFile( const char *filename )
+{
+ Lumps_Init();
+
+ // load the file header
+ LoadFile( filename, (void **)&g_pBSPHeader );
+
+ if ( g_bSwapOnLoad )
+ {
+ g_Swap.ActivateByteSwapping( true );
+ g_Swap.SwapFieldsToTargetEndian( g_pBSPHeader );
+ }
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ g_MapRevision = g_pBSPHeader->mapRevision;
+}
+
+//-----------------------------------------------------------------------------
+// CloseBSPFile
+//-----------------------------------------------------------------------------
+void CloseBSPFile( void )
+{
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// LoadBSPFile
+//-----------------------------------------------------------------------------
+void LoadBSPFile( const char *filename )
+{
+ OpenBSPFile( filename );
+
+ nummodels = CopyLump( LUMP_MODELS, dmodels );
+ numvertexes = CopyLump( LUMP_VERTEXES, dvertexes );
+ numplanes = CopyLump( LUMP_PLANES, dplanes );
+ numleafs = LoadLeafs();
+ numnodes = CopyLump( LUMP_NODES, dnodes );
+ CopyLump( LUMP_TEXINFO, texinfo );
+ numtexdata = CopyLump( LUMP_TEXDATA, dtexdata );
+
+ CopyLump( LUMP_DISPINFO, g_dispinfo );
+ CopyLump( LUMP_DISP_VERTS, g_DispVerts );
+ CopyLump( LUMP_DISP_TRIS, g_DispTris );
+ CopyLump( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
+ CopyLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
+
+ numfaces = CopyLump(LUMP_FACES, dfaces, LUMP_FACES_VERSION);
+ if ( HasLump( LUMP_FACES_HDR ) )
+ numfaces_hdr = CopyLump( LUMP_FACES_HDR, dfaces_hdr, LUMP_FACES_VERSION );
+ else
+ numfaces_hdr = 0;
+
+ CopyOptionalLump( LUMP_FACEIDS, dfaceids );
+
+ g_numprimitives = CopyLump( LUMP_PRIMITIVES, g_primitives );
+ g_numprimverts = CopyLump( LUMP_PRIMVERTS, g_primverts );
+ g_numprimindices = CopyLump( FIELD_SHORT, LUMP_PRIMINDICES, g_primindices );
+ numorigfaces = CopyLump( LUMP_ORIGINALFACES, dorigfaces ); // original faces
+ numleaffaces = CopyLump( FIELD_SHORT, LUMP_LEAFFACES, dleaffaces );
+ numleafbrushes = CopyLump( FIELD_SHORT, LUMP_LEAFBRUSHES, dleafbrushes );
+ numsurfedges = CopyLump( FIELD_INTEGER, LUMP_SURFEDGES, dsurfedges );
+ numedges = CopyLump( LUMP_EDGES, dedges );
+ numbrushes = CopyLump( LUMP_BRUSHES, dbrushes );
+ numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides );
+ numareas = CopyLump( LUMP_AREAS, dareas );
+ numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals );
+
+ visdatasize = CopyLump ( FIELD_CHARACTER, LUMP_VISIBILITY, dvisdata );
+ CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
+ CopyOptionalLump( FIELD_CHARACTER, LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
+
+ LoadLeafAmbientLighting( numleafs );
+
+ CopyLump( FIELD_CHARACTER, LUMP_ENTITIES, dentdata );
+ numworldlightsLDR = CopyLump( LUMP_WORLDLIGHTS, dworldlightsLDR );
+ numworldlightsHDR = CopyLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR );
+
+ numleafwaterdata = CopyLump( LUMP_LEAFWATERDATA, dleafwaterdata );
+ g_PhysCollideSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE, (void**)&g_pPhysCollide );
+ g_PhysDispSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PHYSDISP, (void**)&g_pPhysDisp );
+
+ g_numvertnormals = CopyLump( FIELD_VECTOR, LUMP_VERTNORMALS, (float*)g_vertnormals );
+ g_numvertnormalindices = CopyLump( FIELD_SHORT, LUMP_VERTNORMALINDICES, g_vertnormalindices );
+
+ g_nClipPortalVerts = CopyLump( FIELD_VECTOR, LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts );
+ g_nCubemapSamples = CopyLump( LUMP_CUBEMAPS, g_CubemapSamples );
+
+ CopyLump( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
+ CopyLump( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
+
+ g_nOverlayCount = CopyLump( LUMP_OVERLAYS, g_Overlays );
+ g_nWaterOverlayCount = CopyLump( LUMP_WATEROVERLAYS, g_WaterOverlays );
+ CopyLump( LUMP_OVERLAY_FADES, g_OverlayFades );
+
+ dflagslump_t flags_lump;
+
+ if ( HasLump( LUMP_MAP_FLAGS ) )
+ CopyLump ( LUMP_MAP_FLAGS, &flags_lump );
+ else
+ memset( &flags_lump, 0, sizeof( flags_lump ) ); // default flags to 0
+
+ g_LevelFlags = flags_lump.m_LevelFlags;
+
+ LoadOcclusionLump();
+
+ CopyLump( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater );
+
+ /*
+ int crap;
+ for( crap = 0; crap < g_nBSPStringTable; crap++ )
+ {
+ Msg( "stringtable %d", ( int )crap );
+ Msg( " %d:", ( int )g_BSPStringTable[crap] );
+ puts( &g_BSPStringData[g_BSPStringTable[crap]] );
+ puts( "\n" );
+ }
+ */
+
+ // Load PAK file lump into appropriate data structure
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+ }
+ else
+ {
+ GetPakFile()->Reset();
+ }
+
+ free( pakbuffer );
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+
+ // NOTE: Do NOT call CopyLump after Lumps_Parse() it parses all un-Copied lumps
+ // parse any additional lumps
+ Lumps_Parse();
+
+ // everything has been copied out
+ CloseBSPFile();
+
+ g_Swap.ActivateByteSwapping( false );
+}
+
+//-----------------------------------------------------------------------------
+// Reset any state.
+//-----------------------------------------------------------------------------
+void UnloadBSPFile()
+{
+ nummodels = 0;
+ numvertexes = 0;
+ numplanes = 0;
+
+ numleafs = 0;
+#if defined( BSP_USE_LESS_MEMORY )
+ if ( dleafs )
+ {
+ free( dleafs );
+ dleafs = NULL;
+ }
+#endif
+
+ numnodes = 0;
+ texinfo.Purge();
+ numtexdata = 0;
+
+ g_dispinfo.Purge();
+ g_DispVerts.Purge();
+ g_DispTris.Purge();
+
+ g_DispLightmapSamplePositions.Purge();
+ g_FaceMacroTextureInfos.Purge();
+
+ numfaces = 0;
+ numfaces_hdr = 0;
+
+ dfaceids.Purge();
+
+ g_numprimitives = 0;
+ g_numprimverts = 0;
+ g_numprimindices = 0;
+ numorigfaces = 0;
+ numleaffaces = 0;
+ numleafbrushes = 0;
+ numsurfedges = 0;
+ numedges = 0;
+ numbrushes = 0;
+ numbrushsides = 0;
+ numareas = 0;
+ numareaportals = 0;
+
+ visdatasize = 0;
+ dlightdataLDR.Purge();
+ dlightdataHDR.Purge();
+
+ g_LeafAmbientLightingLDR.Purge();
+ g_LeafAmbientLightingHDR.Purge();
+ g_LeafAmbientIndexHDR.Purge();
+ g_LeafAmbientIndexLDR.Purge();
+
+ dentdata.Purge();
+ numworldlightsLDR = 0;
+ numworldlightsHDR = 0;
+
+ numleafwaterdata = 0;
+
+ if ( g_pPhysCollide )
+ {
+ free( g_pPhysCollide );
+ g_pPhysCollide = NULL;
+ }
+ g_PhysCollideSize = 0;
+
+ if ( g_pPhysDisp )
+ {
+ free( g_pPhysDisp );
+ g_pPhysDisp = NULL;
+ }
+ g_PhysDispSize = 0;
+
+ g_numvertnormals = 0;
+ g_numvertnormalindices = 0;
+
+ g_nClipPortalVerts = 0;
+ g_nCubemapSamples = 0;
+
+ g_TexDataStringData.Purge();
+ g_TexDataStringTable.Purge();
+
+ g_nOverlayCount = 0;
+ g_nWaterOverlayCount = 0;
+
+ g_LevelFlags = 0;
+
+ g_OccluderData.Purge();
+ g_OccluderPolyData.Purge();
+ g_OccluderVertexIndices.Purge();
+
+ g_GameLumps.DestroyAllGameLumps();
+
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ if ( g_Lumps.pLumps[i] )
+ {
+ free( g_Lumps.pLumps[i] );
+ g_Lumps.pLumps[i] = NULL;
+ }
+ }
+
+ ReleasePakFileLumps();
+}
+
+//-----------------------------------------------------------------------------
+// LoadBSPFileFilesystemOnly
+//-----------------------------------------------------------------------------
+void LoadBSPFile_FileSystemOnly( const char *filename )
+{
+ Lumps_Init();
+
+ //
+ // load the file header
+ //
+ LoadFile( filename, (void **)&g_pBSPHeader );
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ // Load PAK file lump into appropriate data structure
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer, 1 );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+ }
+ else
+ {
+ GetPakFile()->Reset();
+ }
+
+ free( pakbuffer );
+
+ // everything has been copied out
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+void ExtractZipFileFromBSP( char *pBSPFileName, char *pZipFileName )
+{
+ Lumps_Init();
+
+ //
+ // load the file header
+ //
+ LoadFile( pBSPFileName, (void **)&g_pBSPHeader);
+
+ ValidateHeader( pBSPFileName, g_pBSPHeader );
+
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ FILE *fp;
+ fp = fopen( pZipFileName, "wb" );
+ if( !fp )
+ {
+ fprintf( stderr, "can't open %s\n", pZipFileName );
+ return;
+ }
+
+ fwrite( pakbuffer, paksize, 1, fp );
+ fclose( fp );
+ }
+ else
+ {
+ fprintf( stderr, "zip file is zero length!\n" );
+ }
+}
+
+/*
+=============
+LoadBSPFileTexinfo
+
+Only loads the texinfo lump, so qdata can scan for textures
+=============
+*/
+void LoadBSPFileTexinfo( const char *filename )
+{
+ FILE *f;
+ int length, ofs;
+
+ g_pBSPHeader = (dheader_t*)malloc( sizeof(dheader_t) );
+
+ f = fopen( filename, "rb" );
+ fread( g_pBSPHeader, sizeof(dheader_t), 1, f);
+
+ ValidateHeader( filename, g_pBSPHeader );
+
+ length = g_pBSPHeader->lumps[LUMP_TEXINFO].filelen;
+ ofs = g_pBSPHeader->lumps[LUMP_TEXINFO].fileofs;
+
+ int nCount = length / sizeof(texinfo_t);
+
+ texinfo.Purge();
+ texinfo.AddMultipleToTail( nCount );
+
+ fseek( f, ofs, SEEK_SET );
+ fread( texinfo.Base(), length, 1, f );
+ fclose( f );
+
+ // everything has been copied out
+ free( g_pBSPHeader );
+ g_pBSPHeader = NULL;
+}
+
+static void AddLumpInternal( int lumpnum, void *data, int len, int version )
+{
+ lump_t *lump;
+
+ g_Lumps.size[lumpnum] = 0; // mark it written
+
+ lump = &g_pBSPHeader->lumps[lumpnum];
+
+ lump->fileofs = g_pFileSystem->Tell( g_hBSPFile );
+ lump->filelen = len;
+ lump->version = version;
+ lump->fourCC[0] = ( char )0;
+ lump->fourCC[1] = ( char )0;
+ lump->fourCC[2] = ( char )0;
+ lump->fourCC[3] = ( char )0;
+
+ SafeWrite( g_hBSPFile, data, len );
+
+ // pad out to the next dword
+ AlignFilePosition( g_hBSPFile, 4 );
+}
+
+template< class T >
+static void SwapInPlace( T *pData, int count )
+{
+ if ( !pData )
+ return;
+
+ // use the datadesc to swap the fields in place
+ g_Swap.SwapFieldsToTargetEndian<T>( (T*)pData, pData, count );
+}
+
+template< class T >
+static void SwapInPlace( int fieldType, T *pData, int count )
+{
+ if ( !pData )
+ return;
+
+ // swap the data in place
+ g_Swap.SwapBufferToTargetEndian<T>( (T*)pData, (T*)pData, count );
+}
+
+//-----------------------------------------------------------------------------
+// Add raw data chunk to file (not a lump)
+//-----------------------------------------------------------------------------
+template< class T >
+static void WriteData( int fieldType, T *pData, int count )
+{
+ if ( g_bSwapOnWrite )
+ {
+ SwapInPlace( fieldType, pData, count );
+ }
+ SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
+}
+
+template< class T >
+static void WriteData( T *pData, int count )
+{
+ if ( g_bSwapOnWrite )
+ {
+ SwapInPlace( pData, count );
+ }
+ SafeWrite( g_hBSPFile, pData, count * sizeof(T) );
+}
+
+//-----------------------------------------------------------------------------
+// Add Lump of object types with datadescs
+//-----------------------------------------------------------------------------
+template< class T >
+static void AddLump( int lumpnum, T *pData, int count, int version )
+{
+ AddLumpInternal( lumpnum, pData, count * sizeof(T), version );
+}
+
+template< class T >
+static void AddLump( int lumpnum, CUtlVector<T> &data, int version )
+{
+ AddLumpInternal( lumpnum, data.Base(), data.Count() * sizeof(T), version );
+}
+
+/*
+=============
+WriteBSPFile
+
+Swaps the bsp file in place, so it should not be referenced again
+=============
+*/
+void WriteBSPFile( const char *filename, char *pUnused )
+{
+ if ( texinfo.Count() > MAX_MAP_TEXINFO )
+ {
+ Error( "Map has too many texinfos (has %d, can have at most %d)\n", texinfo.Count(), MAX_MAP_TEXINFO );
+ return;
+ }
+
+ dheader_t outHeader;
+ g_pBSPHeader = &outHeader;
+ memset( g_pBSPHeader, 0, sizeof( dheader_t ) );
+
+ g_pBSPHeader->ident = IDBSPHEADER;
+ g_pBSPHeader->version = BSPVERSION;
+ g_pBSPHeader->mapRevision = g_MapRevision;
+
+ g_hBSPFile = SafeOpenWrite( filename );
+ WriteData( g_pBSPHeader ); // overwritten later
+
+ AddLump( LUMP_PLANES, dplanes, numplanes );
+ AddLump( LUMP_LEAFS, dleafs, numleafs, LUMP_LEAFS_VERSION );
+ AddLump( LUMP_LEAF_AMBIENT_LIGHTING, g_LeafAmbientLightingLDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+ AddLump( LUMP_LEAF_AMBIENT_INDEX, g_LeafAmbientIndexLDR );
+ AddLump( LUMP_LEAF_AMBIENT_INDEX_HDR, g_LeafAmbientIndexHDR );
+ AddLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR, g_LeafAmbientLightingHDR, LUMP_LEAF_AMBIENT_LIGHTING_VERSION );
+
+ AddLump( LUMP_VERTEXES, dvertexes, numvertexes );
+ AddLump( LUMP_NODES, dnodes, numnodes );
+ AddLump( LUMP_TEXINFO, texinfo );
+ AddLump( LUMP_TEXDATA, dtexdata, numtexdata );
+
+ AddLump( LUMP_DISPINFO, g_dispinfo );
+ AddLump( LUMP_DISP_VERTS, g_DispVerts );
+ AddLump( LUMP_DISP_TRIS, g_DispTris );
+ AddLump( LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS, g_DispLightmapSamplePositions );
+ AddLump( LUMP_FACE_MACRO_TEXTURE_INFO, g_FaceMacroTextureInfos );
+
+ AddLump( LUMP_PRIMITIVES, g_primitives, g_numprimitives );
+ AddLump( LUMP_PRIMVERTS, g_primverts, g_numprimverts );
+ AddLump( LUMP_PRIMINDICES, g_primindices, g_numprimindices );
+ AddLump( LUMP_FACES, dfaces, numfaces, LUMP_FACES_VERSION );
+ if (numfaces_hdr)
+ AddLump( LUMP_FACES_HDR, dfaces_hdr, numfaces_hdr, LUMP_FACES_VERSION );
+ AddLump ( LUMP_FACEIDS, dfaceids, numfaceids );
+
+ AddLump( LUMP_ORIGINALFACES, dorigfaces, numorigfaces ); // original faces lump
+ AddLump( LUMP_BRUSHES, dbrushes, numbrushes );
+ AddLump( LUMP_BRUSHSIDES, dbrushsides, numbrushsides );
+ AddLump( LUMP_LEAFFACES, dleaffaces, numleaffaces );
+ AddLump( LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes );
+ AddLump( LUMP_SURFEDGES, dsurfedges, numsurfedges );
+ AddLump( LUMP_EDGES, dedges, numedges );
+ AddLump( LUMP_MODELS, dmodels, nummodels );
+ AddLump( LUMP_AREAS, dareas, numareas );
+ AddLump( LUMP_AREAPORTALS, dareaportals, numareaportals );
+
+ AddLump( LUMP_LIGHTING, dlightdataLDR, LUMP_LIGHTING_VERSION );
+ AddLump( LUMP_LIGHTING_HDR, dlightdataHDR, LUMP_LIGHTING_VERSION );
+ AddLump( LUMP_VISIBILITY, dvisdata, visdatasize );
+ AddLump( LUMP_ENTITIES, dentdata );
+ AddLump( LUMP_WORLDLIGHTS, dworldlightsLDR, numworldlightsLDR );
+ AddLump( LUMP_WORLDLIGHTS_HDR, dworldlightsHDR, numworldlightsHDR );
+ AddLump( LUMP_LEAFWATERDATA, dleafwaterdata, numleafwaterdata );
+
+ AddOcclusionLump();
+
+ dflagslump_t flags_lump;
+ flags_lump.m_LevelFlags = g_LevelFlags;
+ AddLump( LUMP_MAP_FLAGS, &flags_lump, 1 );
+
+ // NOTE: This is just for debugging, so it is disabled in release maps
+#if 0
+ // add the vis portals to the BSP for visualization
+ AddLump( LUMP_PORTALS, dportals, numportals );
+ AddLump( LUMP_CLUSTERS, dclusters, numclusters );
+ AddLump( LUMP_PORTALVERTS, dportalverts, numportalverts );
+ AddLump( LUMP_CLUSTERPORTALS, dclusterportals, numclusterportals );
+#endif
+
+ AddLump( LUMP_CLIPPORTALVERTS, (float*)g_ClipPortalVerts, g_nClipPortalVerts * 3 );
+ AddLump( LUMP_CUBEMAPS, g_CubemapSamples, g_nCubemapSamples );
+ AddLump( LUMP_TEXDATA_STRING_DATA, g_TexDataStringData );
+ AddLump( LUMP_TEXDATA_STRING_TABLE, g_TexDataStringTable );
+ AddLump( LUMP_OVERLAYS, g_Overlays, g_nOverlayCount );
+ AddLump( LUMP_WATEROVERLAYS, g_WaterOverlays, g_nWaterOverlayCount );
+ AddLump( LUMP_OVERLAY_FADES, g_OverlayFades, g_nOverlayCount );
+
+ if ( g_pPhysCollide )
+ {
+ AddLump( LUMP_PHYSCOLLIDE, g_pPhysCollide, g_PhysCollideSize );
+ }
+
+ if ( g_pPhysDisp )
+ {
+ AddLump ( LUMP_PHYSDISP, g_pPhysDisp, g_PhysDispSize );
+ }
+
+ AddLump( LUMP_VERTNORMALS, (float*)g_vertnormals, g_numvertnormals * 3 );
+ AddLump( LUMP_VERTNORMALINDICES, g_vertnormalindices, g_numvertnormalindices );
+
+ AddLump( LUMP_LEAFMINDISTTOWATER, g_LeafMinDistToWater, numleafs );
+
+ AddGameLumps();
+
+ // Write pakfile lump to disk
+ WritePakFileLump();
+
+ // NOTE: Do NOT call AddLump after Lumps_Write() it writes all un-Added lumps
+ // write any additional lumps
+ Lumps_Write();
+
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+}
+
+// Generate the next clear lump filename for the bsp file
+bool GenerateNextLumpFileName( const char *bspfilename, char *lumpfilename, int buffsize )
+{
+ for (int i = 0; i < MAX_LUMPFILES; i++)
+ {
+ GenerateLumpFileName( bspfilename, lumpfilename, buffsize, i );
+
+ if ( !g_pFileSystem->FileExists( lumpfilename ) )
+ return true;
+ }
+
+ return false;
+}
+
+void WriteLumpToFile( char *filename, int lump )
+{
+ if ( !HasLump(lump) )
+ return;
+
+ char lumppre[MAX_PATH];
+ if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
+ {
+ Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
+ return;
+ }
+
+ // Open the file
+ FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
+ if ( !lumpfile )
+ {
+ Error ("Error opening %s! (Check for write enable)\n",filename);
+ return;
+ }
+
+ int ofs = g_pBSPHeader->lumps[lump].fileofs;
+ int length = g_pBSPHeader->lumps[lump].filelen;
+
+ // Write the header
+ lumpfileheader_t lumpHeader;
+ lumpHeader.lumpID = lump;
+ lumpHeader.lumpVersion = LumpVersion(lump);
+ lumpHeader.lumpLength = length;
+ lumpHeader.mapRevision = LittleLong( g_MapRevision );
+ lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
+ SafeWrite (lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
+
+ // Write the lump
+ SafeWrite (lumpfile, (byte *)g_pBSPHeader + ofs, length);
+}
+
+void WriteLumpToFile( char *filename, int lump, int nLumpVersion, void *pBuffer, size_t nBufLen )
+{
+ char lumppre[MAX_PATH];
+ if ( !GenerateNextLumpFileName( filename, lumppre, MAX_PATH ) )
+ {
+ Warning( "Failed to find valid lump filename for bsp %s.\n", filename );
+ return;
+ }
+
+ // Open the file
+ FileHandle_t lumpfile = g_pFileSystem->Open(lumppre, "wb");
+ if ( !lumpfile )
+ {
+ Error ("Error opening %s! (Check for write enable)\n",filename);
+ return;
+ }
+
+ // Write the header
+ lumpfileheader_t lumpHeader;
+ lumpHeader.lumpID = lump;
+ lumpHeader.lumpVersion = nLumpVersion;
+ lumpHeader.lumpLength = nBufLen;
+ lumpHeader.mapRevision = LittleLong( g_MapRevision );
+ lumpHeader.lumpOffset = sizeof(lumpfileheader_t); // Lump starts after the header
+ SafeWrite( lumpfile, &lumpHeader, sizeof(lumpfileheader_t));
+
+ // Write the lump
+ SafeWrite( lumpfile, pBuffer, nBufLen );
+
+ g_pFileSystem->Close( lumpfile );
+}
+
+
+//============================================================================
+#define ENTRIES(a) (sizeof(a)/sizeof(*(a)))
+#define ENTRYSIZE(a) (sizeof(*(a)))
+
+int ArrayUsage( const char *szItem, int items, int maxitems, int itemsize )
+{
+ float percentage = maxitems ? items * 100.0 / maxitems : 0.0;
+
+ Msg("%-17.17s %8i/%-8i %8i/%-8i (%4.1f%%) ",
+ szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage );
+ if ( percentage > 80.0 )
+ Msg( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ Msg( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ Msg( "SIZE OVERFLOW!!!\n" );
+ else
+ Msg( "\n" );
+ return items * itemsize;
+}
+
+int GlobUsage( const char *szItem, int itemstorage, int maxstorage )
+{
+ float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
+ Msg("%-17.17s [variable] %8i/%-8i (%4.1f%%) ",
+ szItem, itemstorage, maxstorage, percentage );
+ if ( percentage > 80.0 )
+ Msg( "VERY FULL!\n" );
+ else if ( percentage > 95.0 )
+ Msg( "SIZE DANGER!\n" );
+ else if ( percentage > 99.9 )
+ Msg( "SIZE OVERFLOW!!!\n" );
+ else
+ Msg( "\n" );
+ return itemstorage;
+}
+
+/*
+=============
+PrintBSPFileSizes
+
+Dumps info about current file
+=============
+*/
+void PrintBSPFileSizes (void)
+{
+ int totalmemory = 0;
+
+// if (!num_entities)
+// ParseEntities ();
+
+ Msg("\n");
+ Msg( "%-17s %16s %16s %9s \n", "Object names", "Objects/Maxobjs", "Memory / Maxmem", "Fullness" );
+ Msg( "%-17s %16s %16s %9s \n", "------------", "---------------", "---------------", "--------" );
+
+ totalmemory += ArrayUsage( "models", nummodels, ENTRIES(dmodels), ENTRYSIZE(dmodels) );
+ totalmemory += ArrayUsage( "brushes", numbrushes, ENTRIES(dbrushes), ENTRYSIZE(dbrushes) );
+ totalmemory += ArrayUsage( "brushsides", numbrushsides, ENTRIES(dbrushsides), ENTRYSIZE(dbrushsides) );
+ totalmemory += ArrayUsage( "planes", numplanes, ENTRIES(dplanes), ENTRYSIZE(dplanes) );
+ totalmemory += ArrayUsage( "vertexes", numvertexes, ENTRIES(dvertexes), ENTRYSIZE(dvertexes) );
+ totalmemory += ArrayUsage( "nodes", numnodes, ENTRIES(dnodes), ENTRYSIZE(dnodes) );
+ totalmemory += ArrayUsage( "texinfos", texinfo.Count(),MAX_MAP_TEXINFO, sizeof(texinfo_t) );
+ totalmemory += ArrayUsage( "texdata", numtexdata, ENTRIES(dtexdata), ENTRYSIZE(dtexdata) );
+
+ totalmemory += ArrayUsage( "dispinfos", g_dispinfo.Count(), 0, sizeof( ddispinfo_t ) );
+ totalmemory += ArrayUsage( "disp_verts", g_DispVerts.Count(), 0, sizeof( g_DispVerts[0] ) );
+ totalmemory += ArrayUsage( "disp_tris", g_DispTris.Count(), 0, sizeof( g_DispTris[0] ) );
+ totalmemory += ArrayUsage( "disp_lmsamples",g_DispLightmapSamplePositions.Count(),0,sizeof( g_DispLightmapSamplePositions[0] ) );
+
+ totalmemory += ArrayUsage( "faces", numfaces, ENTRIES(dfaces), ENTRYSIZE(dfaces) );
+ totalmemory += ArrayUsage( "hdr faces", numfaces_hdr, ENTRIES(dfaces_hdr), ENTRYSIZE(dfaces_hdr) );
+ totalmemory += ArrayUsage( "origfaces", numorigfaces, ENTRIES(dorigfaces), ENTRYSIZE(dorigfaces) ); // original faces
+ totalmemory += ArrayUsage( "leaves", numleafs, ENTRIES(dleafs), ENTRYSIZE(dleafs) );
+ totalmemory += ArrayUsage( "leaffaces", numleaffaces, ENTRIES(dleaffaces), ENTRYSIZE(dleaffaces) );
+ totalmemory += ArrayUsage( "leafbrushes", numleafbrushes, ENTRIES(dleafbrushes), ENTRYSIZE(dleafbrushes) );
+ totalmemory += ArrayUsage( "areas", numareas, ENTRIES(dareas), ENTRYSIZE(dareas) );
+ totalmemory += ArrayUsage( "surfedges", numsurfedges, ENTRIES(dsurfedges), ENTRYSIZE(dsurfedges) );
+ totalmemory += ArrayUsage( "edges", numedges, ENTRIES(dedges), ENTRYSIZE(dedges) );
+ totalmemory += ArrayUsage( "LDR worldlights", numworldlightsLDR, ENTRIES(dworldlightsLDR), ENTRYSIZE(dworldlightsLDR) );
+ totalmemory += ArrayUsage( "HDR worldlights", numworldlightsHDR, ENTRIES(dworldlightsHDR), ENTRYSIZE(dworldlightsHDR) );
+
+ totalmemory += ArrayUsage( "leafwaterdata", numleafwaterdata,ENTRIES(dleafwaterdata), ENTRYSIZE(dleafwaterdata) );
+ totalmemory += ArrayUsage( "waterstrips", g_numprimitives,ENTRIES(g_primitives), ENTRYSIZE(g_primitives) );
+ totalmemory += ArrayUsage( "waterverts", g_numprimverts, ENTRIES(g_primverts), ENTRYSIZE(g_primverts) );
+ totalmemory += ArrayUsage( "waterindices", g_numprimindices,ENTRIES(g_primindices),ENTRYSIZE(g_primindices) );
+ totalmemory += ArrayUsage( "cubemapsamples", g_nCubemapSamples,ENTRIES(g_CubemapSamples),ENTRYSIZE(g_CubemapSamples) );
+ totalmemory += ArrayUsage( "overlays", g_nOverlayCount, ENTRIES(g_Overlays), ENTRYSIZE(g_Overlays) );
+
+ totalmemory += GlobUsage( "LDR lightdata", dlightdataLDR.Count(), 0 );
+ totalmemory += GlobUsage( "HDR lightdata", dlightdataHDR.Count(), 0 );
+ totalmemory += GlobUsage( "visdata", visdatasize, sizeof(dvisdata) );
+ totalmemory += GlobUsage( "entdata", dentdata.Count(), 384*1024 ); // goal is <384K
+
+ totalmemory += ArrayUsage( "LDR ambient table", g_LeafAmbientIndexLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexLDR[0] ) );
+ totalmemory += ArrayUsage( "HDR ambient table", g_LeafAmbientIndexHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientIndexHDR[0] ) );
+ totalmemory += ArrayUsage( "LDR leaf ambient lighting", g_LeafAmbientLightingLDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingLDR[0] ) );
+ totalmemory += ArrayUsage( "HDR leaf ambient lighting", g_LeafAmbientLightingHDR.Count(), MAX_MAP_LEAFS, sizeof( g_LeafAmbientLightingHDR[0] ) );
+
+ totalmemory += ArrayUsage( "occluders", g_OccluderData.Count(), 0, sizeof( g_OccluderData[0] ) );
+ totalmemory += ArrayUsage( "occluder polygons", g_OccluderPolyData.Count(), 0, sizeof( g_OccluderPolyData[0] ) );
+ totalmemory += ArrayUsage( "occluder vert ind",g_OccluderVertexIndices.Count(),0, sizeof( g_OccluderVertexIndices[0] ) );
+
+ GameLumpHandle_t h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "detail props", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROP_LIGHTING_HDR );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "HDR dtl prp lght", 1, g_GameLumps.GameLumpSize(h) );
+ h = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if (h != g_GameLumps.InvalidGameLump())
+ totalmemory += GlobUsage( "static props", 1, g_GameLumps.GameLumpSize(h) );
+
+ totalmemory += GlobUsage( "pakfile", GetPakFile()->EstimateSize(), 0 );
+ // HACKHACK: Set physics limit at 4MB, in reality this is totally dynamic
+ totalmemory += GlobUsage( "physics", g_PhysCollideSize, 4*1024*1024 );
+ totalmemory += GlobUsage( "physics terrain", g_PhysDispSize, 1*1024*1024 );
+
+ Msg( "\nLevel flags = %x\n", g_LevelFlags );
+
+ Msg( "\n" );
+
+ int triangleCount = 0;
+
+ for ( int i = 0; i < numfaces; i++ )
+ {
+ // face tris = numedges - 2
+ triangleCount += dfaces[i].numedges - 2;
+ }
+ Msg("Total triangle count: %d\n", triangleCount );
+
+ // UNDONE:
+ // areaportals, portals, texdata, clusters, worldlights, portalverts
+}
+
+/*
+=============
+PrintBSPPackDirectory
+
+Dumps a list of files stored in the bsp pack.
+=============
+*/
+void PrintBSPPackDirectory( void )
+{
+ GetPakFile()->PrintDirectory();
+}
+
+
+//============================================
+
+int num_entities;
+entity_t entities[MAX_MAP_ENTITIES];
+
+void StripTrailing (char *e)
+{
+ char *s;
+
+ s = e + strlen(e)-1;
+ while (s >= e && *s <= 32)
+ {
+ *s = 0;
+ s--;
+ }
+}
+
+/*
+=================
+ParseEpair
+=================
+*/
+epair_t *ParseEpair (void)
+{
+ epair_t *e;
+
+ e = (epair_t*)malloc (sizeof(epair_t));
+ memset (e, 0, sizeof(epair_t));
+
+ if (strlen(token) >= MAX_KEY-1)
+ Error ("ParseEpar: token too long");
+ e->key = copystring(token);
+
+ GetToken (false);
+ if (strlen(token) >= MAX_VALUE-1)
+ Error ("ParseEpar: token too long");
+ e->value = copystring(token);
+
+ // strip trailing spaces
+ StripTrailing (e->key);
+ StripTrailing (e->value);
+
+ return e;
+}
+
+
+/*
+================
+ParseEntity
+================
+*/
+qboolean ParseEntity (void)
+{
+ epair_t *e;
+ entity_t *mapent;
+
+ if (!GetToken (true))
+ return false;
+
+ if (Q_stricmp (token, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ mapent = &entities[num_entities];
+ num_entities++;
+
+ do
+ {
+ if (!GetToken (true))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!Q_stricmp (token, "}") )
+ break;
+ e = ParseEpair ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } while (1);
+
+ return true;
+}
+
+/*
+================
+ParseEntities
+
+Parses the dentdata string into entities
+================
+*/
+void ParseEntities (void)
+{
+ num_entities = 0;
+ ParseFromMemory (dentdata.Base(), dentdata.Count());
+
+ while (ParseEntity ())
+ {
+ }
+}
+
+
+/*
+================
+UnparseEntities
+
+Generates the dentdata string from all the entities
+================
+*/
+void UnparseEntities (void)
+{
+ epair_t *ep;
+ char line[2048];
+ int i;
+ char key[1024], value[1024];
+
+ CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ buffer.EnsureCapacity( 256 * 1024 );
+
+ for (i=0 ; i<num_entities ; i++)
+ {
+ ep = entities[i].epairs;
+ if (!ep)
+ continue; // ent got removed
+
+ buffer.PutString( "{\n" );
+
+ for (ep = entities[i].epairs ; ep ; ep=ep->next)
+ {
+ strcpy (key, ep->key);
+ StripTrailing (key);
+ strcpy (value, ep->value);
+ StripTrailing (value);
+
+ sprintf(line, "\"%s\" \"%s\"\n", key, value);
+ buffer.PutString( line );
+ }
+ buffer.PutString("}\n");
+ }
+ int entdatasize = buffer.TellPut()+1;
+
+ dentdata.SetSize( entdatasize );
+ memcpy( dentdata.Base(), buffer.Base(), entdatasize-1 );
+ dentdata[entdatasize-1] = 0;
+}
+
+void PrintEntity (entity_t *ent)
+{
+ epair_t *ep;
+
+ Msg ("------- entity %p -------\n", ent);
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ {
+ Msg ("%s = %s\n", ep->key, ep->value);
+ }
+
+}
+
+void SetKeyValue(entity_t *ent, const char *key, const char *value)
+{
+ epair_t *ep;
+
+ for (ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ {
+ free (ep->value);
+ ep->value = copystring(value);
+ return;
+ }
+ ep = (epair_t*)malloc (sizeof(*ep));
+ ep->next = ent->epairs;
+ ent->epairs = ep;
+ ep->key = copystring(key);
+ ep->value = copystring(value);
+}
+
+char *ValueForKey (entity_t *ent, char *key)
+{
+ for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ return ep->value;
+ return "";
+}
+
+vec_t FloatForKey (entity_t *ent, char *key)
+{
+ char *k = ValueForKey (ent, key);
+ return atof(k);
+}
+
+vec_t FloatForKeyWithDefault (entity_t *ent, char *key, float default_value)
+{
+ for (epair_t *ep=ent->epairs ; ep ; ep=ep->next)
+ if (!Q_stricmp (ep->key, key) )
+ return atof( ep->value );
+ return default_value;
+}
+
+
+
+int IntForKey (entity_t *ent, char *key)
+{
+ char *k = ValueForKey (ent, key);
+ return atol(k);
+}
+
+int IntForKeyWithDefault(entity_t *ent, char *key, int nDefault )
+{
+ char *k = ValueForKey (ent, key);
+ if ( !k[0] )
+ return nDefault;
+ return atol(k);
+}
+
+void GetVectorForKey (entity_t *ent, char *key, Vector& vec)
+{
+
+ char *k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ double v1, v2, v3;
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ vec[0] = v1;
+ vec[1] = v2;
+ vec[2] = v3;
+}
+
+void GetVector2DForKey (entity_t *ent, char *key, Vector2D& vec)
+{
+ double v1, v2;
+
+ char *k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = 0;
+ sscanf (k, "%lf %lf", &v1, &v2);
+ vec[0] = v1;
+ vec[1] = v2;
+}
+
+void GetAnglesForKey (entity_t *ent, char *key, QAngle& angle)
+{
+ char *k;
+ double v1, v2, v3;
+
+ k = ValueForKey (ent, key);
+// scanf into doubles, then assign, so it is vec_t size independent
+ v1 = v2 = v3 = 0;
+ sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
+ angle[0] = v1;
+ angle[1] = v2;
+ angle[2] = v3;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void BuildFaceCalcWindingData( dface_t *pFace, int *points )
+{
+ for( int i = 0; i < pFace->numedges; i++ )
+ {
+ int eIndex = dsurfedges[pFace->firstedge+i];
+ if( eIndex < 0 )
+ {
+ points[i] = dedges[-eIndex].v[1];
+ }
+ else
+ {
+ points[i] = dedges[eIndex].v[0];
+ }
+ }
+}
+
+
+void TriStripToTriList(
+ unsigned short const *pTriStripIndices,
+ int nTriStripIndices,
+ unsigned short **pTriListIndices,
+ int *pnTriListIndices )
+{
+ int nMaxTriListIndices = (nTriStripIndices - 2) * 3;
+ *pTriListIndices = new unsigned short[ nMaxTriListIndices ];
+ *pnTriListIndices = 0;
+
+ for( int i=0; i < nTriStripIndices - 2; i++ )
+ {
+ if( pTriStripIndices[i] == pTriStripIndices[i+1] ||
+ pTriStripIndices[i] == pTriStripIndices[i+2] ||
+ pTriStripIndices[i+1] == pTriStripIndices[i+2] )
+ {
+ }
+ else
+ {
+ // Flip odd numbered tris..
+ if( i & 1 )
+ {
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
+ }
+ else
+ {
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+1];
+ (*pTriListIndices)[(*pnTriListIndices)++] = pTriStripIndices[i+2];
+ }
+ }
+ }
+}
+
+
+void CalcTextureCoordsAtPoints(
+ float const texelsPerWorldUnits[2][4],
+ int const subtractOffset[2],
+ Vector const *pPoints,
+ int const nPoints,
+ Vector2D *pCoords )
+{
+ for( int i=0; i < nPoints; i++ )
+ {
+ for( int iCoord=0; iCoord < 2; iCoord++ )
+ {
+ float *pDestCoord = &pCoords[i][iCoord];
+
+ *pDestCoord = 0;
+ for( int iDot=0; iDot < 3; iDot++ )
+ *pDestCoord += pPoints[i][iDot] * texelsPerWorldUnits[iCoord][iDot];
+
+ *pDestCoord += texelsPerWorldUnits[iCoord][3];
+ *pDestCoord -= subtractOffset[iCoord];
+ }
+ }
+}
+
+
+/*
+================
+CalcFaceExtents
+
+Fills in s->texmins[] and s->texsize[]
+================
+*/
+void CalcFaceExtents(dface_t *s, int lightmapTextureMinsInLuxels[2], int lightmapTextureSizeInLuxels[2])
+{
+ vec_t mins[2], maxs[2], val=0;
+ int i,j, e=0;
+ dvertex_t *v=NULL;
+ texinfo_t *tex=NULL;
+
+ mins[0] = mins[1] = 1e24;
+ maxs[0] = maxs[1] = -1e24;
+
+ tex = &texinfo[s->texinfo];
+
+ for (i=0 ; i<s->numedges ; i++)
+ {
+ e = dsurfedges[s->firstedge+i];
+ if (e >= 0)
+ v = dvertexes + dedges[e].v[0];
+ else
+ v = dvertexes + dedges[-e].v[1];
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = v->point[0] * tex->lightmapVecsLuxelsPerWorldUnits[j][0] +
+ v->point[1] * tex->lightmapVecsLuxelsPerWorldUnits[j][1] +
+ v->point[2] * tex->lightmapVecsLuxelsPerWorldUnits[j][2] +
+ tex->lightmapVecsLuxelsPerWorldUnits[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ int nMaxLightmapDim = (s->dispinfo == -1) ? MAX_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER;
+ for (i=0 ; i<2 ; i++)
+ {
+ mins[i] = ( float )floor( mins[i] );
+ maxs[i] = ( float )ceil( maxs[i] );
+
+ lightmapTextureMinsInLuxels[i] = ( int )mins[i];
+ lightmapTextureSizeInLuxels[i] = ( int )( maxs[i] - mins[i] );
+ if( lightmapTextureSizeInLuxels[i] > nMaxLightmapDim + 1 )
+ {
+ Vector point = vec3_origin;
+ for (int j=0 ; j<s->numedges ; j++)
+ {
+ e = dsurfedges[s->firstedge+j];
+ v = (e<0)?dvertexes + dedges[-e].v[1] : dvertexes + dedges[e].v[0];
+ point += v->point;
+ Warning( "Bad surface extents point: %f %f %f\n", v->point.x, v->point.y, v->point.z );
+ }
+ point *= 1.0f/s->numedges;
+ 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",
+ TexDataStringTable_GetString( dtexdata[texinfo[s->texinfo].texdata].nameStringTableID ),
+ point.x, point.y, point.z,
+ ( int )i,
+ ( int )lightmapTextureSizeInLuxels[i],
+ ( int )( nMaxLightmapDim + 1 )
+ );
+ }
+ }
+}
+
+
+void UpdateAllFaceLightmapExtents()
+{
+ for( int i=0; i < numfaces; i++ )
+ {
+ dface_t *pFace = &dfaces[i];
+
+ if ( texinfo[pFace->texinfo].flags & (SURF_SKY|SURF_NOLIGHT) )
+ continue; // non-lit texture
+
+ CalcFaceExtents( pFace, pFace->m_LightmapTextureMinsInLuxels, pFace->m_LightmapTextureSizeInLuxels );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Helper class to iterate over leaves, used by tools
+//
+//-----------------------------------------------------------------------------
+
+#define TEST_EPSILON (0.03125)
+
+
+class CToolBSPTree : public ISpatialQuery
+{
+public:
+ // Returns the number of leaves
+ int LeafCount() const;
+
+ // Enumerates the leaves along a ray, box, etc.
+ bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
+ bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of leaves
+//-----------------------------------------------------------------------------
+
+int CToolBSPTree::LeafCount() const
+{
+ return numleafs;
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerates the leaves at a point
+//-----------------------------------------------------------------------------
+
+bool CToolBSPTree::EnumerateLeavesAtPoint( Vector const& pt,
+ ISpatialLeafEnumerator* pEnum, int context )
+{
+ int node = 0;
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if (DotProduct( pPlane->normal, pt ) <= pPlane->dist)
+ {
+ node = pNode->children[1];
+ }
+ else
+ {
+ node = pNode->children[0];
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerates the leaves in a box
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesInBox_R( int node, Vector const& mins,
+ Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
+{
+ Vector cornermin, cornermax;
+
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ // Arbitrary split plane here
+ for (int i = 0; i < 3; ++i)
+ {
+ if (pPlane->normal[i] >= 0)
+ {
+ cornermin[i] = mins[i];
+ cornermax[i] = maxs[i];
+ }
+ else
+ {
+ cornermin[i] = maxs[i];
+ cornermax[i] = mins[i];
+ }
+ }
+
+ if ( (DotProduct( pPlane->normal, cornermax ) - pPlane->dist) <= -TEST_EPSILON )
+ {
+ node = pNode->children[1];
+ }
+ else if ( (DotProduct( pPlane->normal, cornermin ) - pPlane->dist) >= TEST_EPSILON )
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ if (!EnumerateLeavesInBox_R( pNode->children[0], mins, maxs, pEnum, context ))
+ {
+ return false;
+ }
+
+ return EnumerateLeavesInBox_R( pNode->children[1], mins, maxs, pEnum, context );
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs,
+ ISpatialLeafEnumerator* pEnum, int context )
+{
+ return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
+}
+
+//-----------------------------------------------------------------------------
+// Enumerate leaves within a sphere
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesInSphere_R( int node, Vector const& origin,
+ float radius, ISpatialLeafEnumerator* pEnum, int context )
+{
+ while( node >= 0 )
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if (DotProduct( pPlane->normal, origin ) + radius - pPlane->dist <= -TEST_EPSILON )
+ {
+ node = pNode->children[1];
+ }
+ else if (DotProduct( pPlane->normal, origin ) - radius - pPlane->dist >= TEST_EPSILON )
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ if (!EnumerateLeavesInSphere_R( pNode->children[0],
+ origin, radius, pEnum, context ))
+ {
+ return false;
+ }
+
+ return EnumerateLeavesInSphere_R( pNode->children[1],
+ origin, radius, pEnum, context );
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
+{
+ return EnumerateLeavesInSphere_R( 0, center, radius, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enumerate leaves along a ray
+//-----------------------------------------------------------------------------
+
+static bool EnumerateLeavesAlongRay_R( int node, Ray_t const& ray,
+ Vector const& start, Vector const& end, ISpatialLeafEnumerator* pEnum, int context )
+{
+ float front,back;
+
+ while (node >= 0)
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if ( pPlane->type <= PLANE_Z )
+ {
+ front = start[pPlane->type] - pPlane->dist;
+ back = end[pPlane->type] - pPlane->dist;
+ }
+ else
+ {
+ front = DotProduct(start, pPlane->normal) - pPlane->dist;
+ back = DotProduct(end, pPlane->normal) - pPlane->dist;
+ }
+
+ if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
+ {
+ node = pNode->children[1];
+ }
+ else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ // test the front side first
+ bool side = front < 0;
+
+ // Compute intersection point based on the original ray
+ float splitfrac;
+ float denom = DotProduct( ray.m_Delta, pPlane->normal );
+ if ( denom == 0.0f )
+ {
+ splitfrac = 1.0f;
+ }
+ else
+ {
+ splitfrac = ( pPlane->dist - DotProduct( ray.m_Start, pPlane->normal ) ) / denom;
+ if (splitfrac < 0)
+ splitfrac = 0;
+ else if (splitfrac > 1)
+ splitfrac = 1;
+ }
+
+ // Compute the split point
+ Vector split;
+ VectorMA( ray.m_Start, splitfrac, ray.m_Delta, split );
+
+ bool r = EnumerateLeavesAlongRay_R (pNode->children[side], ray, start, split, pEnum, context );
+ if (!r)
+ return r;
+ return EnumerateLeavesAlongRay_R (pNode->children[!side], ray, split, end, pEnum, context);
+ }
+ }
+
+ return pEnum->EnumerateLeaf( - node - 1, context );
+}
+
+bool CToolBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
+{
+ if (!ray.m_IsSwept)
+ {
+ Vector mins, maxs;
+ VectorAdd( ray.m_Start, ray.m_Extents, maxs );
+ VectorSubtract( ray.m_Start, ray.m_Extents, mins );
+
+ return EnumerateLeavesInBox_R( 0, mins, maxs, pEnum, context );
+ }
+
+ // FIXME: Extruded ray not implemented yet
+ Assert( ray.m_IsRay );
+
+ Vector end;
+ VectorAdd( ray.m_Start, ray.m_Delta, end );
+ return EnumerateLeavesAlongRay_R( 0, ray, ray.m_Start, end, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton accessor
+//-----------------------------------------------------------------------------
+
+ISpatialQuery* ToolBSPTree()
+{
+ static CToolBSPTree s_ToolBSPTree;
+ return &s_ToolBSPTree;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Enumerates nodes in front to back order...
+//-----------------------------------------------------------------------------
+
+// FIXME: Do we want this in the IBSPTree interface?
+
+static bool EnumerateNodesAlongRay_R( int node, Ray_t const& ray, float start, float end,
+ IBSPNodeEnumerator* pEnum, int context )
+{
+ float front, back;
+ float startDotN, deltaDotN;
+
+ while (node >= 0)
+ {
+ dnode_t* pNode = &dnodes[node];
+ dplane_t* pPlane = &dplanes[pNode->planenum];
+
+ if ( pPlane->type <= PLANE_Z )
+ {
+ startDotN = ray.m_Start[pPlane->type];
+ deltaDotN = ray.m_Delta[pPlane->type];
+ }
+ else
+ {
+ startDotN = DotProduct( ray.m_Start, pPlane->normal );
+ deltaDotN = DotProduct( ray.m_Delta, pPlane->normal );
+ }
+
+ front = startDotN + start * deltaDotN - pPlane->dist;
+ back = startDotN + end * deltaDotN - pPlane->dist;
+
+ if (front <= -TEST_EPSILON && back <= -TEST_EPSILON)
+ {
+ node = pNode->children[1];
+ }
+ else if (front >= TEST_EPSILON && back >= TEST_EPSILON)
+ {
+ node = pNode->children[0];
+ }
+ else
+ {
+ // test the front side first
+ bool side = front < 0;
+
+ // Compute intersection point based on the original ray
+ float splitfrac;
+ if ( deltaDotN == 0.0f )
+ {
+ splitfrac = 1.0f;
+ }
+ else
+ {
+ splitfrac = ( pPlane->dist - startDotN ) / deltaDotN;
+ if (splitfrac < 0.0f)
+ splitfrac = 0.0f;
+ else if (splitfrac > 1.0f)
+ splitfrac = 1.0f;
+ }
+
+ bool r = EnumerateNodesAlongRay_R (pNode->children[side], ray, start, splitfrac, pEnum, context );
+ if (!r)
+ return r;
+
+ // Visit the node...
+ if (!pEnum->EnumerateNode( node, ray, splitfrac, context ))
+ return false;
+
+ return EnumerateNodesAlongRay_R (pNode->children[!side], ray, splitfrac, end, pEnum, context);
+ }
+ }
+
+ // Visit the leaf...
+ return pEnum->EnumerateLeaf( - node - 1, ray, start, end, context );
+}
+
+
+bool EnumerateNodesAlongRay( Ray_t const& ray, IBSPNodeEnumerator* pEnum, int context )
+{
+ Vector end;
+ VectorAdd( ray.m_Start, ray.m_Delta, end );
+ return EnumerateNodesAlongRay_R( 0, ray, 0.0f, 1.0f, pEnum, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Helps us find all leaves associated with a particular cluster
+//-----------------------------------------------------------------------------
+CUtlVector<clusterlist_t> g_ClusterLeaves;
+
+void BuildClusterTable( void )
+{
+ int i, j;
+ int leafCount;
+ int leafList[MAX_MAP_LEAFS];
+
+ g_ClusterLeaves.SetCount( dvis->numclusters );
+ for ( i = 0; i < dvis->numclusters; i++ )
+ {
+ leafCount = 0;
+ for ( j = 0; j < numleafs; j++ )
+ {
+ if ( dleafs[j].cluster == i )
+ {
+ leafList[ leafCount ] = j;
+ leafCount++;
+ }
+ }
+
+ g_ClusterLeaves[i].leafCount = leafCount;
+ if ( leafCount )
+ {
+ g_ClusterLeaves[i].leafs.SetCount( leafCount );
+ memcpy( g_ClusterLeaves[i].leafs.Base(), leafList, sizeof(int) * leafCount );
+ }
+ }
+}
+
+// There's a version of this in host.cpp!!! Make sure that they match.
+void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int dxlevel, int maxLength )
+{
+ Q_StripExtension( pMapPath, pPlatformMapPath, maxLength );
+
+// if( dxlevel <= 60 )
+// {
+// Q_strncat( pPlatformMapPath, "_dx60", maxLength, COPY_ALL_CHARACTERS );
+// }
+
+ Q_strncat( pPlatformMapPath, ".bsp", maxLength, COPY_ALL_CHARACTERS );
+}
+
+// There's a version of this in checksum_engine.cpp!!! Make sure that they match.
+static bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
+{
+ byte chunk[1024];
+ lump_t *curLump;
+
+ FileHandle_t fp = g_pFileSystem->Open( pszFileName, "rb" );
+ if ( !fp )
+ return false;
+
+ // CRC across all lumps except for the Entities lump
+ for ( int l = 0; l < HEADER_LUMPS; ++l )
+ {
+ if (l == LUMP_ENTITIES)
+ continue;
+
+ curLump = &g_pBSPHeader->lumps[l];
+ unsigned int nSize = curLump->filelen;
+
+ g_pFileSystem->Seek( fp, curLump->fileofs, FILESYSTEM_SEEK_HEAD );
+
+ // Now read in 1K chunks
+ while ( nSize > 0 )
+ {
+ int nBytesRead = 0;
+
+ if ( nSize > 1024 )
+ nBytesRead = g_pFileSystem->Read( chunk, 1024, fp );
+ else
+ nBytesRead = g_pFileSystem->Read( chunk, nSize, fp );
+
+ // If any data was received, CRC it.
+ if ( nBytesRead > 0 )
+ {
+ nSize -= nBytesRead;
+ CRC32_ProcessBuffer( crcvalue, chunk, nBytesRead );
+ }
+ else
+ {
+ g_pFileSystem->Close( fp );
+ return false;
+ }
+ }
+ }
+
+ g_pFileSystem->Close( fp );
+ return true;
+}
+
+
+void SetHDRMode( bool bHDR )
+{
+ g_bHDR = bHDR;
+ if ( bHDR )
+ {
+ pdlightdata = &dlightdataHDR;
+ g_pLeafAmbientLighting = &g_LeafAmbientLightingHDR;
+ g_pLeafAmbientIndex = &g_LeafAmbientIndexHDR;
+ pNumworldlights = &numworldlightsHDR;
+ dworldlights = dworldlightsHDR;
+#ifdef VRAD
+ extern void VRadDetailProps_SetHDRMode( bool bHDR );
+ VRadDetailProps_SetHDRMode( bHDR );
+#endif
+ }
+ else
+ {
+ pdlightdata = &dlightdataLDR;
+ g_pLeafAmbientLighting = &g_LeafAmbientLightingLDR;
+ g_pLeafAmbientIndex = &g_LeafAmbientIndexLDR;
+ pNumworldlights = &numworldlightsLDR;
+ dworldlights = dworldlightsLDR;
+#ifdef VRAD
+ extern void VRadDetailProps_SetHDRMode( bool bHDR );
+ VRadDetailProps_SetHDRMode( bHDR );
+#endif
+ }
+}
+
+bool SwapVHV( void *pDestBase, void *pSrcBase )
+{
+ byte *pDest = (byte*)pDestBase;
+ byte *pSrc = (byte*)pSrcBase;
+
+ HardwareVerts::FileHeader_t *pHdr = (HardwareVerts::FileHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
+ g_Swap.SwapFieldsToTargetEndian<HardwareVerts::FileHeader_t>( (HardwareVerts::FileHeader_t*)pDest, (HardwareVerts::FileHeader_t*)pSrc );
+ pSrc += sizeof(HardwareVerts::FileHeader_t);
+ pDest += sizeof(HardwareVerts::FileHeader_t);
+
+ // This swap is pretty format specific
+ Assert( pHdr->m_nVersion == VHV_VERSION );
+ if ( pHdr->m_nVersion != VHV_VERSION )
+ return false;
+
+ HardwareVerts::MeshHeader_t *pSrcMesh = (HardwareVerts::MeshHeader_t*)pSrc;
+ HardwareVerts::MeshHeader_t *pDestMesh = (HardwareVerts::MeshHeader_t*)pDest;
+ HardwareVerts::MeshHeader_t *pMesh = (HardwareVerts::MeshHeader_t*)( g_bSwapOnLoad ? pDest : pSrc );
+ for ( int i = 0; i < pHdr->m_nMeshes; ++i, ++pMesh, ++pSrcMesh, ++pDestMesh )
+ {
+ g_Swap.SwapFieldsToTargetEndian( pDestMesh, pSrcMesh );
+
+ pSrc = (byte*)pSrcBase + pMesh->m_nOffset;
+ pDest = (byte*)pDestBase + pMesh->m_nOffset;
+
+ // Swap as a buffer of integers
+ // (source is bgra for an Intel swap to argb. PowerPC won't swap, so we need argb source.
+ g_Swap.SwapBufferToTargetEndian<int>( (int*)pDest, (int*)pSrc, pMesh->m_nVertexes );
+ }
+ return true;
+}
+
+const char *ResolveStaticPropToModel( const char *pPropName )
+{
+ // resolve back to static prop
+ int iProp = -1;
+
+ // filename should be sp_???.vhv or sp_hdr_???.vhv
+ if ( V_strnicmp( pPropName, "sp_", 3 ) )
+ {
+ return NULL;
+ }
+ const char *pPropNumber = V_strrchr( pPropName, '_' );
+ if ( pPropNumber )
+ {
+ sscanf( pPropNumber+1, "%d.vhv", &iProp );
+ }
+ else
+ {
+ return NULL;
+ }
+
+ // look up the prop to get to the actual model
+ if ( iProp < 0 || iProp >= g_StaticPropInstances.Count() )
+ {
+ // prop out of range
+ return NULL;
+ }
+ int iModel = g_StaticPropInstances[iProp];
+ if ( iModel < 0 || iModel >= g_StaticPropNames.Count() )
+ {
+ // model out of range
+ return NULL;
+ }
+
+ return g_StaticPropNames[iModel].String();
+}
+
+//-----------------------------------------------------------------------------
+// Iterate files in pak file, distribute to converters
+// pak file will be ready for serialization upon completion
+//-----------------------------------------------------------------------------
+void ConvertPakFileContents( const char *pInFilename )
+{
+ IZip *newPakFile = IZip::CreateZip( NULL );
+
+ CUtlBuffer sourceBuf;
+ CUtlBuffer targetBuf;
+ bool bConverted;
+ CUtlVector< CUtlString > hdrFiles;
+
+ int id = -1;
+ int fileSize;
+ while ( 1 )
+ {
+ char relativeName[MAX_PATH];
+ id = GetNextFilename( GetPakFile(), id, relativeName, sizeof( relativeName ), fileSize );
+ if ( id == -1)
+ break;
+
+ bConverted = false;
+ sourceBuf.Purge();
+ targetBuf.Purge();
+
+ const char* pExtension = V_GetFileExtension( relativeName );
+ const char* pExt = 0;
+
+ bool bOK = ReadFileFromPak( GetPakFile(), relativeName, false, sourceBuf );
+ if ( !bOK )
+ {
+ Warning( "Failed to load '%s' from lump pak for conversion or copy in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ if ( pExtension && !V_stricmp( pExtension, "vtf" ) )
+ {
+ bOK = g_pVTFConvertFunc( relativeName, sourceBuf, targetBuf, g_pCompressFunc );
+ if ( !bOK )
+ {
+ Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ bConverted = true;
+ pExt = ".vtf";
+ }
+ else if ( pExtension && !V_stricmp( pExtension, "vhv" ) )
+ {
+ CUtlBuffer tempBuffer;
+ if ( g_pVHVFixupFunc )
+ {
+ // caller supplied a fixup
+ const char *pModelName = ResolveStaticPropToModel( relativeName );
+ if ( !pModelName )
+ {
+ Warning( "Static Prop '%s' failed to resolve actual model in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+
+ // output temp buffer may shrink, must use TellPut() to determine size
+ bOK = g_pVHVFixupFunc( relativeName, pModelName, sourceBuf, tempBuffer );
+ if ( !bOK )
+ {
+ Warning( "Failed to convert '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+ }
+ else
+ {
+ // use the source buffer as-is
+ tempBuffer.EnsureCapacity( sourceBuf.TellMaxPut() );
+ tempBuffer.Put( sourceBuf.Base(), sourceBuf.TellMaxPut() );
+ }
+
+ // swap the VHV
+ targetBuf.EnsureCapacity( tempBuffer.TellPut() );
+ bOK = SwapVHV( targetBuf.Base(), tempBuffer.Base() );
+ if ( !bOK )
+ {
+ Warning( "Failed to swap '%s' in '%s'.\n", relativeName, pInFilename );
+ continue;
+ }
+ targetBuf.SeekPut( CUtlBuffer::SEEK_HEAD, tempBuffer.TellPut() );
+
+ if ( g_pCompressFunc )
+ {
+ CUtlBuffer compressedBuffer;
+ targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, sizeof( HardwareVerts::FileHeader_t ) );
+ bool bCompressed = g_pCompressFunc( targetBuf, compressedBuffer );
+ if ( bCompressed )
+ {
+ // copy all the header data off
+ CUtlBuffer headerBuffer;
+ headerBuffer.EnsureCapacity( sizeof( HardwareVerts::FileHeader_t ) );
+ headerBuffer.Put( targetBuf.Base(), sizeof( HardwareVerts::FileHeader_t ) );
+
+ // reform the target with the header and then the compressed data
+ targetBuf.Clear();
+ targetBuf.Put( headerBuffer.Base(), sizeof( HardwareVerts::FileHeader_t ) );
+ targetBuf.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ }
+
+ targetBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
+ }
+
+ bConverted = true;
+ pExt = ".vhv";
+ }
+
+ if ( !bConverted )
+ {
+ // straight copy
+ AddBufferToPak( newPakFile, relativeName, sourceBuf.Base(), sourceBuf.TellMaxPut(), false );
+ }
+ else
+ {
+ // converted filename
+ V_StripExtension( relativeName, relativeName, sizeof( relativeName ) );
+ V_strcat( relativeName, ".360", sizeof( relativeName ) );
+ V_strcat( relativeName, pExt, sizeof( relativeName ) );
+ AddBufferToPak( newPakFile, relativeName, targetBuf.Base(), targetBuf.TellMaxPut(), false );
+ }
+
+ if ( V_stristr( relativeName, ".hdr" ) || V_stristr( relativeName, "_hdr" ) )
+ {
+ hdrFiles.AddToTail( relativeName );
+ }
+
+ DevMsg( "Created '%s' in lump pak in '%s'.\n", relativeName, pInFilename );
+ }
+
+ // strip ldr version of hdr files
+ for ( int i=0; i<hdrFiles.Count(); i++ )
+ {
+ char ldrFileName[MAX_PATH];
+
+ strcpy( ldrFileName, hdrFiles[i].String() );
+
+ char *pHDRExtension = V_stristr( ldrFileName, ".hdr" );
+ if ( !pHDRExtension )
+ {
+ pHDRExtension = V_stristr( ldrFileName, "_hdr" );
+ }
+
+ if ( pHDRExtension )
+ {
+ // strip .hdr or _hdr to get ldr filename
+ memcpy( pHDRExtension, pHDRExtension+4, strlen( pHDRExtension+4 )+1 );
+
+ DevMsg( "Stripping LDR: %s\n", ldrFileName );
+ newPakFile->RemoveFileFromZip( ldrFileName );
+ }
+ }
+
+ // discard old pak in favor of new pak
+ IZip::ReleaseZip( s_pakFile );
+ s_pakFile = newPakFile;
+}
+
+void SetAlignedLumpPosition( int lumpnum, int alignment = LUMP_ALIGNMENT )
+{
+ g_pBSPHeader->lumps[lumpnum].fileofs = AlignFilePosition( g_hBSPFile, alignment );
+}
+
+template< class T >
+int SwapLumpToDisk( int fieldType, int lumpnum )
+{
+ if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 )
+ return 0;
+
+ DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
+
+ // lump swap may expand, allocate enough expansion room
+ void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
+
+ // CopyLumpInternal will handle the swap on load case
+ unsigned int fieldSize = ( fieldType == FIELD_VECTOR ) ? sizeof(Vector) : sizeof(T);
+ unsigned int count = CopyLumpInternal<T>( fieldType, lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
+ g_pBSPHeader->lumps[lumpnum].filelen = count * fieldSize;
+
+ if ( g_bSwapOnWrite )
+ {
+ // Swap the lump in place before writing
+ switch( lumpnum )
+ {
+ case LUMP_VISIBILITY:
+ SwapVisibilityLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ break;
+
+ case LUMP_PHYSCOLLIDE:
+ // SwapPhyscollideLump may change size
+ SwapPhyscollideLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ g_pBSPHeader->lumps[lumpnum].filelen = count;
+ break;
+
+ case LUMP_PHYSDISP:
+ SwapPhysdispLump( (byte*)pBuffer, (byte*)pBuffer, count );
+ break;
+
+ default:
+ g_Swap.SwapBufferToTargetEndian( (T*)pBuffer, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].filelen / sizeof(T) );
+ break;
+ }
+ }
+
+ SetAlignedLumpPosition( lumpnum );
+ SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
+
+ free( pBuffer );
+
+ return g_pBSPHeader->lumps[lumpnum].filelen;
+}
+
+template< class T >
+int SwapLumpToDisk( int lumpnum )
+{
+ if ( g_pBSPHeader->lumps[lumpnum].filelen == 0 || g_Lumps.bLumpParsed[lumpnum] )
+ return 0;
+
+ DevMsg( "Swapping %s\n", GetLumpName( lumpnum ) );
+
+ // lump swap may expand, allocate enough room
+ void *pBuffer = malloc( 2*g_pBSPHeader->lumps[lumpnum].filelen );
+
+ // CopyLumpInternal will handle the swap on load case
+ int count = CopyLumpInternal<T>( lumpnum, (T*)pBuffer, g_pBSPHeader->lumps[lumpnum].version );
+ g_pBSPHeader->lumps[lumpnum].filelen = count * sizeof(T);
+
+ if ( g_bSwapOnWrite )
+ {
+ // Swap the lump in place before writing
+ g_Swap.SwapFieldsToTargetEndian( (T*)pBuffer, (T*)pBuffer, count );
+ }
+
+ SetAlignedLumpPosition( lumpnum );
+ SafeWrite( g_hBSPFile, pBuffer, g_pBSPHeader->lumps[lumpnum].filelen );
+ free( pBuffer );
+
+ return g_pBSPHeader->lumps[lumpnum].filelen;
+}
+
+void SwapLeafAmbientLightingLumpToDisk()
+{
+ if ( HasLump( LUMP_LEAF_AMBIENT_INDEX ) || HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
+ {
+ // current version, swap in place
+ if ( HasLump( LUMP_LEAF_AMBIENT_INDEX_HDR ) )
+ {
+ // write HDR
+ SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
+ SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX_HDR );
+
+ // cull LDR
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk< dleafambientlighting_t >( LUMP_LEAF_AMBIENT_LIGHTING );
+ SwapLumpToDisk< dleafambientindex_t >( LUMP_LEAF_AMBIENT_INDEX );
+ }
+ }
+ else
+ {
+ // older ambient lighting version (before index)
+ // load older ambient lighting into memory and build ambient/index
+ // an older leaf version would have already built the new LDR leaf ambient/index
+ int numLeafs = g_pBSPHeader->lumps[LUMP_LEAFS].filelen / sizeof( dleaf_t );
+ LoadLeafAmbientLighting( numLeafs );
+
+ if ( HasLump( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) )
+ {
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING_HDR ) );
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX_HDR ) );
+
+ // write HDR
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingHDR.Base(), g_LeafAmbientLightingHDR.Count() );
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexHDR.Base(), g_LeafAmbientIndexHDR.Count() );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING_HDR );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen = g_LeafAmbientLightingHDR.Count() * sizeof( dleafambientlighting_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientLightingHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING_HDR].filelen );
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX_HDR );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen = g_LeafAmbientIndexHDR.Count() * sizeof( dleafambientindex_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientIndexHDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX_HDR].filelen );
+
+ // mark as processed
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING_HDR] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX_HDR] = true;
+
+ // cull LDR
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_LIGHTING ) );
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAF_AMBIENT_INDEX ) );
+
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientLightingLDR.Base(), g_LeafAmbientLightingLDR.Count() );
+ g_Swap.SwapFieldsToTargetEndian( g_LeafAmbientIndexLDR.Base(), g_LeafAmbientIndexLDR.Count() );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_LIGHTING );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].version = LUMP_LEAF_AMBIENT_LIGHTING_VERSION;
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen = g_LeafAmbientLightingLDR.Count() * sizeof( dleafambientlighting_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientLightingLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_LIGHTING].filelen );
+
+ SetAlignedLumpPosition( LUMP_LEAF_AMBIENT_INDEX );
+ g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen = g_LeafAmbientIndexLDR.Count() * sizeof( dleafambientindex_t );
+ SafeWrite( g_hBSPFile, g_LeafAmbientIndexLDR.Base(), g_pBSPHeader->lumps[LUMP_LEAF_AMBIENT_INDEX].filelen );
+
+ // mark as processed
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_LIGHTING] = true;
+ g_Lumps.bLumpParsed[LUMP_LEAF_AMBIENT_INDEX] = true;
+ }
+
+ g_LeafAmbientLightingLDR.Purge();
+ g_LeafAmbientIndexLDR.Purge();
+ g_LeafAmbientLightingHDR.Purge();
+ g_LeafAmbientIndexHDR.Purge();
+ }
+}
+
+void SwapLeafLumpToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_LEAFS ) );
+
+ // load the leafs
+ int count = LoadLeafs();
+ if ( g_bSwapOnWrite )
+ {
+ g_Swap.SwapFieldsToTargetEndian( dleafs, count );
+ }
+
+ bool bOldLeafVersion = ( LumpVersion( LUMP_LEAFS ) == 0 );
+ if ( bOldLeafVersion )
+ {
+ // version has been converted in the load process
+ // not updating the version ye, SwapLeafAmbientLightingLumpToDisk() can detect
+ g_pBSPHeader->lumps[LUMP_LEAFS].filelen = count * sizeof( dleaf_t );
+ }
+
+ SetAlignedLumpPosition( LUMP_LEAFS );
+ SafeWrite( g_hBSPFile, dleafs, g_pBSPHeader->lumps[LUMP_LEAFS].filelen );
+
+ SwapLeafAmbientLightingLumpToDisk();
+
+ if ( bOldLeafVersion )
+ {
+ // version has been converted in the load process
+ // can now safely change
+ g_pBSPHeader->lumps[LUMP_LEAFS].version = 1;
+ }
+
+#if defined( BSP_USE_LESS_MEMORY )
+ if ( dleafs )
+ {
+ free( dleafs );
+ dleafs = NULL;
+ }
+#endif
+}
+
+void SwapOcclusionLumpToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_OCCLUSION ) );
+
+ LoadOcclusionLump();
+ SetAlignedLumpPosition( LUMP_OCCLUSION );
+ AddOcclusionLump();
+}
+
+void SwapPakfileLumpToDisk( const char *pInFilename )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_PAKFILE ) );
+
+ byte *pakbuffer = NULL;
+ int paksize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, ( void ** )&pakbuffer );
+ if ( paksize > 0 )
+ {
+ GetPakFile()->ActivateByteSwapping( IsX360() );
+ GetPakFile()->ParseFromBuffer( pakbuffer, paksize );
+
+ ConvertPakFileContents( pInFilename );
+ }
+ free( pakbuffer );
+
+ SetAlignedLumpPosition( LUMP_PAKFILE, XBOX_DVD_SECTORSIZE );
+ WritePakFileLump();
+
+ ReleasePakFileLumps();
+}
+
+void SwapGameLumpsToDisk( void )
+{
+ DevMsg( "Swapping %s\n", GetLumpName( LUMP_GAME_LUMP ) );
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+ SetAlignedLumpPosition( LUMP_GAME_LUMP );
+ AddGameLumps();
+}
+
+//-----------------------------------------------------------------------------
+// Generate a table of all static props, used for resolving static prop lighting
+// files back to their actual mdl.
+//-----------------------------------------------------------------------------
+void BuildStaticPropNameTable()
+{
+ g_StaticPropNames.Purge();
+ g_StaticPropInstances.Purge();
+
+ g_GameLumps.ParseGameLump( g_pBSPHeader );
+
+ GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ int nVersion = g_GameLumps.GetGameLumpVersion( hGameLump );
+ if ( nVersion < 4 )
+ {
+ // old unsupported version
+ return;
+ }
+
+ if ( nVersion != 4 && nVersion != 5 && nVersion != 6 )
+ {
+ Error( "Unknown Static Prop Lump version %d!\n", nVersion );
+ }
+
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ // get the model dictionary
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
+ for ( int i = 0; i < count; i++ )
+ {
+ g_StaticPropNames.AddToTail( pStaticPropDictLump[i].m_Name );
+ }
+ pGameLumpData += count * sizeof( StaticPropDictLump_t );
+
+ // skip the leaf list
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ pGameLumpData += count * sizeof( StaticPropLeafLump_t );
+
+ // get the instances
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ for ( int i = 0; i < count; i++ )
+ {
+ int propType;
+ if ( nVersion == 4 )
+ {
+ propType = ((StaticPropLumpV4_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLumpV4_t );
+ }
+ else if ( nVersion == 5 )
+ {
+ propType = ((StaticPropLumpV5_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLumpV5_t );
+ }
+ else
+ {
+ propType = ((StaticPropLump_t *)pGameLumpData)->m_PropType;
+ pGameLumpData += sizeof( StaticPropLump_t );
+ }
+ g_StaticPropInstances.AddToTail( propType );
+ }
+ }
+ }
+
+ g_GameLumps.DestroyAllGameLumps();
+}
+
+int AlignBuffer( CUtlBuffer &buffer, int alignment )
+{
+ unsigned int newPosition = AlignValue( buffer.TellPut(), alignment );
+ int padLength = newPosition - buffer.TellPut();
+ for ( int i = 0; i<padLength; i++ )
+ {
+ buffer.PutChar( '\0' );
+ }
+ return buffer.TellPut();
+}
+
+struct SortedLump_t
+{
+ int lumpNum;
+ lump_t *pLump;
+};
+
+int SortLumpsByOffset( const SortedLump_t *pSortedLumpA, const SortedLump_t *pSortedLumpB )
+{
+ int fileOffsetA = pSortedLumpA->pLump->fileofs;
+ int fileOffsetB = pSortedLumpB->pLump->fileofs;
+
+ int fileSizeA = pSortedLumpA->pLump->filelen;
+ int fileSizeB = pSortedLumpB->pLump->filelen;
+
+ // invalid or empty lumps get sorted together
+ if ( !fileSizeA )
+ {
+ fileOffsetA = 0;
+ }
+ if ( !fileSizeB )
+ {
+ fileOffsetB = 0;
+ }
+
+ // compare by offset, want ascending
+ if ( fileOffsetA < fileOffsetB )
+ {
+ return -1;
+ }
+ else if ( fileOffsetA > fileOffsetB )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+bool CompressGameLump( dheader_t *pInBSPHeader, dheader_t *pOutBSPHeader, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
+{
+ CByteswap byteSwap;
+
+ dgamelumpheader_t* pInGameLumpHeader = (dgamelumpheader_t*)(((byte *)pInBSPHeader) + pInBSPHeader->lumps[LUMP_GAME_LUMP].fileofs);
+ dgamelump_t* pInGameLump = (dgamelump_t*)(pInGameLumpHeader + 1);
+
+ byteSwap.ActivateByteSwapping( true );
+ byteSwap.SwapFieldsToTargetEndian( pInGameLumpHeader );
+ byteSwap.SwapFieldsToTargetEndian( pInGameLump, pInGameLumpHeader->lumpCount );
+
+ unsigned int newOffset = outputBuffer.TellPut();
+ outputBuffer.Put( pInGameLumpHeader, sizeof( dgamelumpheader_t ) );
+ outputBuffer.Put( pInGameLump, pInGameLumpHeader->lumpCount * sizeof( dgamelump_t ) );
+
+ dgamelumpheader_t* pOutGameLumpHeader = (dgamelumpheader_t*)((byte *)outputBuffer.Base() + newOffset);
+ dgamelump_t* pOutGameLump = (dgamelump_t*)(pOutGameLumpHeader + 1);
+
+ // add a dummy terminal gamelump
+ // purposely NOT updating the .filelen to reflect the compressed size, but leaving as original size
+ // callers use the next entry offset to determine compressed size
+ pOutGameLumpHeader->lumpCount++;
+ dgamelump_t dummyLump = { 0 };
+ outputBuffer.Put( &dummyLump, sizeof( dgamelump_t ) );
+
+ for ( int i = 0; i < pInGameLumpHeader->lumpCount; i++ )
+ {
+ CUtlBuffer inputBuffer;
+ CUtlBuffer compressedBuffer;
+
+ pOutGameLump[i].fileofs = AlignBuffer( outputBuffer, 4 );
+
+ if ( pInGameLump[i].filelen )
+ {
+ inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pInGameLump[i].fileofs, pInGameLump[i].filelen, pInGameLump[i].filelen );
+
+ bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
+ if ( bCompressed )
+ {
+ pOutGameLump[i].flags |= GAMELUMPFLAG_COMPRESSED;
+
+ outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ compressedBuffer.Purge();
+ }
+ else
+ {
+ // as is
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ }
+ }
+
+ // fix the dummy terminal lump
+ int lastLump = pOutGameLumpHeader->lumpCount-1;
+ pOutGameLump[lastLump].fileofs = outputBuffer.TellPut();
+
+ // fix the output for 360, swapping it back
+ byteSwap.SwapFieldsToTargetEndian( pOutGameLump, pOutGameLumpHeader->lumpCount );
+ byteSwap.SwapFieldsToTargetEndian( pOutGameLumpHeader );
+
+ pOutBSPHeader->lumps[LUMP_GAME_LUMP].fileofs = newOffset;
+ pOutBSPHeader->lumps[LUMP_GAME_LUMP].filelen = outputBuffer.TellPut() - newOffset;
+
+ return true;
+}
+
+bool CompressBSP( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer, CompressFunc_t pCompressFunc )
+{
+ CByteswap byteSwap;
+
+ dheader_t *pInBSPHeader = (dheader_t *)inputBuffer.Base();
+ if ( pInBSPHeader->ident != BigLong( IDBSPHEADER ) || !pCompressFunc )
+ {
+ // only compress 360 bsp's
+ return false;
+ }
+
+ // bsp is 360, swap the header back
+ byteSwap.ActivateByteSwapping( true );
+ byteSwap.SwapFieldsToTargetEndian( pInBSPHeader );
+
+ // output will be smaller, use input size as upper bound
+ outputBuffer.EnsureCapacity( inputBuffer.TellMaxPut() );
+ outputBuffer.Put( pInBSPHeader, sizeof( dheader_t ) );
+
+ dheader_t *pOutBSPHeader = (dheader_t *)outputBuffer.Base();
+
+ // must adhere to input lump's offset order and process according to that, NOT lump num
+ // sort by offset order
+ CUtlVector< SortedLump_t > sortedLumps;
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ int iIndex = sortedLumps.AddToTail();
+ sortedLumps[iIndex].lumpNum = i;
+ sortedLumps[iIndex].pLump = &pInBSPHeader->lumps[i];
+ }
+ sortedLumps.Sort( SortLumpsByOffset );
+
+ // iterate in sorted order
+ for ( int i = 0; i < HEADER_LUMPS; ++i )
+ {
+ SortedLump_t *pSortedLump = &sortedLumps[i];
+ int lumpNum = pSortedLump->lumpNum;
+
+ if ( !pSortedLump->pLump->filelen )
+ {
+ // degenerate
+ pOutBSPHeader->lumps[lumpNum].fileofs = 0;
+ }
+ else
+ {
+ int alignment = 4;
+ if ( lumpNum == LUMP_PAKFILE )
+ {
+ alignment = 2048;
+ }
+ unsigned int newOffset = AlignBuffer( outputBuffer, alignment );
+
+ // only set by compressed lumps, hides the uncompressed size
+ *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = 0;
+
+ CUtlBuffer inputBuffer;
+ inputBuffer.SetExternalBuffer( ((byte *)pInBSPHeader) + pSortedLump->pLump->fileofs, pSortedLump->pLump->filelen, pSortedLump->pLump->filelen );
+
+ if ( lumpNum == LUMP_GAME_LUMP )
+ {
+ // the game lump has to have each of its components individually compressed
+ CompressGameLump( pInBSPHeader, pOutBSPHeader, outputBuffer, pCompressFunc );
+ }
+ else if ( lumpNum == LUMP_PAKFILE )
+ {
+ // add as is
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ else
+ {
+ CUtlBuffer compressedBuffer;
+ bool bCompressed = pCompressFunc( inputBuffer, compressedBuffer );
+ if ( bCompressed )
+ {
+ // placing the uncompressed size in the unused fourCC, will decode at runtime
+ *((unsigned int *)pOutBSPHeader->lumps[lumpNum].fourCC) = BigLong( inputBuffer.TellPut() );
+ pOutBSPHeader->lumps[lumpNum].filelen = compressedBuffer.TellPut();
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( compressedBuffer.Base(), compressedBuffer.TellPut() );
+ compressedBuffer.Purge();
+ }
+ else
+ {
+ // add as is
+ pOutBSPHeader->lumps[lumpNum].fileofs = newOffset;
+ outputBuffer.Put( inputBuffer.Base(), inputBuffer.TellPut() );
+ }
+ }
+ }
+ }
+
+ // fix the output for 360, swapping it back
+ byteSwap.SetTargetBigEndian( true );
+ byteSwap.SwapFieldsToTargetEndian( pOutBSPHeader );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// For all lumps in a bsp: Loads the lump from file A, swaps it, writes it to file B.
+// This limits the memory used for the swap process which helps the Xbox 360.
+//
+// NOTE: These lumps will be written to the file in exactly the order they appear here,
+// so they can be shifted around if desired for file access optimization.
+//-----------------------------------------------------------------------------
+bool SwapBSPFile( const char *pInFilename, const char *pOutFilename, bool bSwapOnLoad, VTFConvertFunc_t pVTFConvertFunc, VHVFixupFunc_t pVHVFixupFunc, CompressFunc_t pCompressFunc )
+{
+ DevMsg( "Creating %s\n", pOutFilename );
+
+ if ( !g_pFileSystem->FileExists( pInFilename ) )
+ {
+ Warning( "Error! Couldn't open input file %s - BSP swap failed!\n", pInFilename );
+ return false;
+ }
+
+ g_hBSPFile = SafeOpenWrite( pOutFilename );
+ if ( !g_hBSPFile )
+ {
+ Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
+ return false;
+ }
+
+ if ( !pVTFConvertFunc )
+ {
+ Warning( "Error! Missing VTF Conversion function\n" );
+ return false;
+ }
+ g_pVTFConvertFunc = pVTFConvertFunc;
+
+ // optional VHV fixup
+ g_pVHVFixupFunc = pVHVFixupFunc;
+
+ // optional compression callback
+ g_pCompressFunc = pCompressFunc;
+
+ // These must be mutually exclusive
+ g_bSwapOnLoad = bSwapOnLoad;
+ g_bSwapOnWrite = !bSwapOnLoad;
+
+ g_Swap.ActivateByteSwapping( true );
+
+ OpenBSPFile( pInFilename );
+
+ // CRC the bsp first
+ CRC32_t mapCRC;
+ CRC32_Init(&mapCRC);
+ if ( !CRC_MapFile( &mapCRC, pInFilename ) )
+ {
+ Warning( "Failed to CRC the bsp\n" );
+ return false;
+ }
+
+ // hold a dictionary of all the static prop names
+ // this is needed to properly convert any VHV files inside the pak lump
+ BuildStaticPropNameTable();
+
+ // Set the output file pointer after the header
+ dheader_t dummyHeader = { 0 };
+ SafeWrite( g_hBSPFile, &dummyHeader, sizeof( dheader_t ) );
+
+ // To allow for alignment fixups, the lumps will be written to the
+ // output file in the order they appear in this function.
+
+ // NOTE: Flags for 360 !!!MUST!!! be first
+ SwapLumpToDisk< dflagslump_t >( LUMP_MAP_FLAGS );
+
+ // complex lump swaps first or for later contingent data
+ SwapLeafLumpToDisk();
+ SwapOcclusionLumpToDisk();
+ SwapGameLumpsToDisk();
+
+ // Strip dead or non relevant lumps
+ g_pBSPHeader->lumps[LUMP_DISP_LIGHTMAP_ALPHAS].filelen = 0;
+ g_pBSPHeader->lumps[LUMP_FACEIDS].filelen = 0;
+
+ // Strip obsolete LDR in favor of HDR
+ if ( SwapLumpToDisk<dface_t>( LUMP_FACES_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_FACES].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<dface_t>( LUMP_FACES );
+ }
+
+ if ( SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_WORLDLIGHTS].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<dworldlight_t>( LUMP_WORLDLIGHTS );
+ }
+
+ // Simple lump swaps
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSDISP );
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_PHYSCOLLIDE );
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_VISIBILITY );
+ SwapLumpToDisk<dmodel_t>( LUMP_MODELS );
+ SwapLumpToDisk<dvertex_t>( LUMP_VERTEXES );
+ SwapLumpToDisk<dplane_t>( LUMP_PLANES );
+ SwapLumpToDisk<dnode_t>( LUMP_NODES );
+ SwapLumpToDisk<texinfo_t>( LUMP_TEXINFO );
+ SwapLumpToDisk<dtexdata_t>( LUMP_TEXDATA );
+ SwapLumpToDisk<ddispinfo_t>( LUMP_DISPINFO );
+ SwapLumpToDisk<CDispVert>( LUMP_DISP_VERTS );
+ SwapLumpToDisk<CDispTri>( LUMP_DISP_TRIS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS );
+ SwapLumpToDisk<CFaceMacroTextureInfo>( LUMP_FACE_MACRO_TEXTURE_INFO );
+ SwapLumpToDisk<dprimitive_t>( LUMP_PRIMITIVES );
+ SwapLumpToDisk<dprimvert_t>( LUMP_PRIMVERTS );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_PRIMINDICES );
+ SwapLumpToDisk<dface_t>( LUMP_ORIGINALFACES );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFFACES );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFBRUSHES );
+ SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_SURFEDGES );
+ SwapLumpToDisk<dedge_t>( LUMP_EDGES );
+ SwapLumpToDisk<dbrush_t>( LUMP_BRUSHES );
+ SwapLumpToDisk<dbrushside_t>( LUMP_BRUSHSIDES );
+ SwapLumpToDisk<darea_t>( LUMP_AREAS );
+ SwapLumpToDisk<dareaportal_t>( LUMP_AREAPORTALS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_ENTITIES );
+ SwapLumpToDisk<dleafwaterdata_t>( LUMP_LEAFWATERDATA );
+ SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_VERTNORMALS );
+ SwapLumpToDisk<short>( FIELD_SHORT, LUMP_VERTNORMALINDICES );
+ SwapLumpToDisk<float>( FIELD_VECTOR, LUMP_CLIPPORTALVERTS );
+ SwapLumpToDisk<dcubemapsample_t>( LUMP_CUBEMAPS );
+ SwapLumpToDisk<char>( FIELD_CHARACTER, LUMP_TEXDATA_STRING_DATA );
+ SwapLumpToDisk<int>( FIELD_INTEGER, LUMP_TEXDATA_STRING_TABLE );
+ SwapLumpToDisk<doverlay_t>( LUMP_OVERLAYS );
+ SwapLumpToDisk<dwateroverlay_t>( LUMP_WATEROVERLAYS );
+ SwapLumpToDisk<unsigned short>( FIELD_SHORT, LUMP_LEAFMINDISTTOWATER );
+ SwapLumpToDisk<doverlayfade_t>( LUMP_OVERLAY_FADES );
+
+
+ // NOTE: this data placed at the end for the sake of 360:
+ {
+ // NOTE: lighting must be the penultimate lump
+ // (allows 360 to free this memory part-way through map loading)
+ if ( SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING_HDR ) )
+ {
+ g_pBSPHeader->lumps[LUMP_LIGHTING].filelen = 0;
+ }
+ else
+ {
+ // no HDR, keep LDR version
+ SwapLumpToDisk<byte>( FIELD_CHARACTER, LUMP_LIGHTING );
+ }
+ // NOTE: Pakfile for 360 !!!MUST!!! be last
+ SwapPakfileLumpToDisk( pInFilename );
+ }
+
+
+ // Store the crc in the flags lump version field
+ g_pBSPHeader->lumps[LUMP_MAP_FLAGS].version = mapCRC;
+
+ // Pad out the end of the file to a sector boundary for optimal IO
+ AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+
+ // Warn of any lumps that didn't get swapped
+ for ( int i = 0; i < HEADER_LUMPS; ++i )
+ {
+ if ( HasLump( i ) && !g_Lumps.bLumpParsed[i] )
+ {
+ // a new lump got added that needs to have a swap function
+ Warning( "BSP: '%s', %s has no swap or copy function. Discarding!\n", pInFilename, GetLumpName(i) );
+
+ // the data didn't get copied, so don't reference garbage
+ g_pBSPHeader->lumps[i].filelen = 0;
+ }
+ }
+
+ // Write the updated header
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+ g_hBSPFile = 0;
+
+ // Cleanup
+ g_Swap.ActivateByteSwapping( false );
+
+ CloseBSPFile();
+
+ g_StaticPropNames.Purge();
+ g_StaticPropInstances.Purge();
+
+ DevMsg( "Finished BSP Swap\n" );
+
+ // caller provided compress func will further compress compatible lumps
+ if ( pCompressFunc )
+ {
+ CUtlBuffer inputBuffer;
+ if ( !g_pFileSystem->ReadFile( pOutFilename, NULL, inputBuffer ) )
+ {
+ Warning( "Error! Couldn't read file %s - final BSP compression failed!\n", pOutFilename );
+ return false;
+ }
+
+ CUtlBuffer outputBuffer;
+ if ( !CompressBSP( inputBuffer, outputBuffer, pCompressFunc ) )
+ {
+ Warning( "Error! Failed to compress BSP '%s'!\n", pOutFilename );
+ return false;
+ }
+
+ g_hBSPFile = SafeOpenWrite( pOutFilename );
+ if ( !g_hBSPFile )
+ {
+ Warning( "Error! Couldn't open output file %s - BSP swap failed!\n", pOutFilename );
+ return false;
+ }
+ SafeWrite( g_hBSPFile, outputBuffer.Base(), outputBuffer.TellPut() );
+ g_pFileSystem->Close( g_hBSPFile );
+ g_hBSPFile = 0;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Get the pak lump from a BSP
+//-----------------------------------------------------------------------------
+bool GetPakFileLump( const char *pBSPFilename, void **pPakData, int *pPakSize )
+{
+ *pPakData = NULL;
+ *pPakSize = 0;
+
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // determine endian nature
+ dheader_t *pHeader;
+ LoadFile( pBSPFilename, (void **)&pHeader );
+ bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
+ free( pHeader );
+
+ g_bSwapOnLoad = bSwap;
+ g_bSwapOnWrite = !bSwap;
+
+ OpenBSPFile( pBSPFilename );
+
+ if ( g_pBSPHeader->lumps[LUMP_PAKFILE].filelen )
+ {
+ *pPakSize = CopyVariableLump<byte>( FIELD_CHARACTER, LUMP_PAKFILE, pPakData );
+ }
+
+ CloseBSPFile();
+
+ return true;
+}
+
+// compare function for qsort below
+static int LumpOffsetCompare( const void *pElem1, const void *pElem2 )
+{
+ int lump1 = *(byte *)pElem1;
+ int lump2 = *(byte *)pElem2;
+
+ if ( lump1 != lump2 )
+ {
+ // force LUMP_MAP_FLAGS to be first, always
+ if ( lump1 == LUMP_MAP_FLAGS )
+ {
+ return -1;
+ }
+ else if ( lump2 == LUMP_MAP_FLAGS )
+ {
+ return 1;
+ }
+
+ // force LUMP_PAKFILE to be last, always
+ if ( lump1 == LUMP_PAKFILE )
+ {
+ return 1;
+ }
+ else if ( lump2 == LUMP_PAKFILE )
+ {
+ return -1;
+ }
+ }
+
+ int fileOffset1 = g_pBSPHeader->lumps[lump1].fileofs;
+ int fileOffset2 = g_pBSPHeader->lumps[lump2].fileofs;
+
+ // invalid or empty lumps will get sorted together
+ if ( !g_pBSPHeader->lumps[lump1].filelen )
+ {
+ fileOffset1 = 0;
+ }
+
+ if ( !g_pBSPHeader->lumps[lump2].filelen )
+ {
+ fileOffset2 = 0;
+ }
+
+ // compare by offset
+ if ( fileOffset1 < fileOffset2 )
+ {
+ return -1;
+ }
+ else if ( fileOffset1 > fileOffset2 )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Replace the pak lump in a BSP
+//-----------------------------------------------------------------------------
+bool SetPakFileLump( const char *pBSPFilename, const char *pNewFilename, void *pPakData, int pakSize )
+{
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // determine endian nature
+ dheader_t *pHeader;
+ LoadFile( pBSPFilename, (void **)&pHeader );
+ bool bSwap = ( pHeader->ident == BigLong( IDBSPHEADER ) );
+ free( pHeader );
+
+ g_bSwapOnLoad = bSwap;
+ g_bSwapOnWrite = bSwap;
+
+ OpenBSPFile( pBSPFilename );
+
+ // save a copy of the old header
+ // generating a new bsp is a destructive operation
+ dheader_t oldHeader;
+ oldHeader = *g_pBSPHeader;
+
+ g_hBSPFile = SafeOpenWrite( pNewFilename );
+ if ( !g_hBSPFile )
+ {
+ return false;
+ }
+
+ // placeholder only, reset at conclusion
+ WriteData( &oldHeader );
+
+ // lumps must be reserialized in same relative offset order
+ // build sorted order table
+ int readOrder[HEADER_LUMPS];
+ for ( int i=0; i<HEADER_LUMPS; i++ )
+ {
+ readOrder[i] = i;
+ }
+ qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpOffsetCompare );
+
+ for ( int i = 0; i < HEADER_LUMPS; i++ )
+ {
+ int lump = readOrder[i];
+
+ if ( lump == LUMP_PAKFILE )
+ {
+ // pak lump always written last, with special alignment
+ continue;
+ }
+
+ int length = g_pBSPHeader->lumps[lump].filelen;
+ if ( length )
+ {
+ // save the lump data
+ int offset = g_pBSPHeader->lumps[lump].fileofs;
+ SetAlignedLumpPosition( lump );
+ SafeWrite( g_hBSPFile, (byte *)g_pBSPHeader + offset, length );
+ }
+ else
+ {
+ g_pBSPHeader->lumps[lump].fileofs = 0;
+ }
+ }
+
+ // Always write the pak file at the end
+ // Pad out the end of the file to a sector boundary for optimal IO
+ g_pBSPHeader->lumps[LUMP_PAKFILE].fileofs = AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+ g_pBSPHeader->lumps[LUMP_PAKFILE].filelen = pakSize;
+ SafeWrite( g_hBSPFile, pPakData, pakSize );
+
+ // Pad out the end of the file to a sector boundary for optimal IO
+ AlignFilePosition( g_hBSPFile, XBOX_DVD_SECTORSIZE );
+
+ // Write the updated header
+ g_pFileSystem->Seek( g_hBSPFile, 0, FILESYSTEM_SEEK_HEAD );
+ WriteData( g_pBSPHeader );
+ g_pFileSystem->Close( g_hBSPFile );
+
+ CloseBSPFile();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Build a list of files that BSP owns, world/cubemap materials, static props, etc.
+//-----------------------------------------------------------------------------
+bool GetBSPDependants( const char *pBSPFilename, CUtlVector< CUtlString > *pList )
+{
+ if ( !g_pFileSystem->FileExists( pBSPFilename ) )
+ {
+ Warning( "Error! Couldn't open file %s!\n", pBSPFilename );
+ return false;
+ }
+
+ // must be set, but exact hdr not critical for dependant traversal
+ SetHDRMode( false );
+
+ LoadBSPFile( pBSPFilename );
+
+ char szBspName[MAX_PATH];
+ V_FileBase( pBSPFilename, szBspName, sizeof( szBspName ) );
+ V_SetExtension( szBspName, ".bsp", sizeof( szBspName ) );
+
+ // get embedded pak files, and internals
+ char szFilename[MAX_PATH];
+ int fileSize;
+ int fileId = -1;
+ for ( ;; )
+ {
+ fileId = GetPakFile()->GetNextFilename( fileId, szFilename, sizeof( szFilename ), fileSize );
+ if ( fileId == -1 )
+ {
+ break;
+ }
+ pList->AddToTail( szFilename );
+ }
+
+ // get all the world materials
+ for ( int i=0; i<numtexdata; i++ )
+ {
+ const char *pName = TexDataStringTable_GetString( dtexdata[i].nameStringTableID );
+ V_ComposeFileName( "materials", pName, szFilename, sizeof( szFilename ) );
+ V_SetExtension( szFilename, ".vmt", sizeof( szFilename ) );
+ pList->AddToTail( szFilename );
+ }
+
+ // get all the static props
+ GameLumpHandle_t hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+
+ StaticPropDictLump_t *pStaticPropDictLump = (StaticPropDictLump_t *)pGameLumpData;
+ for ( int i=0; i<count; i++ )
+ {
+ pList->AddToTail( pStaticPropDictLump[i].m_Name );
+ }
+ }
+ }
+
+ // get all the detail props
+ hGameLump = g_GameLumps.GetGameLumpHandle( GAMELUMP_DETAIL_PROPS );
+ if ( hGameLump != g_GameLumps.InvalidGameLump() )
+ {
+ byte *pGameLumpData = (byte *)g_GameLumps.GetGameLump( hGameLump );
+ if ( pGameLumpData && g_GameLumps.GameLumpSize( hGameLump ) )
+ {
+ int count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+
+ DetailObjectDictLump_t *pDetailObjectDictLump = (DetailObjectDictLump_t *)pGameLumpData;
+ for ( int i=0; i<count; i++ )
+ {
+ pList->AddToTail( pDetailObjectDictLump[i].m_Name );
+ }
+ pGameLumpData += count * sizeof( DetailObjectDictLump_t );
+
+ if ( g_GameLumps.GetGameLumpVersion( hGameLump ) == 4 )
+ {
+ count = ((int *)pGameLumpData)[0];
+ pGameLumpData += sizeof( int );
+ if ( count )
+ {
+ // All detail prop sprites must lie in the material detail/detailsprites
+ pList->AddToTail( "materials/detail/detailsprites.vmt" );
+ }
+ }
+ }
+ }
+
+ UnloadBSPFile();
+
+ return true;
+}
+