/
noire-dev
/
SourceTech
Обзор
Документация
Войти
/
noire-dev
/
SourceTech
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
sourcetech
code/qcommon/cm_load.c
963 строки
22 KB
noire-dev
Update: 2025-12-21 16:14 powersaving and clean
21 дек 2025, 07:14
21 дек 2025, 07:14
05bd062
Код
Авторство
О чём код?
/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake III Arena source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // cmodel.c -- model loading #include "cm_local.h" #ifdef BSPC #include "../bspc/l_qfiles.h" void SetPlaneSignbits( cplane_t *out ) { int bits, j; // for fast box on planeside test bits = 0; for ( j = 0; j < 3; j++) { if ( out->normal[j] < 0 ) { bits |= 1<<j; } } out->signbits = bits; } #endif //BSPC // to allow boxes to be treated as brush models, we allocate // some extra indexes along with those needed by the map #define BOX_BRUSHES 1 #define BOX_SIDES 6 #define BOX_LEAFS 2 #define BOX_PLANES 12 #define LL(x) x=LittleLong(x) #ifdef USE_BSP_COLMODELS clipMap_t cmWorlds[MAX_NUM_MAPS]; int cmi = 0; #else clipMap_t cm; #endif int c_pointcontents; int c_traces, c_brush_traces, c_patch_traces; static byte *cmod_base; #ifndef BSPC cvar_t *cm_noAreas; cvar_t *cm_noCurves; cvar_t *cm_playerCurveClip; #endif #ifdef USE_BSP_COLMODELS static cmodel_t box_modelWorlds[MAX_NUM_MAPS]; static cplane_t *box_planesWorlds[MAX_NUM_MAPS]; static cbrush_t *box_brushWorlds[MAX_NUM_MAPS]; #define box_model box_modelWorlds[cmi] #define box_planes box_planesWorlds[cmi] #define box_brush box_brushWorlds[cmi] #else static cmodel_t box_model; static cplane_t *box_planes; static cbrush_t *box_brush; #endif static void CM_InitBoxHull (void); void CM_FloodAreaConnections (void); /* =============================================================================== MAP LOADING =============================================================================== */ /* ================= CMod_LoadShaders ================= */ static void CMod_LoadShaders( const lump_t *l ) { dshader_t *in, *out; int i, count; in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) { Com_Error (ERR_DROP, "%s: funny lump size", __func__ ); } count = l->filelen / sizeof(*in); if ( count < 1 ) Com_Error (ERR_DROP, "%s: map with no shaders", __func__ ); cm.shaders = Hunk_Alloc( count * sizeof( *cm.shaders ) ); cm.numShaders = count; Com_Memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) ); out = cm.shaders; for ( i = 0; i < count; i++, in++, out++ ) { out->contentFlags = LittleLong( out->contentFlags ); out->surfaceFlags = LittleLong( out->surfaceFlags ); } } /* ================= CMod_LoadSubmodels ================= */ static void CMod_LoadSubmodels( const lump_t *l ) { dmodel_t *in; cmodel_t *out; int i, j, count; int *indexes; in = (void *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); if ( count < 1 ) Com_Error( ERR_DROP, "%s: map with no models", __func__ ); cm.cmodels = Hunk_Alloc( count * sizeof( *cm.cmodels ) ); cm.numSubModels = count; if ( count > MAX_SUBMODELS ) Com_Error( ERR_DROP, "%s: MAX_SUBMODELS exceeded", __func__ ); for ( i=0 ; i<count ; i++, in++) { out = &cm.cmodels[i]; for (j=0 ; j<3 ; j++) { // spread the mins / maxs by a pixel out->mins[j] = LittleFloat (in->mins[j]) - 1; out->maxs[j] = LittleFloat (in->maxs[j]) + 1; } if ( i == 0 ) { continue; // world model doesn't need other info } // make a "leaf" just to hold the model's brushes and surfaces out->leaf.numLeafBrushes = LittleLong( in->numBrushes ); indexes = Hunk_Alloc( out->leaf.numLeafBrushes * 4 ); out->leaf.firstLeafBrush = indexes - cm.leafbrushes; for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) { indexes[j] = LittleLong( in->firstBrush ) + j; } out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces ); indexes = Hunk_Alloc( out->leaf.numLeafSurfaces * 4 ); out->leaf.firstLeafSurface = indexes - cm.leafsurfaces; for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) { indexes[j] = LittleLong( in->firstSurface ) + j; } } } /* ================= CMod_LoadNodes ================= */ static void CMod_LoadNodes( const lump_t *l ) { dnode_t *in; int child; cNode_t *out; int i, j, count; in = (dnode_t *)(cmod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); if ( count < 1 ) Com_Error( ERR_DROP, "%s: map has no nodes", __func__ ); cm.nodes = Hunk_Alloc( count * sizeof( *cm.nodes ) ); cm.numNodes = count; out = cm.nodes; for ( i = 0; i < count; i++, out++, in++ ) { out->plane = cm.planes + LittleLong( in->planeNum ); for ( j = 0; j < 2; j++ ) { child = LittleLong( in->children[j] ); out->children[j] = child; } } } /* ================= CM_BoundBrush ================= */ static void CM_BoundBrush( cbrush_t *b ) { b->bounds[0][0] = -b->sides[0].plane->dist; b->bounds[1][0] = b->sides[1].plane->dist; b->bounds[0][1] = -b->sides[2].plane->dist; b->bounds[1][1] = b->sides[3].plane->dist; b->bounds[0][2] = -b->sides[4].plane->dist; b->bounds[1][2] = b->sides[5].plane->dist; } /* ================= CMod_LoadBrushes ================= */ static void CMod_LoadBrushes( const lump_t *l ) { dbrush_t *in; cbrush_t *out; int i, count; in = (void *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); cm.brushes = Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ) ); cm.numBrushes = count; out = cm.brushes; for ( i = 0; i < count; i++, out++, in++ ) { out->sides = cm.brushsides + LittleLong( in->firstSide ); out->numsides = LittleLong( in->numSides ); out->shaderNum = LittleLong( in->shaderNum ); if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) { Com_Error( ERR_DROP, "%s: bad shaderNum: %i", __func__, out->shaderNum ); } out->contents = cm.shaders[out->shaderNum].contentFlags; CM_BoundBrush( out ); } } /* ================= CMod_LoadLeafs ================= */ static void CMod_LoadLeafs( const lump_t *l ) { int i; cLeaf_t *out; dleaf_t *in; int count; in = (void *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); if ( count < 1 ) Com_Error( ERR_DROP, "%s: map with no leafs", __func__ ); cm.leafs = Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ) ); cm.numLeafs = count; out = cm.leafs; for ( i = 0; i < count; i++, in++, out++ ) { out->cluster = LittleLong( in->cluster ); out->area = LittleLong( in->area ); out->firstLeafBrush = LittleLong( in->firstLeafBrush ); out->numLeafBrushes = LittleLong( in->numLeafBrushes ); out->firstLeafSurface = LittleLong( in->firstLeafSurface ); out->numLeafSurfaces = LittleLong( in->numLeafSurfaces ); if ( out->cluster >= cm.numClusters ) cm.numClusters = out->cluster + 1; if ( out->area >= cm.numAreas ) cm.numAreas = out->area + 1; } cm.areas = Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ) ); cm.areaPortals = Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ) ); } /* ================= CMod_LoadPlanes ================= */ static void CMod_LoadPlanes( const lump_t *l ) { int i, j; cplane_t *out; dplane_t *in; int count; int bits; in = (void *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); if ( count < 1 ) Com_Error( ERR_DROP, "%s: map with no planes", __func__ ); cm.planes = Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ) ); cm.numPlanes = count; out = cm.planes; for ( i = 0; i < count; i++, in++, out++ ) { bits = 0; for ( j = 0; j < 3; j++ ) { out->normal[j] = LittleFloat( in->normal[j] ); if ( out->normal[j] < 0 ) bits |= 1<<j; } out->dist = LittleFloat( in->dist ); out->type = PlaneTypeForNormal( out->normal ); out->signbits = bits; } } /* ================= CMod_LoadLeafBrushes ================= */ static void CMod_LoadLeafBrushes( const lump_t *l ) { int i; int *out; int *in; int count; in = (void *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); cm.leafbrushes = Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ) ); cm.numLeafBrushes = count; out = cm.leafbrushes; for ( i = 0; i < count; i++, in++, out++ ) { *out = LittleLong( *in ); } } /* ================= CMod_LoadLeafSurfaces ================= */ static void CMod_LoadLeafSurfaces( const lump_t *l ) { int i; int *out; int *in; int count; in = (void *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); count = l->filelen / sizeof(*in); cm.leafsurfaces = Hunk_Alloc( count * sizeof( *cm.leafsurfaces ) ); cm.numLeafSurfaces = count; out = cm.leafsurfaces; for ( i = 0; i < count; i++, in++, out++ ) { *out = LittleLong( *in ); } } /* ================= CMod_CheckLeafBrushes ================= */ static void CMod_CheckLeafBrushes( void ) { int i; for ( i = 0; i < cm.numLeafBrushes; i++ ) { if ( cm.leafbrushes[ i ] < 0 || cm.leafbrushes[ i ] >= cm.numBrushes ) { Com_DPrintf( S_COLOR_YELLOW "[%i] invalid leaf brush %08x\n", i, cm.leafbrushes[i] ); cm.leafbrushes[ i ] = 0; } } } /* ================= CMod_LoadBrushSides ================= */ static void CMod_LoadBrushSides( const lump_t *l ) { int i; cbrushside_t *out; dbrushside_t *in; int count; int num; in = (dbrushside_t *)(cmod_base + l->fileofs); if ( l->filelen % sizeof(*in) ) { Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); } count = l->filelen / sizeof(*in); cm.brushsides = Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ) ); cm.numBrushSides = count; out = cm.brushsides; for ( i= 0; i < count; i++, in++, out++ ) { num = LittleLong( in->planeNum ); out->plane = &cm.planes[num]; out->shaderNum = LittleLong( in->shaderNum ); if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) { Com_Error( ERR_DROP, "%s: bad shaderNum: %i", __func__, out->shaderNum ); } out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags; } } /* ================= CMod_LoadEntityString ================= */ static void CMod_LoadEntityString( const lump_t *l ) { cm.entityString = Hunk_Alloc( l->filelen ); cm.numEntityChars = l->filelen; Com_Memcpy( cm.entityString, cmod_base + l->fileofs, l->filelen ); } /* ================= CMod_LoadVisibility ================= */ #define VIS_HEADER 8 static void CMod_LoadVisibility( const lump_t *l ) { int len; byte *buf; len = l->filelen; if ( !len ) { cm.clusterBytes = ( cm.numClusters + 31 ) & ~31; cm.visibility = Hunk_Alloc( cm.clusterBytes ); Com_Memset( cm.visibility, 255, cm.clusterBytes ); return; } buf = cmod_base + l->fileofs; cm.vised = qtrue; cm.visibility = Hunk_Alloc( len ); cm.numClusters = LittleLong( ((int *)buf)[0] ); cm.clusterBytes = LittleLong( ((int *)buf)[1] ); Com_Memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER ); } //================================================================== /* ================= CMod_LoadPatches ================= */ #define MAX_PATCH_VERTS 1024 static void CMod_LoadPatches( const lump_t *surfs, const lump_t *verts ) { drawVert_t *dv, *dv_p; dsurface_t *in; int count; int i, j; int c; cPatch_t *patch; vec3_t points[MAX_PATCH_VERTS]; int width, height; int shaderNum; in = (void *)(cmod_base + surfs->fileofs); if (surfs->filelen % sizeof(*in)) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); cm.numSurfaces = count = surfs->filelen / sizeof(*in); cm.surfaces = Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ) ); dv = (void *)(cmod_base + verts->fileofs); if (verts->filelen % sizeof(*dv)) Com_Error( ERR_DROP, "%s: funny lump size", __func__ ); // scan through all the surfaces, but only load patches, // not planar faces for ( i = 0 ; i < count ; i++, in++ ) { if ( LittleLong( in->surfaceType ) != MST_PATCH ) { continue; // ignore other surfaces } // FIXME: check for non-colliding patches cm.surfaces[ i ] = patch = Hunk_Alloc( sizeof( *patch ) ); // load the full drawverts onto the stack width = LittleLong( in->patchWidth ); height = LittleLong( in->patchHeight ); c = width * height; if ( c > MAX_PATCH_VERTS ) { Com_Error( ERR_DROP, "%s: MAX_PATCH_VERTS", __func__ ); } dv_p = dv + LittleLong( in->firstVert ); for ( j = 0 ; j < c ; j++, dv_p++ ) { points[j][0] = LittleFloat( dv_p->xyz[0] ); points[j][1] = LittleFloat( dv_p->xyz[1] ); points[j][2] = LittleFloat( dv_p->xyz[2] ); } shaderNum = LittleLong( in->shaderNum ); patch->contents = cm.shaders[shaderNum].contentFlags; patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags; // create the internal facet structure patch->pc = CM_GeneratePatchCollide( width, height, points ); } } //================================================================== #ifdef USE_BSP_COLMODELS static void CM_MapList_f(void) { int count = 0; Com_Printf ("-----------------------\n"); for(int i = 0; i < MAX_NUM_MAPS; i++) { if(!cmWorlds[i].name[0]) break; count++; Com_Printf("%s\n", cmWorlds[i].name); } Com_Printf ("%i total maps\n", count); Com_Printf ("------------------\n"); } #endif /* ================== CM_LoadMap Loads in the map and all submodels ================== */ #ifdef USE_BSP_COLMODELS int CM_LoadMap( const char *name, qboolean clientload, int *checksum ) { #else void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) { #endif void *buf; int i; dheader_t header; int length; #ifdef USE_BSP_COLMODELS int outModel = 0; #endif if ( !name || !name[0] ) { Com_Error( ERR_DROP, "%s: NULL name", __func__ ); } #ifdef USE_BSP_COLMODELS int j, empty = -1; for(j = 0; j < MAX_NUM_MAPS; j++) { if ( !strcmp( cmWorlds[j].name, name ) /* && clientload */ ) { *checksum = cmWorlds[j].checksum; cmi = 0; return cmWorlds[j].brushIndex; } else if (cmWorlds[j].name[0] == '\0' && empty == -1) { // fill the next empty clipmap slot empty = j; } } cmi = empty; Com_DPrintf( "%s( '%s', %i )\n", __func__, name, clientload ); if(cmi == 0) { #endif #ifndef BSPC cm_noAreas = Cvar_Get( "cm_noAreas", "0", CVAR_CHEAT ); cm_noCurves = Cvar_Get( "cm_noCurves", "0", CVAR_CHEAT ); cm_playerCurveClip = Cvar_Get( "cm_playerCurveClip", "1", CVAR_ARCHIVE | CVAR_CHEAT ); #endif #ifdef USE_BSP_COLMODELS Cmd_AddCommand("cmlist", CM_MapList_f); #endif #ifdef USE_BSP_COLMODELS } #endif Com_DPrintf( "%s( '%s', %i )\n", __func__, name, clientload ); #ifndef USE_BSP_COLMODELS if ( !strcmp( cm.name, name ) && clientload ) { *checksum = cm.checksum; return; } // free old stuff CM_ClearMap(); #endif #ifdef USE_BSP_COLMODELS for(i = 0; i < MAX_NUM_MAPS && i < empty; i++) { outModel += cmWorlds[i].numSubModels; } #endif // // load the file // #ifndef BSPC length = FS_ReadFile( name, &buf ); #else length = LoadQuakeFile( (quakefile_t *) name, &buf ); #endif #ifdef USE_BSP_COLMODELS if( !buf /*&& empty > 0*/ ) { cmi = 0; return 0; } else #endif if ( !buf ) { Com_Error( ERR_DROP, "%s: couldn't load %s", __func__, name ); } if ( length < sizeof( dheader_t ) ) { Com_Error( ERR_DROP, "%s: %s has truncated header", __func__, name ); } *checksum = cm.checksum = LittleLong( Com_BlockChecksum( buf, length ) ); header = *(dheader_t *)buf; for ( i = 0; i < sizeof( dheader_t ) / sizeof( int32_t ); i++ ) { ( (int32_t *)&header )[i] = LittleLong( ( (int32_t *)&header )[i] ); } if ( header.version != BSP_VERSION ) { Com_Error( ERR_DROP, "%s: %s has wrong version number (%i should be %i)", __func__, name, header.version, BSP_VERSION ); } for ( i = 0; i < HEADER_LUMPS; i++ ) { int32_t ofs = header.lumps[i].fileofs; int32_t len = header.lumps[i].filelen; if ( (uint32_t)ofs > MAX_QINT || (uint32_t)len > MAX_QINT || ofs + len > length || ofs + len < 0 ) { Com_Error( ERR_DROP, "%s: %s has wrong lump[%i] size/offset", __func__, name, i ); } } cmod_base = (byte *)buf; // load into heap CMod_LoadShaders( &header.lumps[LUMP_SHADERS] ); CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]); CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]); CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]); CMod_LoadPlanes (&header.lumps[LUMP_PLANES]); CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]); CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]); CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]); CMod_LoadNodes (&header.lumps[LUMP_NODES]); CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]); CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] ); CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] ); CMod_CheckLeafBrushes(); // we are NOT freeing the file, because it is cached for the ref FS_FreeFile( buf ); CM_InitBoxHull(); CM_FloodAreaConnections(); // allow this to be cached if it is loaded by the server if ( !clientload ) { Q_strncpyz( cm.name, name, sizeof( cm.name ) ); } #ifdef USE_BSP_COLMODELS cm.brushIndex = outModel; cmi = 0; return outModel; #endif } /* ================== CM_ClearMap ================== */ void CM_ClearMap( void ) { #ifdef USE_BSP_COLMODELS Com_Memset( &cmWorlds, 0, sizeof( cmWorlds ) ); #else Com_Memset( &cm, 0, sizeof( cm ) ); #endif CM_ClearLevelPatches(); } /* ================== CM_ClipHandleToModel ================== */ cmodel_t *CM_ClipHandleToModel( clipHandle_t handle ) { if ( handle < 0 ) { Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle ); } #ifdef USE_BSP_COLMODELS if(handle >= cm.numSubModels) { int i; int modifiedHandle = (int)handle; for(i = 0; i < MAX_NUM_MAPS; i++) { if ( modifiedHandle < cmWorlds[i].numSubModels ) { return &cmWorlds[i].cmodels[modifiedHandle]; } modifiedHandle -= cmWorlds[i].numSubModels; } } #endif if ( handle < cm.numSubModels ) { return &cm.cmodels[handle]; } if ( handle == BOX_MODEL_HANDLE ) { return &box_model; } if ( handle < MAX_SUBMODELS ) { Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i", cm.numSubModels, handle, MAX_SUBMODELS ); } Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS ); return NULL; } /* ================== CM_InlineModel ================== */ #ifdef USE_BSP_COLMODELS clipHandle_t CM_InlineModel( int index ) { int i; int modifiedIndex = index; for(i = 0; i < MAX_NUM_MAPS; i++) { if ( modifiedIndex >= 0 && modifiedIndex < cmWorlds[i].numSubModels ) { return index; } modifiedIndex -= cmWorlds[i].numSubModels; } if ( index < 0 || index >= cm.numSubModels ) { Com_Error (ERR_DROP, "CM_InlineModel: bad number %i >= %i", index, cm.numSubModels); } return index; } #else clipHandle_t CM_InlineModel( int index ) { if ( index < 0 || index >= cm.numSubModels ) { Com_Error (ERR_DROP, "CM_InlineModel: bad number"); } return index; } #endif int CM_NumClusters( void ) { return cm.numClusters; } int CM_NumInlineModels( void ) { return cm.numSubModels; } char *CM_EntityString( void ) { return cm.entityString; } int CM_LeafCluster( int leafnum ) { if ( leafnum < 0 || leafnum >= cm.numLeafs ) { Com_Error( ERR_DROP, "CM_LeafCluster: bad number" ); } return cm.leafs[leafnum].cluster; } int CM_LeafArea( int leafnum ) { if ( leafnum < 0 || leafnum >= cm.numLeafs ) { Com_Error( ERR_DROP, "CM_LeafArea: bad number" ); } return cm.leafs[leafnum].area; } //======================================================================= /* =================== CM_InitBoxHull Set up the planes and nodes so that the six floats of a bounding box can just be stored out and get a proper clipping hull structure. =================== */ static void CM_InitBoxHull( void ) { int i; int side; cplane_t *p; cbrushside_t *s; box_planes = &cm.planes[cm.numPlanes]; box_brush = &cm.brushes[cm.numBrushes]; box_brush->numsides = 6; box_brush->sides = cm.brushsides + cm.numBrushSides; box_brush->contents = CONTENTS_BODY; box_model.leaf.numLeafBrushes = 1; // box_model.leaf.firstLeafBrush = cm.numBrushes; box_model.leaf.firstLeafBrush = cm.numLeafBrushes; cm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes; for ( i = 0; i < 6; i++ ) { side = i & 1; // brush sides s = &cm.brushsides[cm.numBrushSides + i]; s->plane = cm.planes + ( cm.numPlanes + i * 2 + side ); s->surfaceFlags = 0; // planes p = &box_planes[i * 2]; p->type = i >> 1; p->signbits = 0; VectorClear( p->normal ); p->normal[i >> 1] = 1; p = &box_planes[i * 2 + 1]; p->type = 3 + ( i >> 1 ); p->signbits = 0; VectorClear( p->normal ); p->normal[i >> 1] = -1; SetPlaneSignbits( p ); } } /* =================== CM_TempBoxModel To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being compared directly. =================== */ clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { VectorCopy( mins, box_model.mins ); VectorCopy( maxs, box_model.maxs ); box_planes[0].dist = maxs[0]; box_planes[1].dist = -maxs[0]; box_planes[2].dist = mins[0]; box_planes[3].dist = -mins[0]; box_planes[4].dist = maxs[1]; box_planes[5].dist = -maxs[1]; box_planes[6].dist = mins[1]; box_planes[7].dist = -mins[1]; box_planes[8].dist = maxs[2]; box_planes[9].dist = -maxs[2]; box_planes[10].dist = mins[2]; box_planes[11].dist = -mins[2]; VectorCopy( mins, box_brush->bounds[0] ); VectorCopy( maxs, box_brush->bounds[1] ); return BOX_MODEL_HANDLE; } /* =================== CM_ModelBounds =================== */ void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) { cmodel_t *cmod; cmod = CM_ClipHandleToModel( model ); VectorCopy( cmod->mins, mins ); VectorCopy( cmod->maxs, maxs ); }