|
|
//========= Copyright � 1996-2005, 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"
#include "vphysics_interface.h"
#include "sys_dll.h"
#include "tier3/tier3.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IPhysicsSurfaceProps *physprops = NULL; IPhysicsCollision *physcollision = NULL;
// local forward declarations
void CollisionBSPData_LoadTextures( CCollisionBSPData *pBSPData ); void CollisionBSPData_LoadTexinfo( CCollisionBSPData *pBSPData, texinfo_t *pTexinfo, int texinfoCount ); 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, texinfo_t *pTexinfo, int texinfoCount ); 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, texinfo_t *pTexinfo, int texinfoCount );
//=============================================================================
//
// 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_boxbrushes.Base() ) { pBSPData->map_boxbrushes.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->numboxbrushes = 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->mapPathName[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( !physprops ) { physprops = ( IPhysicsSurfaceProps* )g_AppSystemFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL ); physcollision = ( IPhysicsCollision* )g_AppSystemFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
if ( !physprops || !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 *pPathName, CCollisionBSPData *pBSPData, texinfo_t *pTexinfo, int texinfoCount ) { // This is a table that maps texinfo references to csurface_t
// It is freed after the map has been loaded
// copy map name
Q_strncpy( pBSPData->mapPathName, pPathName, sizeof( pBSPData->mapPathName ) );
//
// load bsp file data
//
COM_TimestampedLog( " CollisionBSPData_LoadTextures" ); CollisionBSPData_LoadTextures( pBSPData );
COM_TimestampedLog( " CollisionBSPData_LoadTexinfo" ); CollisionBSPData_LoadTexinfo( pBSPData, pTexinfo, texinfoCount );
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, pTexinfo, texinfoCount );
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, pTexinfo, texinfoCount );
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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Textures" ) ) );
pBSPData->numtextures = count;
pBSPData->map_texturenames = (char *)Hunk_AllocName( lhStringData.LumpSize() * sizeof(char), va( "%s [%s]", lh.GetLoadName(), "Textures" ), 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 = physprops->GetSurfaceIndex( pProps ); } } } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CollisionBSPData_LoadTexinfo( CCollisionBSPData *pBSPData, texinfo_t *pTexinfo, int texinfoCount ) { for ( int i=0 ; i<texinfoCount; i++ ) { unsigned short out = pTexinfo[i].texdata; if ( out >= pBSPData->numtextures ) out = 0;
// HACKHACK: Copy this over for the whole material!!!
pBSPData->map_surfaces[out].flags |= pTexinfo[i].flags; } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Leafs" ) ) );
pBSPData->numleafs = count; pBSPData->numclusters = 0; int allcontents = 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; } allcontents |= in->contents; }
pBSPData->allcontents = allcontents; 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Leafs" ) ) );
pBSPData->numleafs = count; pBSPData->numclusters = 0; int allcontents = 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; } allcontents |= in->contents; } pBSPData->allcontents = allcontents;
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 ) { pBSPData->allcontents = MASK_ALL; 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_AllocName( count * sizeof(unsigned short), va( "%s [%s]", lh.GetLoadName(), "LeafBrushes" ), 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Planes" ) ) );
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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Brushes" ) ) );
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, texinfo_t *pTexinfo, int texinfoCount ) { // brush.numsides is no longer valid. Assume numsides == 6
pBox->thinMask = 0; 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<texinfoCount); int surfaceIndex = (t<0) ? SURFACE_INDEX_INVALID : pTexinfo[t].texdata; int axis = plane->type; Assert(fabs(plane->normal[axis])==1.0f); int maskIndex = axis; if ( plane->normal[axis] == 1.0f ) { pBox->maxs[axis] = plane->dist; pBox->surfaceIndex[axis+3] = surfaceIndex; maskIndex += 3; } else if ( plane->normal[axis] == -1.0f ) { pBox->mins[axis] = -plane->dist; pBox->surfaceIndex[axis] = surfaceIndex; } else { Assert(0); } pBox->thinMask |= side->thin << maskIndex; } pBox->pad = 0; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CollisionBSPData_LoadBrushSides( CCollisionBSPData *pBSPData, texinfo_t *pTexinfo, int texinfoCount ) { 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "BrushSides" ), false ) ); pBSPData->map_boxbrushes.Attach( boxBrushCount, (cboxbrush_t*)Hunk_AllocName( boxBrushCount*sizeof(cboxbrush_t), va( "%s [%s]", lh.GetLoadName(), "BrushSides" ), 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(), pTexinfo, texinfoCount ); 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 >= texinfoCount) { 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 : pTexinfo[t].texdata; pSide->bBevel = pInputSide->bevel; pSide->bThin = pInputSide->thin; 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Submodels" ) ) ); 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Nodes" ) ) );
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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "Areas" ) ) );
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_AllocName( pBSPData->numportalopen * sizeof(bool), va( "%s [%s]", lh.GetLoadName(), "AreaPortals" ), 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_AllocName( nSize, va( "%s [%s]", lh.GetLoadName(), "AreaPortals" ) ) );
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_AllocName( visDataSize, va( "%s [%s]", lh.GetLoadName(), "Visibility" ), false ); memcpy( pBSPData->map_vis, lh.LumpBase(), visDataSize ); } }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CollisionBSPData_LoadEntityString( CCollisionBSPData *pBSPData ) { CMapLoadHelper lh( LUMP_ENTITIES );
pBSPData->numentitychars = lh.LumpSize(); MEM_ALLOC_CREDIT(); pBSPData->map_entitystring.Init( lh.GetDiskName(), lh.LumpOffset(), lh.LumpSize(), lh.LumpBase() ); }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CollisionBSPData_LoadPhysics( CCollisionBSPData *pBSPData ) { CMapLoadHelper lh( LUMP_PHYSCOLLIDE );
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, texinfo_t *pTexinfo, int texinfoCount ) { // How many displacements in the map?
CMapLoadHelper lhDispInfo( LUMP_DISPINFO ); int coreDispCount = lhDispInfo.LumpSize() / 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;
// allocate displacement collision trees
g_DispCollTreeCount = coreDispCount; g_pDispCollTrees = DispCollTrees_Alloc( g_DispCollTreeCount ); g_pDispBounds = (alignedbbox_t *)Hunk_AllocName( g_DispCollTreeCount * sizeof(alignedbbox_t), va( "%s [%s]", lhDispInfo.GetLoadName(), "DispInfo" ), 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; int iCurMultiBlend = 0; CDispVert tempVerts[MAX_DISPVERTS]; CDispTri tempTris[MAX_DISPTRIS]; CDispMultiBlend tempMultiBlend[MAX_DISPVERTS];
int nSize = 0; int nCacheSize = 0; int nPowerCount[3] = { 0, 0, 0 };
CMapLoadHelper lhDispVerts( LUMP_DISP_VERTS ); CMapLoadHelper lhDispTris( LUMP_DISP_TRIS ); CMapLoadHelper lhDispMultiBLend( LUMP_DISP_MULTIBLEND );
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;
int nFlags = 0; if ( ( dispInfo.minTess & DISP_INFO_FLAG_HAS_MULTIBLEND ) != 0 ) { lhDispMultiBLend.LoadLumpData( iCurMultiBlend * sizeof( CDispMultiBlend ), nVerts * sizeof( CDispMultiBlend ), tempMultiBlend ); iCurMultiBlend += nVerts; nFlags = DISP_INFO_FLAG_HAS_MULTIBLEND; }
CCoreDispInfo coreDisp; CCoreDispSurface *pDispSurf = coreDisp.GetSurface(); pDispSurf->SetPointStart( dispInfo.startPosition ); pDispSurf->SetContents( dispInfo.contents ); coreDisp.InitDispInfo( dispInfo.power, dispInfo.minTess, dispInfo.smoothingAngle, tempVerts, tempTris, nFlags, tempMultiBlend );
// 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 = &pTexinfo[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(); int nPropIndex = physprops->GetSurfaceIndex( pProps ); pDispTree->SetSurfaceProps( 0, nPropIndex ); pDispTree->SetSurfaceProps( 1, nPropIndex ); pDispTree->SetSurfaceProps( 2, nPropIndex ); pDispTree->SetSurfaceProps( 3, nPropIndex ); }
pVar = pMaterial->FindVar( "$surfaceprop2", &bVarFound, false ); if ( bVarFound ) { const char *pProps = pVar->GetStringValue(); pDispTree->SetSurfaceProps( 1, physprops->GetSurfaceIndex( pProps ) ); }
pVar = pMaterial->FindVar( "$surfaceprop3", &bVarFound, false ); if ( bVarFound ) { const char *pProps = pVar->GetStringValue(); pDispTree->SetSurfaceProps( 2, physprops->GetSurfaceIndex( pProps ) ); }
pVar = pMaterial->FindVar( "$surfaceprop4", &bVarFound, false ); if ( bVarFound ) { const char *pProps = pVar->GetStringValue(); pDispTree->SetSurfaceProps( 3, physprops->GetSurfaceIndex( pProps ) ); } }
pDispTree->SetTexinfoFlags( pBSPData->map_surfaces[pTex->texdata].flags ); } }
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
|