summaryrefslogtreecommitdiff
path: root/engine/cmodel_bsp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/cmodel_bsp.cpp')
-rw-r--r--engine/cmodel_bsp.cpp1306
1 files changed, 1306 insertions, 0 deletions
diff --git a/engine/cmodel_bsp.cpp b/engine/cmodel_bsp.cpp
new file mode 100644
index 0000000..81e9622
--- /dev/null
+++ b/engine/cmodel_bsp.cpp
@@ -0,0 +1,1306 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "tier0/platform.h"
+#include "sysexternal.h"
+#include "cmodel_engine.h"
+#include "dispcoll_common.h"
+#include "modelloader.h"
+#include "common.h"
+#include "zone.h"
+
+// UNDONE: Abstract the texture/material lookup stuff and all of this goes away
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "materialsystem/materialsystem_config.h"
+extern IMaterialSystem *materials;
+
+#include "vphysics_interface.h"
+#include "sys_dll.h"
+#include "tier2/tier2.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern int g_iServerGameDLLVersion;
+IPhysicsSurfaceProps *physprop = NULL;
+IPhysicsCollision *physcollision = NULL;
+
+// local forward declarations
+void CollisionBSPData_LoadTextures( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadTexinfo( CCollisionBSPData *pBSPData, CUtlVector<unsigned short> &map_texinfo );
+void CollisionBSPData_LoadLeafs_Version_0( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadLeafs_Version_1( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadLeafs( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadLeafBrushes( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadPlanes( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadBrushes( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadBrushSides( CCollisionBSPData *pBSPData, CUtlVector<unsigned short> &map_texinfo );
+void CollisionBSPData_LoadSubmodels( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadNodes( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadAreas( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadAreaPortals( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadVisibility( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadEntityString( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadPhysics( CCollisionBSPData *pBSPData );
+void CollisionBSPData_LoadDispInfo( CCollisionBSPData *pBSPData );
+
+
+//=============================================================================
+//
+// Initialization/Destruction Functions
+//
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CollisionBSPData_Init( CCollisionBSPData *pBSPData )
+{
+ pBSPData->numleafs = 1;
+ pBSPData->map_vis = NULL;
+ pBSPData->numareas = 1;
+ pBSPData->numclusters = 1;
+ pBSPData->map_nullname = "**empty**";
+ pBSPData->numtextures = 0;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_Destroy( CCollisionBSPData *pBSPData )
+{
+ for ( int i = 0; i < pBSPData->numcmodels; i++ )
+ {
+ physcollision->VCollideUnload( &pBSPData->map_cmodels[i].vcollisionData );
+ }
+
+ // free displacement data
+ DispCollTrees_FreeLeafList( pBSPData );
+ CM_DestroyDispPhysCollide();
+ DispCollTrees_Free( g_pDispCollTrees );
+ g_pDispCollTrees = NULL;
+ g_pDispBounds = NULL;
+ g_DispCollTreeCount = 0;
+
+ if ( pBSPData->map_planes.Base() )
+ {
+ pBSPData->map_planes.Detach();
+ }
+
+ if ( pBSPData->map_texturenames )
+ {
+ pBSPData->map_texturenames = NULL;
+ }
+
+ if ( pBSPData->map_surfaces.Base() )
+ {
+ pBSPData->map_surfaces.Detach();
+ }
+
+ if ( pBSPData->map_areaportals.Base() )
+ {
+ pBSPData->map_areaportals.Detach();
+ }
+
+ if ( pBSPData->portalopen.Base() )
+ {
+ pBSPData->portalopen.Detach();
+ }
+
+ if ( pBSPData->map_areas.Base() )
+ {
+ pBSPData->map_areas.Detach();
+ }
+
+ pBSPData->map_entitystring.Discard();
+
+ if ( pBSPData->map_brushes.Base() )
+ {
+ pBSPData->map_brushes.Detach();
+ }
+
+ if ( pBSPData->map_dispList.Base() )
+ {
+ pBSPData->map_dispList.Detach();
+ }
+
+ if ( pBSPData->map_cmodels.Base() )
+ {
+ pBSPData->map_cmodels.Detach();
+ }
+
+ if ( pBSPData->map_leafbrushes.Base() )
+ {
+ pBSPData->map_leafbrushes.Detach();
+ }
+
+ if ( pBSPData->map_leafs.Base() )
+ {
+ pBSPData->map_leafs.Detach();
+ }
+
+ if ( pBSPData->map_nodes.Base() )
+ {
+ pBSPData->map_nodes.Detach();
+ }
+
+ if ( pBSPData->map_brushsides.Base() )
+ {
+ pBSPData->map_brushsides.Detach();
+ }
+
+ if ( pBSPData->map_vis )
+ {
+ pBSPData->map_vis = NULL;
+ }
+
+ pBSPData->numplanes = 0;
+ pBSPData->numbrushsides = 0;
+ pBSPData->emptyleaf = pBSPData->solidleaf =0;
+ pBSPData->numnodes = 0;
+ pBSPData->numleafs = 0;
+ pBSPData->numbrushes = 0;
+ pBSPData->numdisplist = 0;
+ pBSPData->numleafbrushes = 0;
+ pBSPData->numareas = 0;
+ pBSPData->numtextures = 0;
+ pBSPData->floodvalid = 0;
+ pBSPData->numareaportals = 0;
+ pBSPData->numclusters = 0;
+ pBSPData->numcmodels = 0;
+ pBSPData->numvisibility = 0;
+ pBSPData->numentitychars = 0;
+ pBSPData->numportalopen = 0;
+ pBSPData->map_name[0] = 0;
+ pBSPData->map_rootnode = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Returns the collision tree associated with the ith displacement
+//-----------------------------------------------------------------------------
+
+CDispCollTree* CollisionBSPData_GetCollisionTree( int i )
+{
+ if ((i < 0) || (i >= g_DispCollTreeCount))
+ return 0;
+
+ return &g_pDispCollTrees[i];
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LinkPhysics( void )
+{
+ //
+ // initialize the physics surface properties -- if necessary!
+ //
+ if( !physprop )
+ {
+ physprop = ( IPhysicsSurfaceProps* )g_AppSystemFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL );
+ physcollision = ( IPhysicsCollision* )g_AppSystemFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
+
+ if ( !physprop || !physcollision )
+ {
+ Sys_Error( "CollisionBSPData_PreLoad: Can't link physics" );
+ }
+ }
+}
+
+
+//=============================================================================
+//
+// Loading Functions
+//
+
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_PreLoad( CCollisionBSPData *pBSPData )
+{
+ // initialize the collision bsp data
+ CollisionBSPData_Init( pBSPData );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CollisionBSPData_Load( const char *pName, CCollisionBSPData *pBSPData )
+{
+ // This is a table that maps texinfo references to csurface_t
+ // It is freed after the map has been loaded
+ CUtlVector<unsigned short> map_texinfo;
+
+ // copy map name
+ Q_strncpy( pBSPData->map_name, pName, sizeof( pBSPData->map_name ) );
+
+ //
+ // load bsp file data
+ //
+ COM_TimestampedLog( " CollisionBSPData_LoadTextures" );
+ CollisionBSPData_LoadTextures( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadTexinfo" );
+ CollisionBSPData_LoadTexinfo( pBSPData, map_texinfo );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadLeafs" );
+ CollisionBSPData_LoadLeafs( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadLeafBrushes" );
+ CollisionBSPData_LoadLeafBrushes( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadPlanes" );
+ CollisionBSPData_LoadPlanes( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadBrushes" );
+ CollisionBSPData_LoadBrushes( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadBrushSides" );
+ CollisionBSPData_LoadBrushSides( pBSPData, map_texinfo );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadSubmodels" );
+ CollisionBSPData_LoadSubmodels( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadPlanes" );
+ CollisionBSPData_LoadNodes( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadAreas" );
+ CollisionBSPData_LoadAreas( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadAreaPortals" );
+ CollisionBSPData_LoadAreaPortals( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadVisibility" );
+ CollisionBSPData_LoadVisibility( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadEntityString" );
+ CollisionBSPData_LoadEntityString( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadPhysics" );
+ CollisionBSPData_LoadPhysics( pBSPData );
+
+ COM_TimestampedLog( " CollisionBSPData_LoadDispInfo" );
+ CollisionBSPData_LoadDispInfo( pBSPData );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadTextures( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_TEXDATA );
+
+ CMapLoadHelper lhStringData( LUMP_TEXDATA_STRING_DATA );
+ const char *pStringData = ( const char * )lhStringData.LumpBase();
+
+ CMapLoadHelper lhStringTable( LUMP_TEXDATA_STRING_TABLE );
+ if( lhStringTable.LumpSize() % sizeof( int ) )
+ Sys_Error( "CMod_LoadTextures: funny lump size");
+ int *pStringTable = ( int * )lhStringTable.LumpBase();
+
+ dtexdata_t *in;
+ int i, count;
+ IMaterial *material;
+
+ in = (dtexdata_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadTextures: funny lump size");
+ }
+ count = lh.LumpSize() / sizeof(*in);
+ if (count < 1)
+ {
+ Sys_Error( "Map with no textures");
+ }
+ if (count > MAX_MAP_TEXDATA)
+ {
+ Sys_Error( "Map has too many textures");
+ }
+
+ int nSize = count * sizeof(csurface_t);
+ pBSPData->map_surfaces.Attach( count, (csurface_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numtextures = count;
+
+ pBSPData->map_texturenames = (char *)Hunk_Alloc( lhStringData.LumpSize() * sizeof(char), false );
+ memcpy( pBSPData->map_texturenames, pStringData, lhStringData.LumpSize() );
+
+ for ( i=0 ; i<count ; i++, in++ )
+ {
+ Assert( in->nameStringTableID >= 0 );
+ Assert( pStringTable[in->nameStringTableID] >= 0 );
+
+ const char *pInName = &pStringData[pStringTable[in->nameStringTableID]];
+ int index = pInName - pStringData;
+
+ csurface_t *out = &pBSPData->map_surfaces[i];
+ out->name = &pBSPData->map_texturenames[index];
+ out->surfaceProps = 0;
+ out->flags = 0;
+
+ material = materials->FindMaterial( pBSPData->map_surfaces[i].name, TEXTURE_GROUP_WORLD, true );
+ if ( !IsErrorMaterial( material ) )
+ {
+ IMaterialVar *var;
+ bool varFound;
+ var = material->FindVar( "$surfaceprop", &varFound, false );
+ if ( varFound )
+ {
+ const char *pProps = var->GetStringValue();
+ pBSPData->map_surfaces[i].surfaceProps = physprop->GetSurfaceIndex( pProps );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadTexinfo( CCollisionBSPData *pBSPData,
+ CUtlVector<unsigned short> &map_texinfo )
+{
+ CMapLoadHelper lh( LUMP_TEXINFO );
+
+ texinfo_t *in;
+ unsigned short out;
+ int i, count;
+
+ in = (texinfo_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ Sys_Error( "CollisionBSPData_LoadTexinfo: funny lump size");
+ count = lh.LumpSize() / sizeof(*in);
+ if (count < 1)
+ Sys_Error( "Map with no texinfo");
+ if (count > MAX_MAP_TEXINFO)
+ Sys_Error( "Map has too many surfaces");
+
+ MEM_ALLOC_CREDIT();
+ map_texinfo.RemoveAll();
+ map_texinfo.EnsureCapacity( count );
+
+ for ( i=0 ; i<count ; i++, in++ )
+ {
+ out = in->texdata;
+
+ if ( out >= pBSPData->numtextures )
+ out = 0;
+
+ // HACKHACK: Copy this over for the whole material!!!
+ pBSPData->map_surfaces[out].flags |= in->flags;
+ map_texinfo.AddToTail(out);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadLeafs_Version_0( CCollisionBSPData *pBSPData, CMapLoadHelper &lh )
+{
+ int i;
+ dleaf_version_0_t *in;
+ int count;
+
+ in = (dleaf_version_0_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CollisionBSPData_LoadLeafs: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+
+ if (count < 1)
+ {
+ Sys_Error( "Map with no leafs");
+ }
+
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ {
+ Sys_Error( "Map has too many planes");
+ }
+
+ // Need an extra one for the emptyleaf below
+ int nSize = (count + 1) * sizeof(cleaf_t);
+ pBSPData->map_leafs.Attach( count + 1, (cleaf_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numleafs = count;
+ pBSPData->numclusters = 0;
+
+ for ( i=0 ; i<count ; i++, in++ )
+ {
+ cleaf_t *out = &pBSPData->map_leafs[i];
+ out->contents = in->contents;
+ out->cluster = in->cluster;
+ out->area = in->area;
+ out->flags = in->flags;
+ out->firstleafbrush = in->firstleafbrush;
+ out->numleafbrushes = in->numleafbrushes;
+
+ out->dispCount = 0;
+
+ if (out->cluster >= pBSPData->numclusters)
+ {
+ pBSPData->numclusters = out->cluster + 1;
+ }
+ }
+
+ if (pBSPData->map_leafs[0].contents != CONTENTS_SOLID)
+ {
+ Sys_Error( "Map leaf 0 is not CONTENTS_SOLID");
+ }
+
+ pBSPData->solidleaf = 0;
+ pBSPData->emptyleaf = pBSPData->numleafs;
+ memset( &pBSPData->map_leafs[pBSPData->emptyleaf], 0, sizeof(pBSPData->map_leafs[pBSPData->emptyleaf]) );
+ pBSPData->numleafs++;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadLeafs_Version_1( CCollisionBSPData *pBSPData, CMapLoadHelper &lh )
+{
+ int i;
+ dleaf_t *in;
+ int count;
+
+ in = (dleaf_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CollisionBSPData_LoadLeafs: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+
+ if (count < 1)
+ {
+ Sys_Error( "Map with no leafs");
+ }
+
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ {
+ Sys_Error( "Map has too many planes");
+ }
+
+ // Need an extra one for the emptyleaf below
+ int nSize = (count + 1) * sizeof(cleaf_t);
+ pBSPData->map_leafs.Attach( count + 1, (cleaf_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numleafs = count;
+ pBSPData->numclusters = 0;
+
+ for ( i=0 ; i<count ; i++, in++ )
+ {
+ cleaf_t *out = &pBSPData->map_leafs[i];
+ out->contents = in->contents;
+ out->cluster = in->cluster;
+ out->area = in->area;
+ out->flags = in->flags;
+ out->firstleafbrush = in->firstleafbrush;
+ out->numleafbrushes = in->numleafbrushes;
+
+ out->dispCount = 0;
+
+ if (out->cluster >= pBSPData->numclusters)
+ {
+ pBSPData->numclusters = out->cluster + 1;
+ }
+ }
+
+ if (pBSPData->map_leafs[0].contents != CONTENTS_SOLID)
+ {
+ Sys_Error( "Map leaf 0 is not CONTENTS_SOLID");
+ }
+
+ pBSPData->solidleaf = 0;
+ pBSPData->emptyleaf = pBSPData->numleafs;
+ memset( &pBSPData->map_leafs[pBSPData->emptyleaf], 0, sizeof(pBSPData->map_leafs[pBSPData->emptyleaf]) );
+ pBSPData->numleafs++;
+}
+
+void CollisionBSPData_LoadLeafs( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_LEAFS );
+ switch( lh.LumpVersion() )
+ {
+ case 0:
+ CollisionBSPData_LoadLeafs_Version_0( pBSPData, lh );
+ break;
+ case 1:
+ CollisionBSPData_LoadLeafs_Version_1( pBSPData, lh );
+ break;
+ default:
+ Assert( 0 );
+ Error( "Unknown LUMP_LEAFS version\n" );
+ break;
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadLeafBrushes( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_LEAFBRUSHES );
+
+ int i;
+ unsigned short *in;
+ int count;
+
+ in = (unsigned short *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadLeafBrushes: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+ if (count < 1)
+ {
+ Sys_Error( "Map with no planes");
+ }
+
+ // need to save space for box planes
+ if (count > MAX_MAP_LEAFBRUSHES)
+ {
+ Sys_Error( "Map has too many leafbrushes");
+ }
+
+ pBSPData->map_leafbrushes.Attach( count, (unsigned short*)Hunk_Alloc( count * sizeof(unsigned short), false ) );
+ pBSPData->numleafbrushes = count;
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ pBSPData->map_leafbrushes[i] = *in;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadPlanes( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_PLANES );
+
+ int i, j;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (dplane_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CollisionBSPData_LoadPlanes: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+
+ if (count < 1)
+ {
+ Sys_Error( "Map with no planes");
+ }
+
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ {
+ Sys_Error( "Map has too many planes");
+ }
+
+ int nSize = count * sizeof(cplane_t);
+ pBSPData->map_planes.Attach( count, (cplane_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ cplane_t *out = &pBSPData->map_planes[i];
+ bits = 0;
+ for (j=0 ; j<3 ; j++)
+ {
+ out->normal[j] = in->normal[j];
+ if (out->normal[j] < 0)
+ {
+ bits |= 1<<j;
+ }
+ }
+
+ out->dist = in->dist;
+ out->type = in->type;
+ out->signbits = bits;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadBrushes( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_BRUSHES );
+
+ dbrush_t *in;
+ int i, count;
+
+ in = (dbrush_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadBrushes: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+ if (count > MAX_MAP_BRUSHES)
+ {
+ Sys_Error( "Map has too many brushes");
+ }
+
+ int nSize = count * sizeof(cbrush_t);
+ pBSPData->map_brushes.Attach( count, (cbrush_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numbrushes = count;
+
+ for (i=0 ; i<count ; i++, in++)
+ {
+ cbrush_t *out = &pBSPData->map_brushes[i];
+ out->firstbrushside = in->firstside;
+ out->numsides = in->numsides;
+ out->contents = in->contents;
+ }
+}
+
+inline bool IsBoxBrush( const cbrush_t &brush, dbrushside_t *pSides, cplane_t *pPlanes )
+{
+ int countAxial = 0;
+ if ( brush.numsides == 6 )
+ {
+ for ( int i = 0; i < brush.numsides; i++ )
+ {
+ cplane_t *plane = pPlanes + pSides[brush.firstbrushside+i].planenum;
+ if ( plane->type > PLANE_Z )
+ break;
+ countAxial++;
+ }
+ }
+ return (countAxial == brush.numsides) ? true : false;
+}
+
+inline void ExtractBoxBrush( cboxbrush_t *pBox, const cbrush_t &brush, dbrushside_t *pSides, cplane_t *pPlanes, CUtlVector<unsigned short> &map_texinfo )
+{
+ // brush.numsides is no longer valid. Assume numsides == 6
+ for ( int i = 0; i < 6; i++ )
+ {
+ dbrushside_t *side = pSides + i + brush.firstbrushside;
+ cplane_t *plane = pPlanes + side->planenum;
+ int t = side->texinfo;
+ Assert(t<map_texinfo.Count());
+ int surfaceIndex = (t<0) ? SURFACE_INDEX_INVALID : map_texinfo[t];
+ int axis = plane->type;
+ Assert(fabs(plane->normal[axis])==1.0f);
+ if ( plane->normal[axis] == 1.0f )
+ {
+ pBox->maxs[axis] = plane->dist;
+ pBox->surfaceIndex[axis+3] = surfaceIndex;
+ }
+ else if ( plane->normal[axis] == -1.0f )
+ {
+ pBox->mins[axis] = -plane->dist;
+ pBox->surfaceIndex[axis] = surfaceIndex;
+ }
+ else
+ {
+ Assert(0);
+ }
+ }
+ pBox->pad2[0] = 0;
+ pBox->pad2[1] = 0;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadBrushSides( CCollisionBSPData *pBSPData, CUtlVector<unsigned short> &map_texinfo )
+{
+ CMapLoadHelper lh( LUMP_BRUSHSIDES );
+
+ int i, j;
+ dbrushside_t *in;
+
+ in = (dbrushside_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadBrushSides: funny lump size");
+ }
+
+ int inputSideCount = lh.LumpSize() / sizeof(*in);
+
+ // need to save space for box planes
+ if (inputSideCount > MAX_MAP_BRUSHSIDES)
+ {
+ Sys_Error( "Map has too many planes");
+ }
+
+
+ // Brushes are compressed on load to remove any AABB brushes. The brushsides for those are removed
+ // and those brushes are stored as cboxbrush_t. But the texinfo/surface data needs to be copied
+ // So the algorithm is:
+ //
+ // count box brushes
+ // count total brush sides
+ // allocate
+ // iterate brushes and copy sides or fill out box brushes
+ // done
+ //
+
+ int boxBrushCount = 0;
+ int brushSideCount = 0;
+ for ( i = 0; i < pBSPData->numbrushes; i++ )
+ {
+ if ( IsBoxBrush(pBSPData->map_brushes[i], in, pBSPData->map_planes.Base()) )
+ {
+ // mark as axial
+ pBSPData->map_brushes[i].numsides = NUMSIDES_BOXBRUSH;
+ boxBrushCount++;
+ }
+ else
+ {
+ brushSideCount += pBSPData->map_brushes[i].numsides;
+ }
+ }
+
+ int nSize = brushSideCount * sizeof(cbrushside_t);
+ pBSPData->map_brushsides.Attach( brushSideCount, (cbrushside_t*)Hunk_Alloc( nSize, false ) );
+ pBSPData->map_boxbrushes.Attach( boxBrushCount, (cboxbrush_t*)Hunk_Alloc( boxBrushCount*sizeof(cboxbrush_t), false ) );
+
+ pBSPData->numbrushsides = brushSideCount;
+ pBSPData->numboxbrushes = boxBrushCount;
+
+ int outBoxBrush = 0;
+ int outBrushSide = 0;
+ for ( i = 0; i < pBSPData->numbrushes; i++ )
+ {
+ cbrush_t *pBrush = &pBSPData->map_brushes[i];
+
+ if ( pBrush->IsBox() )
+ {
+ // fill out the box brush - extract from the input sides
+ cboxbrush_t *pBox = &pBSPData->map_boxbrushes[outBoxBrush];
+ ExtractBoxBrush( pBox, *pBrush, in, pBSPData->map_planes.Base(), map_texinfo );
+ pBrush->SetBox(outBoxBrush);
+ outBoxBrush++;
+ }
+ else
+ {
+ // copy each side into the output array
+ int firstInputSide = pBrush->firstbrushside;
+ pBrush->firstbrushside = outBrushSide;
+ for ( j = 0; j < pBrush->numsides; j++ )
+ {
+ cbrushside_t * RESTRICT pSide = &pBSPData->map_brushsides[outBrushSide];
+ dbrushside_t * RESTRICT pInputSide = in + firstInputSide + j;
+ pSide->plane = &pBSPData->map_planes[pInputSide->planenum];
+ int t = pInputSide->texinfo;
+ if (t >= map_texinfo.Size())
+ {
+ Sys_Error( "Bad brushside texinfo");
+ }
+
+ // BUGBUG: Why is vbsp writing out -1 as the texinfo id? (TEXINFO_NODE ?)
+ pSide->surfaceIndex = (t < 0) ? SURFACE_INDEX_INVALID : map_texinfo[t];
+ pSide->bBevel = pInputSide->bevel ? true : false;
+ outBrushSide++;
+ }
+ }
+ }
+ Assert( outBrushSide == pBSPData->numbrushsides && outBoxBrush == pBSPData->numboxbrushes );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadSubmodels( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_MODELS );
+
+ dmodel_t *in;
+ int i, j, count;
+
+ in = (dmodel_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ Sys_Error("CMod_LoadSubmodels: funny lump size");
+ count = lh.LumpSize() / sizeof(*in);
+
+ if (count < 1)
+ Sys_Error( "Map with no models" );
+ if (count > MAX_MAP_MODELS)
+ Sys_Error( "Map has too many models" );
+
+ int nSize = count * sizeof(cmodel_t);
+ pBSPData->map_cmodels.Attach( count, (cmodel_t*)Hunk_Alloc( nSize ) );
+ pBSPData->numcmodels = count;
+
+ for ( i=0 ; i<count ; i++, in++ )
+ {
+ cmodel_t *out = &pBSPData->map_cmodels[i];
+
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out->mins[j] = in->mins[j] - 1;
+ out->maxs[j] = in->maxs[j] + 1;
+ out->origin[j] = in->origin[j];
+ }
+ out->headnode = in->headnode;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadNodes( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_NODES );
+
+ dnode_t *in;
+ int i, j, count;
+
+ in = (dnode_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ Sys_Error( "CollisionBSPData_LoadNodes: funny lump size");
+ count = lh.LumpSize() / sizeof(*in);
+
+ if (count < 1)
+ Sys_Error( "Map has no nodes");
+ if (count > MAX_MAP_NODES)
+ Sys_Error( "Map has too many nodes");
+
+ // 6 extra for box hull
+ int nSize = ( count + 6 ) * sizeof(cnode_t);
+ pBSPData->map_nodes.Attach( count + 6, (cnode_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numnodes = count;
+ pBSPData->map_rootnode = pBSPData->map_nodes.Base();
+
+ for (i=0; i<count; i++, in++)
+ {
+ cnode_t *out = &pBSPData->map_nodes[i];
+ out->plane = &pBSPData->map_planes[ in->planenum ];
+ for (j=0; j<2; j++)
+ {
+ out->children[j] = in->children[j];
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadAreas( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_AREAS );
+
+ int i;
+ darea_t *in;
+ int count;
+
+ in = (darea_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadAreas: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+ if (count > MAX_MAP_AREAS)
+ {
+ Sys_Error( "Map has too many areas");
+ }
+
+ int nSize = count * sizeof(carea_t);
+ pBSPData->map_areas.Attach( count, (carea_t*)Hunk_Alloc( nSize ) );
+
+ pBSPData->numareas = count;
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ carea_t *out = &pBSPData->map_areas[i];
+ out->numareaportals = in->numareaportals;
+ out->firstareaportal = in->firstareaportal;
+ out->floodvalid = 0;
+ out->floodnum = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadAreaPortals( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_AREAPORTALS );
+
+ dareaportal_t *in;
+ int count;
+
+ in = (dareaportal_t *)lh.LumpBase();
+ if (lh.LumpSize() % sizeof(*in))
+ {
+ Sys_Error( "CMod_LoadAreaPortals: funny lump size");
+ }
+
+ count = lh.LumpSize() / sizeof(*in);
+ if (count > MAX_MAP_AREAPORTALS)
+ {
+ Sys_Error( "Map has too many area portals");
+ }
+
+ // Need to add one more in owing to 1-based instead of 0-based data!
+ ++count;
+
+ pBSPData->numportalopen = count;
+ pBSPData->portalopen.Attach( count, (bool*)Hunk_Alloc( pBSPData->numportalopen * sizeof(bool), false ) );
+ for ( int i=0; i < pBSPData->numportalopen; i++ )
+ {
+ pBSPData->portalopen[i] = false;
+ }
+
+ pBSPData->numareaportals = count;
+ int nSize = count * sizeof(dareaportal_t);
+ pBSPData->map_areaportals.Attach( count, (dareaportal_t*)Hunk_Alloc( nSize ) );
+
+ Assert( nSize >= lh.LumpSize() );
+ memcpy( pBSPData->map_areaportals.Base(), in, lh.LumpSize() );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadVisibility( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_VISIBILITY );
+
+ pBSPData->numvisibility = lh.LumpSize();
+ if (lh.LumpSize() > MAX_MAP_VISIBILITY)
+ Sys_Error( "Map has too large visibility lump");
+
+ int visDataSize = lh.LumpSize();
+ if ( visDataSize == 0 )
+ {
+ pBSPData->map_vis = NULL;
+ }
+ else
+ {
+ pBSPData->map_vis = (dvis_t *) Hunk_Alloc( visDataSize, false );
+ memcpy( pBSPData->map_vis, lh.LumpBase(), visDataSize );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadEntityString( CCollisionBSPData *pBSPData )
+{
+ CMapLoadHelper lh( LUMP_ENTITIES );
+
+ pBSPData->numentitychars = lh.LumpSize();
+ MEM_ALLOC_CREDIT();
+ char szMapName[MAX_PATH] = { 0 };
+ V_strncpy( szMapName, lh.GetMapName(), sizeof( szMapName ) );
+ pBSPData->map_entitystring.Init( szMapName, lh.LumpOffset(), lh.LumpSize(), lh.LumpBase() );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadPhysics( CCollisionBSPData *pBSPData )
+{
+#ifdef _WIN32
+ CMapLoadHelper lh( LUMP_PHYSCOLLIDE );
+#else
+ int nLoadLump = LUMP_PHYSCOLLIDE;
+ // backwards compat support for older game dlls
+ // they crash if they don't have vcollide data for terrain
+ // even though the new engine ignores it
+ if ( g_iServerGameDLLVersion >= 5 )
+ {
+ // if there's a linux lump present, go ahead and load it
+ // otherwise, the win32 lump will work as long as it doesn't have any
+ // mopp surfaces in it (if compiled with the current vbsp.exe or a map without any displacements).
+ // The legacy server game DLLs will crash when mopps are present but since
+ // they also crash with a NULL lump there's nothing lost in that case.
+ if ( CMapLoadHelper::LumpSize(LUMP_PHYSCOLLIDESURFACE) > 0 )
+ {
+ nLoadLump = LUMP_PHYSCOLLIDESURFACE;
+ }
+ else
+ {
+ DevWarning("Legacy game DLL may not support terrain vphysics collisions with this BSP!\n");
+ }
+ }
+
+ CMapLoadHelper lh( nLoadLump );
+#endif
+ if ( !lh.LumpSize() )
+ return;
+
+ byte *ptr = lh.LumpBase();
+ byte *basePtr = ptr;
+
+ dphysmodel_t physModel;
+
+ // physics data is variable length. The last physmodel is a NULL pointer
+ // with modelIndex -1, dataSize -1
+ do
+ {
+ memcpy( &physModel, ptr, sizeof(physModel) );
+ ptr += sizeof(physModel);
+
+ if ( physModel.dataSize > 0 )
+ {
+ cmodel_t *pModel = &pBSPData->map_cmodels[ physModel.modelIndex ];
+ physcollision->VCollideLoad( &pModel->vcollisionData, physModel.solidCount, (const char *)ptr, physModel.dataSize + physModel.keydataSize );
+ ptr += physModel.dataSize;
+ ptr += physModel.keydataSize;
+ }
+
+ // avoid infinite loop on badly formed file
+ if ( (int)(ptr - basePtr) > lh.LumpSize() )
+ break;
+
+ } while ( physModel.dataSize > 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionBSPData_LoadDispInfo( CCollisionBSPData *pBSPData )
+{
+ // How many displacements in the map?
+ int coreDispCount = CMapLoadHelper::LumpSize( LUMP_DISPINFO ) / sizeof( ddispinfo_t );
+ if ( coreDispCount == 0 )
+ return;
+
+ //
+ // get the vertex data
+ //
+ CMapLoadHelper lhv( LUMP_VERTEXES );
+ dvertex_t *pVerts = ( dvertex_t* )lhv.LumpBase();
+ if ( lhv.LumpSize() % sizeof( dvertex_t ) )
+ Sys_Error( "CMod_LoadDispInfo: bad vertex lump size!" );
+
+ //
+ // get the edge data
+ //
+ CMapLoadHelper lhe( LUMP_EDGES );
+ dedge_t *pEdges = ( dedge_t* )lhe.LumpBase();
+ if ( lhe.LumpSize() % sizeof( dedge_t ) )
+ Sys_Error( "CMod_LoadDispInfo: bad edge lump size!" );
+
+ //
+ // get surf edges data
+ //
+ CMapLoadHelper lhs( LUMP_SURFEDGES );
+ int *pSurfEdges = ( int* )lhs.LumpBase();
+ if ( lhs.LumpSize() % sizeof( int ) )
+ Sys_Error( "CMod_LoadDispInfo: bad surf edge lump size!" );
+
+ //
+ // get face data
+ //
+ int face_lump_to_load = LUMP_FACES;
+ if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE &&
+ CMapLoadHelper::LumpSize( LUMP_FACES_HDR ) > 0 )
+ {
+ face_lump_to_load = LUMP_FACES_HDR;
+ }
+ CMapLoadHelper lhf( face_lump_to_load );
+ dface_t *pFaces = ( dface_t* )lhf.LumpBase();
+ if ( lhf.LumpSize() % sizeof( dface_t ) )
+ Sys_Error( "CMod_LoadDispInfo: bad face lump size!" );
+ int faceCount = lhf.LumpSize() / sizeof( dface_t );
+
+ dface_t *pFaceList = pFaces;
+ if ( !pFaceList )
+ return;
+
+ //
+ // get texinfo data
+ //
+ CMapLoadHelper lhti( LUMP_TEXINFO );
+ texinfo_t *pTexinfoList = ( texinfo_t* )lhti.LumpBase();
+ if ( lhti.LumpSize() % sizeof( texinfo_t ) )
+ Sys_Error( "CMod_LoadDispInfo: bad texinfo lump size!" );
+
+ // allocate displacement collision trees
+ g_DispCollTreeCount = coreDispCount;
+ g_pDispCollTrees = DispCollTrees_Alloc( g_DispCollTreeCount );
+ g_pDispBounds = (alignedbbox_t *)Hunk_Alloc( g_DispCollTreeCount * sizeof(alignedbbox_t), false );
+
+ // Build the inverse mapping from disp index to face
+ int nMemSize = coreDispCount * sizeof(unsigned short);
+ unsigned short *pDispIndexToFaceIndex = (unsigned short*)stackalloc( nMemSize );
+ memset( pDispIndexToFaceIndex, 0xFF, nMemSize );
+
+ int i;
+ for ( i = 0; i < faceCount; ++i, ++pFaces )
+ {
+ // check face for displacement data
+ if ( pFaces->dispinfo == -1 )
+ continue;
+
+ // get the current displacement build surface
+ if ( pFaces->dispinfo >= coreDispCount )
+ continue;
+
+ pDispIndexToFaceIndex[pFaces->dispinfo] = (unsigned short)i;
+ }
+
+ // Load one dispinfo from disk at a time and set it up.
+ int iCurVert = 0;
+ int iCurTri = 0;
+ CDispVert tempVerts[MAX_DISPVERTS];
+ CDispTri tempTris[MAX_DISPTRIS];
+
+ int nSize = 0;
+ int nCacheSize = 0;
+ int nPowerCount[3] = { 0, 0, 0 };
+
+ CMapLoadHelper lhDispInfo( LUMP_DISPINFO );
+ CMapLoadHelper lhDispVerts( LUMP_DISP_VERTS );
+ CMapLoadHelper lhDispTris( LUMP_DISP_TRIS );
+
+ for ( i = 0; i < coreDispCount; ++i )
+ {
+ // Find the face associated with this dispinfo
+ unsigned short nFaceIndex = pDispIndexToFaceIndex[i];
+ if ( nFaceIndex == 0xFFFF )
+ continue;
+
+ // Load up the dispinfo and create the CCoreDispInfo from it.
+ ddispinfo_t dispInfo;
+ lhDispInfo.LoadLumpElement( i, sizeof(ddispinfo_t), &dispInfo );
+
+ // Read in the vertices.
+ int nVerts = NUM_DISP_POWER_VERTS( dispInfo.power );
+ lhDispVerts.LoadLumpData( iCurVert * sizeof(CDispVert), nVerts*sizeof(CDispVert), tempVerts );
+ iCurVert += nVerts;
+
+ // Read in the tris.
+ int nTris = NUM_DISP_POWER_TRIS( dispInfo.power );
+ lhDispTris.LoadLumpData( iCurTri * sizeof( CDispTri ), nTris*sizeof( CDispTri), tempTris );
+ iCurTri += nTris;
+
+ CCoreDispInfo coreDisp;
+ CCoreDispSurface *pDispSurf = coreDisp.GetSurface();
+ pDispSurf->SetPointStart( dispInfo.startPosition );
+ pDispSurf->SetContents( dispInfo.contents );
+
+ coreDisp.InitDispInfo( dispInfo.power, dispInfo.minTess, dispInfo.smoothingAngle, tempVerts, tempTris );
+
+ // Hook the disp surface to the face
+ pFaces = &pFaceList[ nFaceIndex ];
+ pDispSurf->SetHandle( nFaceIndex );
+
+ // get points
+ if ( pFaces->numedges > 4 )
+ continue;
+
+ Vector surfPoints[4];
+ pDispSurf->SetPointCount( pFaces->numedges );
+ int j;
+ for ( j = 0; j < pFaces->numedges; j++ )
+ {
+ int eIndex = pSurfEdges[pFaces->firstedge+j];
+ if ( eIndex < 0 )
+ {
+ VectorCopy( pVerts[pEdges[-eIndex].v[1]].point, surfPoints[j] );
+ }
+ else
+ {
+ VectorCopy( pVerts[pEdges[eIndex].v[0]].point, surfPoints[j] );
+ }
+ }
+
+ for ( j = 0; j < 4; j++ )
+ {
+ pDispSurf->SetPoint( j, surfPoints[j] );
+ }
+
+ pDispSurf->FindSurfPointStartIndex();
+ pDispSurf->AdjustSurfPointData();
+
+ //
+ // generate the collision displacement surfaces
+ //
+ CDispCollTree *pDispTree = &g_pDispCollTrees[i];
+ pDispTree->SetPower( 0 );
+
+ //
+ // check for null faces, should have been taken care of in vbsp!!!
+ //
+ int pointCount = pDispSurf->GetPointCount();
+ if ( pointCount != 4 )
+ continue;
+
+ coreDisp.Create();
+
+ // new collision
+ pDispTree->Create( &coreDisp );
+ g_pDispBounds[i].Init(pDispTree->m_mins, pDispTree->m_maxs, pDispTree->m_iCounter, pDispTree->GetContents());
+ nSize += pDispTree->GetMemorySize();
+ nCacheSize += pDispTree->GetCacheMemorySize();
+ nPowerCount[pDispTree->GetPower()-2]++;
+
+ // Surface props.
+ texinfo_t *pTex = &pTexinfoList[pFaces->texinfo];
+ if ( pTex->texdata >= 0 )
+ {
+ IMaterial *pMaterial = materials->FindMaterial( pBSPData->map_surfaces[pTex->texdata].name, TEXTURE_GROUP_WORLD, true );
+ if ( !IsErrorMaterial( pMaterial ) )
+ {
+ IMaterialVar *pVar;
+ bool bVarFound;
+ pVar = pMaterial->FindVar( "$surfaceprop", &bVarFound, false );
+ if ( bVarFound )
+ {
+ const char *pProps = pVar->GetStringValue();
+ pDispTree->SetSurfaceProps( 0, physprop->GetSurfaceIndex( pProps ) );
+ pDispTree->SetSurfaceProps( 1, physprop->GetSurfaceIndex( pProps ) );
+ }
+
+ pVar = pMaterial->FindVar( "$surfaceprop2", &bVarFound, false );
+ if ( bVarFound )
+ {
+ const char *pProps = pVar->GetStringValue();
+ pDispTree->SetSurfaceProps( 1, physprop->GetSurfaceIndex( pProps ) );
+ }
+ }
+ }
+ }
+
+ CMapLoadHelper lhDispPhys( LUMP_PHYSDISP );
+ dphysdisp_t *pDispPhys = (dphysdisp_t *)lhDispPhys.LumpBase();
+ // create the vphysics collision models for each displacement
+ CM_CreateDispPhysCollide( pDispPhys, lhDispPhys.LumpSize() );
+}
+
+
+//=============================================================================
+//
+// Collision Count Functions
+//
+
+#ifdef COUNT_COLLISIONS
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CollisionCounts_Init( CCollisionCounts *pCounts )
+{
+ pCounts->m_PointContents = 0;
+ pCounts->m_Traces = 0;
+ pCounts->m_BrushTraces = 0;
+ pCounts->m_DispTraces = 0;
+ pCounts->m_Stabs = 0;
+}
+#endif