Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cm_load.c (20416B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // cmodel.c -- model loading
     23 
     24 #include "cm_local.h"
     25 
     26 #ifdef BSPC
     27 
     28 #include "../bspc/l_qfiles.h"
     29 
     30 void SetPlaneSignbits (cplane_t *out) {
     31 	int	bits, j;
     32 
     33 	// for fast box on planeside test
     34 	bits = 0;
     35 	for (j=0 ; j<3 ; j++) {
     36 		if (out->normal[j] < 0) {
     37 			bits |= 1<<j;
     38 		}
     39 	}
     40 	out->signbits = bits;
     41 }
     42 #endif //BSPC
     43 
     44 // to allow boxes to be treated as brush models, we allocate
     45 // some extra indexes along with those needed by the map
     46 #define	BOX_BRUSHES		1
     47 #define	BOX_SIDES		6
     48 #define	BOX_LEAFS		2
     49 #define	BOX_PLANES		12
     50 
     51 #define	LL(x) x=LittleLong(x)
     52 
     53 
     54 clipMap_t	cm;
     55 int			c_pointcontents;
     56 int			c_traces, c_brush_traces, c_patch_traces;
     57 
     58 
     59 byte		*cmod_base;
     60 
     61 #ifndef BSPC
     62 cvar_t		*cm_noAreas;
     63 cvar_t		*cm_noCurves;
     64 cvar_t		*cm_playerCurveClip;
     65 #endif
     66 
     67 cmodel_t	box_model;
     68 cplane_t	*box_planes;
     69 cbrush_t	*box_brush;
     70 
     71 
     72 
     73 void	CM_InitBoxHull (void);
     74 void	CM_FloodAreaConnections (void);
     75 
     76 
     77 /*
     78 ===============================================================================
     79 
     80 					MAP LOADING
     81 
     82 ===============================================================================
     83 */
     84 
     85 /*
     86 =================
     87 CMod_LoadShaders
     88 =================
     89 */
     90 void CMod_LoadShaders( lump_t *l ) {
     91 	dshader_t	*in, *out;
     92 	int			i, count;
     93 
     94 	in = (void *)(cmod_base + l->fileofs);
     95 	if (l->filelen % sizeof(*in)) {
     96 		Com_Error (ERR_DROP, "CMod_LoadShaders: funny lump size");
     97 	}
     98 	count = l->filelen / sizeof(*in);
     99 
    100 	if (count < 1) {
    101 		Com_Error (ERR_DROP, "Map with no shaders");
    102 	}
    103 	cm.shaders = Hunk_Alloc( count * sizeof( *cm.shaders ), h_high );
    104 	cm.numShaders = count;
    105 
    106 	Com_Memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) );
    107 
    108 	out = cm.shaders;
    109 	for ( i=0 ; i<count ; i++, in++, out++ ) {
    110 		out->contentFlags = LittleLong( out->contentFlags );
    111 		out->surfaceFlags = LittleLong( out->surfaceFlags );
    112 	}
    113 }
    114 
    115 
    116 /*
    117 =================
    118 CMod_LoadSubmodels
    119 =================
    120 */
    121 void CMod_LoadSubmodels( lump_t *l ) {
    122 	dmodel_t	*in;
    123 	cmodel_t	*out;
    124 	int			i, j, count;
    125 	int			*indexes;
    126 
    127 	in = (void *)(cmod_base + l->fileofs);
    128 	if (l->filelen % sizeof(*in))
    129 		Com_Error (ERR_DROP, "CMod_LoadSubmodels: funny lump size");
    130 	count = l->filelen / sizeof(*in);
    131 
    132 	if (count < 1)
    133 		Com_Error (ERR_DROP, "Map with no models");
    134 	cm.cmodels = Hunk_Alloc( count * sizeof( *cm.cmodels ), h_high );
    135 	cm.numSubModels = count;
    136 
    137 	if ( count > MAX_SUBMODELS ) {
    138 		Com_Error( ERR_DROP, "MAX_SUBMODELS exceeded" );
    139 	}
    140 
    141 	for ( i=0 ; i<count ; i++, in++, out++)
    142 	{
    143 		out = &cm.cmodels[i];
    144 
    145 		for (j=0 ; j<3 ; j++)
    146 		{	// spread the mins / maxs by a pixel
    147 			out->mins[j] = LittleFloat (in->mins[j]) - 1;
    148 			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
    149 		}
    150 
    151 		if ( i == 0 ) {
    152 			continue;	// world model doesn't need other info
    153 		}
    154 
    155 		// make a "leaf" just to hold the model's brushes and surfaces
    156 		out->leaf.numLeafBrushes = LittleLong( in->numBrushes );
    157 		indexes = Hunk_Alloc( out->leaf.numLeafBrushes * 4, h_high );
    158 		out->leaf.firstLeafBrush = indexes - cm.leafbrushes;
    159 		for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {
    160 			indexes[j] = LittleLong( in->firstBrush ) + j;
    161 		}
    162 
    163 		out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );
    164 		indexes = Hunk_Alloc( out->leaf.numLeafSurfaces * 4, h_high );
    165 		out->leaf.firstLeafSurface = indexes - cm.leafsurfaces;
    166 		for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {
    167 			indexes[j] = LittleLong( in->firstSurface ) + j;
    168 		}
    169 	}
    170 }
    171 
    172 
    173 /*
    174 =================
    175 CMod_LoadNodes
    176 
    177 =================
    178 */
    179 void CMod_LoadNodes( lump_t *l ) {
    180 	dnode_t		*in;
    181 	int			child;
    182 	cNode_t		*out;
    183 	int			i, j, count;
    184 	
    185 	in = (void *)(cmod_base + l->fileofs);
    186 	if (l->filelen % sizeof(*in))
    187 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    188 	count = l->filelen / sizeof(*in);
    189 
    190 	if (count < 1)
    191 		Com_Error (ERR_DROP, "Map has no nodes");
    192 	cm.nodes = Hunk_Alloc( count * sizeof( *cm.nodes ), h_high );
    193 	cm.numNodes = count;
    194 
    195 	out = cm.nodes;
    196 
    197 	for (i=0 ; i<count ; i++, out++, in++)
    198 	{
    199 		out->plane = cm.planes + LittleLong( in->planeNum );
    200 		for (j=0 ; j<2 ; j++)
    201 		{
    202 			child = LittleLong (in->children[j]);
    203 			out->children[j] = child;
    204 		}
    205 	}
    206 
    207 }
    208 
    209 /*
    210 =================
    211 CM_BoundBrush
    212 
    213 =================
    214 */
    215 void CM_BoundBrush( cbrush_t *b ) {
    216 	b->bounds[0][0] = -b->sides[0].plane->dist;
    217 	b->bounds[1][0] = b->sides[1].plane->dist;
    218 
    219 	b->bounds[0][1] = -b->sides[2].plane->dist;
    220 	b->bounds[1][1] = b->sides[3].plane->dist;
    221 
    222 	b->bounds[0][2] = -b->sides[4].plane->dist;
    223 	b->bounds[1][2] = b->sides[5].plane->dist;
    224 }
    225 
    226 
    227 /*
    228 =================
    229 CMod_LoadBrushes
    230 
    231 =================
    232 */
    233 void CMod_LoadBrushes( lump_t *l ) {
    234 	dbrush_t	*in;
    235 	cbrush_t	*out;
    236 	int			i, count;
    237 
    238 	in = (void *)(cmod_base + l->fileofs);
    239 	if (l->filelen % sizeof(*in)) {
    240 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    241 	}
    242 	count = l->filelen / sizeof(*in);
    243 
    244 	cm.brushes = Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), h_high );
    245 	cm.numBrushes = count;
    246 
    247 	out = cm.brushes;
    248 
    249 	for ( i=0 ; i<count ; i++, out++, in++ ) {
    250 		out->sides = cm.brushsides + LittleLong(in->firstSide);
    251 		out->numsides = LittleLong(in->numSides);
    252 
    253 		out->shaderNum = LittleLong( in->shaderNum );
    254 		if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
    255 			Com_Error( ERR_DROP, "CMod_LoadBrushes: bad shaderNum: %i", out->shaderNum );
    256 		}
    257 		out->contents = cm.shaders[out->shaderNum].contentFlags;
    258 
    259 		CM_BoundBrush( out );
    260 	}
    261 
    262 }
    263 
    264 /*
    265 =================
    266 CMod_LoadLeafs
    267 =================
    268 */
    269 void CMod_LoadLeafs (lump_t *l)
    270 {
    271 	int			i;
    272 	cLeaf_t		*out;
    273 	dleaf_t 	*in;
    274 	int			count;
    275 	
    276 	in = (void *)(cmod_base + l->fileofs);
    277 	if (l->filelen % sizeof(*in))
    278 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    279 	count = l->filelen / sizeof(*in);
    280 
    281 	if (count < 1)
    282 		Com_Error (ERR_DROP, "Map with no leafs");
    283 
    284 	cm.leafs = Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), h_high );
    285 	cm.numLeafs = count;
    286 
    287 	out = cm.leafs;	
    288 	for ( i=0 ; i<count ; i++, in++, out++)
    289 	{
    290 		out->cluster = LittleLong (in->cluster);
    291 		out->area = LittleLong (in->area);
    292 		out->firstLeafBrush = LittleLong (in->firstLeafBrush);
    293 		out->numLeafBrushes = LittleLong (in->numLeafBrushes);
    294 		out->firstLeafSurface = LittleLong (in->firstLeafSurface);
    295 		out->numLeafSurfaces = LittleLong (in->numLeafSurfaces);
    296 
    297 		if (out->cluster >= cm.numClusters)
    298 			cm.numClusters = out->cluster + 1;
    299 		if (out->area >= cm.numAreas)
    300 			cm.numAreas = out->area + 1;
    301 	}
    302 
    303 	cm.areas = Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ), h_high );
    304 	cm.areaPortals = Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), h_high );
    305 }
    306 
    307 /*
    308 =================
    309 CMod_LoadPlanes
    310 =================
    311 */
    312 void CMod_LoadPlanes (lump_t *l)
    313 {
    314 	int			i, j;
    315 	cplane_t	*out;
    316 	dplane_t 	*in;
    317 	int			count;
    318 	int			bits;
    319 	
    320 	in = (void *)(cmod_base + l->fileofs);
    321 	if (l->filelen % sizeof(*in))
    322 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    323 	count = l->filelen / sizeof(*in);
    324 
    325 	if (count < 1)
    326 		Com_Error (ERR_DROP, "Map with no planes");
    327 	cm.planes = Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), h_high );
    328 	cm.numPlanes = count;
    329 
    330 	out = cm.planes;	
    331 
    332 	for ( i=0 ; i<count ; i++, in++, out++)
    333 	{
    334 		bits = 0;
    335 		for (j=0 ; j<3 ; j++)
    336 		{
    337 			out->normal[j] = LittleFloat (in->normal[j]);
    338 			if (out->normal[j] < 0)
    339 				bits |= 1<<j;
    340 		}
    341 
    342 		out->dist = LittleFloat (in->dist);
    343 		out->type = PlaneTypeForNormal( out->normal );
    344 		out->signbits = bits;
    345 	}
    346 }
    347 
    348 /*
    349 =================
    350 CMod_LoadLeafBrushes
    351 =================
    352 */
    353 void CMod_LoadLeafBrushes (lump_t *l)
    354 {
    355 	int			i;
    356 	int			*out;
    357 	int		 	*in;
    358 	int			count;
    359 	
    360 	in = (void *)(cmod_base + l->fileofs);
    361 	if (l->filelen % sizeof(*in))
    362 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    363 	count = l->filelen / sizeof(*in);
    364 
    365 	cm.leafbrushes = Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ), h_high );
    366 	cm.numLeafBrushes = count;
    367 
    368 	out = cm.leafbrushes;
    369 
    370 	for ( i=0 ; i<count ; i++, in++, out++) {
    371 		*out = LittleLong (*in);
    372 	}
    373 }
    374 
    375 /*
    376 =================
    377 CMod_LoadLeafSurfaces
    378 =================
    379 */
    380 void CMod_LoadLeafSurfaces( lump_t *l )
    381 {
    382 	int			i;
    383 	int			*out;
    384 	int		 	*in;
    385 	int			count;
    386 	
    387 	in = (void *)(cmod_base + l->fileofs);
    388 	if (l->filelen % sizeof(*in))
    389 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    390 	count = l->filelen / sizeof(*in);
    391 
    392 	cm.leafsurfaces = Hunk_Alloc( count * sizeof( *cm.leafsurfaces ), h_high );
    393 	cm.numLeafSurfaces = count;
    394 
    395 	out = cm.leafsurfaces;
    396 
    397 	for ( i=0 ; i<count ; i++, in++, out++) {
    398 		*out = LittleLong (*in);
    399 	}
    400 }
    401 
    402 /*
    403 =================
    404 CMod_LoadBrushSides
    405 =================
    406 */
    407 void CMod_LoadBrushSides (lump_t *l)
    408 {
    409 	int				i;
    410 	cbrushside_t	*out;
    411 	dbrushside_t 	*in;
    412 	int				count;
    413 	int				num;
    414 
    415 	in = (void *)(cmod_base + l->fileofs);
    416 	if ( l->filelen % sizeof(*in) ) {
    417 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    418 	}
    419 	count = l->filelen / sizeof(*in);
    420 
    421 	cm.brushsides = Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), h_high );
    422 	cm.numBrushSides = count;
    423 
    424 	out = cm.brushsides;	
    425 
    426 	for ( i=0 ; i<count ; i++, in++, out++) {
    427 		num = LittleLong( in->planeNum );
    428 		out->plane = &cm.planes[num];
    429 		out->shaderNum = LittleLong( in->shaderNum );
    430 		if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
    431 			Com_Error( ERR_DROP, "CMod_LoadBrushSides: bad shaderNum: %i", out->shaderNum );
    432 		}
    433 		out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;
    434 	}
    435 }
    436 
    437 
    438 /*
    439 =================
    440 CMod_LoadEntityString
    441 =================
    442 */
    443 void CMod_LoadEntityString( lump_t *l ) {
    444 	cm.entityString = Hunk_Alloc( l->filelen, h_high );
    445 	cm.numEntityChars = l->filelen;
    446 	Com_Memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);
    447 }
    448 
    449 /*
    450 =================
    451 CMod_LoadVisibility
    452 =================
    453 */
    454 #define	VIS_HEADER	8
    455 void CMod_LoadVisibility( lump_t *l ) {
    456 	int		len;
    457 	byte	*buf;
    458 
    459     len = l->filelen;
    460 	if ( !len ) {
    461 		cm.clusterBytes = ( cm.numClusters + 31 ) & ~31;
    462 		cm.visibility = Hunk_Alloc( cm.clusterBytes, h_high );
    463 		Com_Memset( cm.visibility, 255, cm.clusterBytes );
    464 		return;
    465 	}
    466 	buf = cmod_base + l->fileofs;
    467 
    468 	cm.vised = qtrue;
    469 	cm.visibility = Hunk_Alloc( len, h_high );
    470 	cm.numClusters = LittleLong( ((int *)buf)[0] );
    471 	cm.clusterBytes = LittleLong( ((int *)buf)[1] );
    472 	Com_Memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );
    473 }
    474 
    475 //==================================================================
    476 
    477 
    478 /*
    479 =================
    480 CMod_LoadPatches
    481 =================
    482 */
    483 #define	MAX_PATCH_VERTS		1024
    484 void CMod_LoadPatches( lump_t *surfs, lump_t *verts ) {
    485 	drawVert_t	*dv, *dv_p;
    486 	dsurface_t	*in;
    487 	int			count;
    488 	int			i, j;
    489 	int			c;
    490 	cPatch_t	*patch;
    491 	vec3_t		points[MAX_PATCH_VERTS];
    492 	int			width, height;
    493 	int			shaderNum;
    494 
    495 	in = (void *)(cmod_base + surfs->fileofs);
    496 	if (surfs->filelen % sizeof(*in))
    497 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    498 	cm.numSurfaces = count = surfs->filelen / sizeof(*in);
    499 	cm.surfaces = Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), h_high );
    500 
    501 	dv = (void *)(cmod_base + verts->fileofs);
    502 	if (verts->filelen % sizeof(*dv))
    503 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    504 
    505 	// scan through all the surfaces, but only load patches,
    506 	// not planar faces
    507 	for ( i = 0 ; i < count ; i++, in++ ) {
    508 		if ( LittleLong( in->surfaceType ) != MST_PATCH ) {
    509 			continue;		// ignore other surfaces
    510 		}
    511 		// FIXME: check for non-colliding patches
    512 
    513 		cm.surfaces[ i ] = patch = Hunk_Alloc( sizeof( *patch ), h_high );
    514 
    515 		// load the full drawverts onto the stack
    516 		width = LittleLong( in->patchWidth );
    517 		height = LittleLong( in->patchHeight );
    518 		c = width * height;
    519 		if ( c > MAX_PATCH_VERTS ) {
    520 			Com_Error( ERR_DROP, "ParseMesh: MAX_PATCH_VERTS" );
    521 		}
    522 
    523 		dv_p = dv + LittleLong( in->firstVert );
    524 		for ( j = 0 ; j < c ; j++, dv_p++ ) {
    525 			points[j][0] = LittleFloat( dv_p->xyz[0] );
    526 			points[j][1] = LittleFloat( dv_p->xyz[1] );
    527 			points[j][2] = LittleFloat( dv_p->xyz[2] );
    528 		}
    529 
    530 		shaderNum = LittleLong( in->shaderNum );
    531 		patch->contents = cm.shaders[shaderNum].contentFlags;
    532 		patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;
    533 
    534 		// create the internal facet structure
    535 		patch->pc = CM_GeneratePatchCollide( width, height, points );
    536 	}
    537 }
    538 
    539 //==================================================================
    540 
    541 unsigned CM_LumpChecksum(lump_t *lump) {
    542 	return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));
    543 }
    544 
    545 unsigned CM_Checksum(dheader_t *header) {
    546 	unsigned checksums[16];
    547 	checksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);
    548 	checksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);
    549 	checksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);
    550 	checksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);
    551 	checksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);
    552 	checksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);
    553 	checksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);
    554 	checksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);
    555 	checksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);
    556 	checksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);
    557 	checksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);
    558 
    559 	return LittleLong(Com_BlockChecksum(checksums, 11 * 4));
    560 }
    561 
    562 /*
    563 ==================
    564 CM_LoadMap
    565 
    566 Loads in the map and all submodels
    567 ==================
    568 */
    569 void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
    570 	int				*buf;
    571 	int				i;
    572 	dheader_t		header;
    573 	int				length;
    574 	static unsigned	last_checksum;
    575 
    576 	if ( !name || !name[0] ) {
    577 		Com_Error( ERR_DROP, "CM_LoadMap: NULL name" );
    578 	}
    579 
    580 #ifndef BSPC
    581 	cm_noAreas = Cvar_Get ("cm_noAreas", "0", CVAR_CHEAT);
    582 	cm_noCurves = Cvar_Get ("cm_noCurves", "0", CVAR_CHEAT);
    583 	cm_playerCurveClip = Cvar_Get ("cm_playerCurveClip", "1", CVAR_ARCHIVE|CVAR_CHEAT );
    584 #endif
    585 	Com_DPrintf( "CM_LoadMap( %s, %i )\n", name, clientload );
    586 
    587 	if ( !strcmp( cm.name, name ) && clientload ) {
    588 		*checksum = last_checksum;
    589 		return;
    590 	}
    591 
    592 	// free old stuff
    593 	Com_Memset( &cm, 0, sizeof( cm ) );
    594 	CM_ClearLevelPatches();
    595 
    596 	if ( !name[0] ) {
    597 		cm.numLeafs = 1;
    598 		cm.numClusters = 1;
    599 		cm.numAreas = 1;
    600 		cm.cmodels = Hunk_Alloc( sizeof( *cm.cmodels ), h_high );
    601 		*checksum = 0;
    602 		return;
    603 	}
    604 
    605 	//
    606 	// load the file
    607 	//
    608 #ifndef BSPC
    609 	length = FS_ReadFile( name, (void **)&buf );
    610 #else
    611 	length = LoadQuakeFile((quakefile_t *) name, (void **)&buf);
    612 #endif
    613 
    614 	if ( !buf ) {
    615 		Com_Error (ERR_DROP, "Couldn't load %s", name);
    616 	}
    617 
    618 	last_checksum = LittleLong (Com_BlockChecksum (buf, length));
    619 	*checksum = last_checksum;
    620 
    621 	header = *(dheader_t *)buf;
    622 	for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
    623 		((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
    624 	}
    625 
    626 	if ( header.version != BSP_VERSION ) {
    627 		Com_Error (ERR_DROP, "CM_LoadMap: %s has wrong version number (%i should be %i)"
    628 		, name, header.version, BSP_VERSION );
    629 	}
    630 
    631 	cmod_base = (byte *)buf;
    632 
    633 	// load into heap
    634 	CMod_LoadShaders( &header.lumps[LUMP_SHADERS] );
    635 	CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
    636 	CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
    637 	CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]);
    638 	CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
    639 	CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
    640 	CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
    641 	CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
    642 	CMod_LoadNodes (&header.lumps[LUMP_NODES]);
    643 	CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
    644 	CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] );
    645 	CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] );
    646 
    647 	// we are NOT freeing the file, because it is cached for the ref
    648 	FS_FreeFile (buf);
    649 
    650 	CM_InitBoxHull ();
    651 
    652 	CM_FloodAreaConnections ();
    653 
    654 	// allow this to be cached if it is loaded by the server
    655 	if ( !clientload ) {
    656 		Q_strncpyz( cm.name, name, sizeof( cm.name ) );
    657 	}
    658 }
    659 
    660 /*
    661 ==================
    662 CM_ClearMap
    663 ==================
    664 */
    665 void CM_ClearMap( void ) {
    666 	Com_Memset( &cm, 0, sizeof( cm ) );
    667 	CM_ClearLevelPatches();
    668 }
    669 
    670 /*
    671 ==================
    672 CM_ClipHandleToModel
    673 ==================
    674 */
    675 cmodel_t	*CM_ClipHandleToModel( clipHandle_t handle ) {
    676 	if ( handle < 0 ) {
    677 		Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle );
    678 	}
    679 	if ( handle < cm.numSubModels ) {
    680 		return &cm.cmodels[handle];
    681 	}
    682 	if ( handle == BOX_MODEL_HANDLE ) {
    683 		return &box_model;
    684 	}
    685 	if ( handle < MAX_SUBMODELS ) {
    686 		Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i", 
    687 			cm.numSubModels, handle, MAX_SUBMODELS );
    688 	}
    689 	Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS );
    690 
    691 	return NULL;
    692 
    693 }
    694 
    695 /*
    696 ==================
    697 CM_InlineModel
    698 ==================
    699 */
    700 clipHandle_t	CM_InlineModel( int index ) {
    701 	if ( index < 0 || index >= cm.numSubModels ) {
    702 		Com_Error (ERR_DROP, "CM_InlineModel: bad number");
    703 	}
    704 	return index;
    705 }
    706 
    707 int		CM_NumClusters( void ) {
    708 	return cm.numClusters;
    709 }
    710 
    711 int		CM_NumInlineModels( void ) {
    712 	return cm.numSubModels;
    713 }
    714 
    715 char	*CM_EntityString( void ) {
    716 	return cm.entityString;
    717 }
    718 
    719 int		CM_LeafCluster( int leafnum ) {
    720 	if (leafnum < 0 || leafnum >= cm.numLeafs) {
    721 		Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
    722 	}
    723 	return cm.leafs[leafnum].cluster;
    724 }
    725 
    726 int		CM_LeafArea( int leafnum ) {
    727 	if ( leafnum < 0 || leafnum >= cm.numLeafs ) {
    728 		Com_Error (ERR_DROP, "CM_LeafArea: bad number");
    729 	}
    730 	return cm.leafs[leafnum].area;
    731 }
    732 
    733 //=======================================================================
    734 
    735 
    736 /*
    737 ===================
    738 CM_InitBoxHull
    739 
    740 Set up the planes and nodes so that the six floats of a bounding box
    741 can just be stored out and get a proper clipping hull structure.
    742 ===================
    743 */
    744 void CM_InitBoxHull (void)
    745 {
    746 	int			i;
    747 	int			side;
    748 	cplane_t	*p;
    749 	cbrushside_t	*s;
    750 
    751 	box_planes = &cm.planes[cm.numPlanes];
    752 
    753 	box_brush = &cm.brushes[cm.numBrushes];
    754 	box_brush->numsides = 6;
    755 	box_brush->sides = cm.brushsides + cm.numBrushSides;
    756 	box_brush->contents = CONTENTS_BODY;
    757 
    758 	box_model.leaf.numLeafBrushes = 1;
    759 //	box_model.leaf.firstLeafBrush = cm.numBrushes;
    760 	box_model.leaf.firstLeafBrush = cm.numLeafBrushes;
    761 	cm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes;
    762 
    763 	for (i=0 ; i<6 ; i++)
    764 	{
    765 		side = i&1;
    766 
    767 		// brush sides
    768 		s = &cm.brushsides[cm.numBrushSides+i];
    769 		s->plane = 	cm.planes + (cm.numPlanes+i*2+side);
    770 		s->surfaceFlags = 0;
    771 
    772 		// planes
    773 		p = &box_planes[i*2];
    774 		p->type = i>>1;
    775 		p->signbits = 0;
    776 		VectorClear (p->normal);
    777 		p->normal[i>>1] = 1;
    778 
    779 		p = &box_planes[i*2+1];
    780 		p->type = 3 + (i>>1);
    781 		p->signbits = 0;
    782 		VectorClear (p->normal);
    783 		p->normal[i>>1] = -1;
    784 
    785 		SetPlaneSignbits( p );
    786 	}	
    787 }
    788 
    789 /*
    790 ===================
    791 CM_TempBoxModel
    792 
    793 To keep everything totally uniform, bounding boxes are turned into small
    794 BSP trees instead of being compared directly.
    795 Capsules are handled differently though.
    796 ===================
    797 */
    798 clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule ) {
    799 
    800 	VectorCopy( mins, box_model.mins );
    801 	VectorCopy( maxs, box_model.maxs );
    802 
    803 	if ( capsule ) {
    804 		return CAPSULE_MODEL_HANDLE;
    805 	}
    806 
    807 	box_planes[0].dist = maxs[0];
    808 	box_planes[1].dist = -maxs[0];
    809 	box_planes[2].dist = mins[0];
    810 	box_planes[3].dist = -mins[0];
    811 	box_planes[4].dist = maxs[1];
    812 	box_planes[5].dist = -maxs[1];
    813 	box_planes[6].dist = mins[1];
    814 	box_planes[7].dist = -mins[1];
    815 	box_planes[8].dist = maxs[2];
    816 	box_planes[9].dist = -maxs[2];
    817 	box_planes[10].dist = mins[2];
    818 	box_planes[11].dist = -mins[2];
    819 
    820 	VectorCopy( mins, box_brush->bounds[0] );
    821 	VectorCopy( maxs, box_brush->bounds[1] );
    822 
    823 	return BOX_MODEL_HANDLE;
    824 }
    825 
    826 /*
    827 ===================
    828 CM_ModelBounds
    829 ===================
    830 */
    831 void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
    832 	cmodel_t	*cmod;
    833 
    834 	cmod = CM_ClipHandleToModel( model );
    835 	VectorCopy( cmod->mins, mins );
    836 	VectorCopy( cmod->maxs, maxs );
    837 }
    838 
    839