Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

cmodel.c (35987B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // cmodel.c -- model loading
     21 
     22 #include "qcommon.h"
     23 
     24 typedef struct
     25 {
     26 	cplane_t	*plane;
     27 	int			children[2];		// negative numbers are leafs
     28 } cnode_t;
     29 
     30 typedef struct
     31 {
     32 	cplane_t	*plane;
     33 	mapsurface_t	*surface;
     34 } cbrushside_t;
     35 
     36 typedef struct
     37 {
     38 	int			contents;
     39 	int			cluster;
     40 	int			area;
     41 	unsigned short	firstleafbrush;
     42 	unsigned short	numleafbrushes;
     43 } cleaf_t;
     44 
     45 typedef struct
     46 {
     47 	int			contents;
     48 	int			numsides;
     49 	int			firstbrushside;
     50 	int			checkcount;		// to avoid repeated testings
     51 } cbrush_t;
     52 
     53 typedef struct
     54 {
     55 	int		numareaportals;
     56 	int		firstareaportal;
     57 	int		floodnum;			// if two areas have equal floodnums, they are connected
     58 	int		floodvalid;
     59 } carea_t;
     60 
     61 int			checkcount;
     62 
     63 char		map_name[MAX_QPATH];
     64 
     65 int			numbrushsides;
     66 cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
     67 
     68 int			numtexinfo;
     69 mapsurface_t	map_surfaces[MAX_MAP_TEXINFO];
     70 
     71 int			numplanes;
     72 cplane_t	map_planes[MAX_MAP_PLANES+6];		// extra for box hull
     73 
     74 int			numnodes;
     75 cnode_t		map_nodes[MAX_MAP_NODES+6];		// extra for box hull
     76 
     77 int			numleafs = 1;	// allow leaf funcs to be called without a map
     78 cleaf_t		map_leafs[MAX_MAP_LEAFS];
     79 int			emptyleaf, solidleaf;
     80 
     81 int			numleafbrushes;
     82 unsigned short	map_leafbrushes[MAX_MAP_LEAFBRUSHES];
     83 
     84 int			numcmodels;
     85 cmodel_t	map_cmodels[MAX_MAP_MODELS];
     86 
     87 int			numbrushes;
     88 cbrush_t	map_brushes[MAX_MAP_BRUSHES];
     89 
     90 int			numvisibility;
     91 byte		map_visibility[MAX_MAP_VISIBILITY];
     92 dvis_t		*map_vis = (dvis_t *)map_visibility;
     93 
     94 int			numentitychars;
     95 char		map_entitystring[MAX_MAP_ENTSTRING];
     96 
     97 int			numareas = 1;
     98 carea_t		map_areas[MAX_MAP_AREAS];
     99 
    100 int			numareaportals;
    101 dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
    102 
    103 int			numclusters = 1;
    104 
    105 mapsurface_t	nullsurface;
    106 
    107 int			floodvalid;
    108 
    109 qboolean	portalopen[MAX_MAP_AREAPORTALS];
    110 
    111 
    112 cvar_t		*map_noareas;
    113 
    114 void	CM_InitBoxHull (void);
    115 void	FloodAreaConnections (void);
    116 
    117 
    118 int		c_pointcontents;
    119 int		c_traces, c_brush_traces;
    120 
    121 
    122 /*
    123 ===============================================================================
    124 
    125 					MAP LOADING
    126 
    127 ===============================================================================
    128 */
    129 
    130 byte	*cmod_base;
    131 
    132 /*
    133 =================
    134 CMod_LoadSubmodels
    135 =================
    136 */
    137 void CMod_LoadSubmodels (lump_t *l)
    138 {
    139 	dmodel_t	*in;
    140 	cmodel_t	*out;
    141 	int			i, j, count;
    142 
    143 	in = (void *)(cmod_base + l->fileofs);
    144 	if (l->filelen % sizeof(*in))
    145 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    146 	count = l->filelen / sizeof(*in);
    147 
    148 	if (count < 1)
    149 		Com_Error (ERR_DROP, "Map with no models");
    150 	if (count > MAX_MAP_MODELS)
    151 		Com_Error (ERR_DROP, "Map has too many models");
    152 
    153 	numcmodels = count;
    154 
    155 	for ( i=0 ; i<count ; i++, in++, out++)
    156 	{
    157 		out = &map_cmodels[i];
    158 
    159 		for (j=0 ; j<3 ; j++)
    160 		{	// spread the mins / maxs by a pixel
    161 			out->mins[j] = LittleFloat (in->mins[j]) - 1;
    162 			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
    163 			out->origin[j] = LittleFloat (in->origin[j]);
    164 		}
    165 		out->headnode = LittleLong (in->headnode);
    166 	}
    167 }
    168 
    169 
    170 /*
    171 =================
    172 CMod_LoadSurfaces
    173 =================
    174 */
    175 void CMod_LoadSurfaces (lump_t *l)
    176 {
    177 	texinfo_t	*in;
    178 	mapsurface_t	*out;
    179 	int			i, count;
    180 
    181 	in = (void *)(cmod_base + l->fileofs);
    182 	if (l->filelen % sizeof(*in))
    183 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    184 	count = l->filelen / sizeof(*in);
    185 	if (count < 1)
    186 		Com_Error (ERR_DROP, "Map with no surfaces");
    187 	if (count > MAX_MAP_TEXINFO)
    188 		Com_Error (ERR_DROP, "Map has too many surfaces");
    189 
    190 	numtexinfo = count;
    191 	out = map_surfaces;
    192 
    193 	for ( i=0 ; i<count ; i++, in++, out++)
    194 	{
    195 		strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
    196 		strncpy (out->rname, in->texture, sizeof(out->rname)-1);
    197 		out->c.flags = LittleLong (in->flags);
    198 		out->c.value = LittleLong (in->value);
    199 	}
    200 }
    201 
    202 
    203 /*
    204 =================
    205 CMod_LoadNodes
    206 
    207 =================
    208 */
    209 void CMod_LoadNodes (lump_t *l)
    210 {
    211 	dnode_t		*in;
    212 	int			child;
    213 	cnode_t		*out;
    214 	int			i, j, count;
    215 	
    216 	in = (void *)(cmod_base + l->fileofs);
    217 	if (l->filelen % sizeof(*in))
    218 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    219 	count = l->filelen / sizeof(*in);
    220 
    221 	if (count < 1)
    222 		Com_Error (ERR_DROP, "Map has no nodes");
    223 	if (count > MAX_MAP_NODES)
    224 		Com_Error (ERR_DROP, "Map has too many nodes");
    225 
    226 	out = map_nodes;
    227 
    228 	numnodes = count;
    229 
    230 	for (i=0 ; i<count ; i++, out++, in++)
    231 	{
    232 		out->plane = map_planes + LittleLong(in->planenum);
    233 		for (j=0 ; j<2 ; j++)
    234 		{
    235 			child = LittleLong (in->children[j]);
    236 			out->children[j] = child;
    237 		}
    238 	}
    239 
    240 }
    241 
    242 /*
    243 =================
    244 CMod_LoadBrushes
    245 
    246 =================
    247 */
    248 void CMod_LoadBrushes (lump_t *l)
    249 {
    250 	dbrush_t	*in;
    251 	cbrush_t	*out;
    252 	int			i, count;
    253 	
    254 	in = (void *)(cmod_base + l->fileofs);
    255 	if (l->filelen % sizeof(*in))
    256 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    257 	count = l->filelen / sizeof(*in);
    258 
    259 	if (count > MAX_MAP_BRUSHES)
    260 		Com_Error (ERR_DROP, "Map has too many brushes");
    261 
    262 	out = map_brushes;
    263 
    264 	numbrushes = count;
    265 
    266 	for (i=0 ; i<count ; i++, out++, in++)
    267 	{
    268 		out->firstbrushside = LittleLong(in->firstside);
    269 		out->numsides = LittleLong(in->numsides);
    270 		out->contents = LittleLong(in->contents);
    271 	}
    272 
    273 }
    274 
    275 /*
    276 =================
    277 CMod_LoadLeafs
    278 =================
    279 */
    280 void CMod_LoadLeafs (lump_t *l)
    281 {
    282 	int			i;
    283 	cleaf_t		*out;
    284 	dleaf_t 	*in;
    285 	int			count;
    286 	
    287 	in = (void *)(cmod_base + l->fileofs);
    288 	if (l->filelen % sizeof(*in))
    289 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    290 	count = l->filelen / sizeof(*in);
    291 
    292 	if (count < 1)
    293 		Com_Error (ERR_DROP, "Map with no leafs");
    294 	// need to save space for box planes
    295 	if (count > MAX_MAP_PLANES)
    296 		Com_Error (ERR_DROP, "Map has too many planes");
    297 
    298 	out = map_leafs;	
    299 	numleafs = count;
    300 	numclusters = 0;
    301 
    302 	for ( i=0 ; i<count ; i++, in++, out++)
    303 	{
    304 		out->contents = LittleLong (in->contents);
    305 		out->cluster = LittleShort (in->cluster);
    306 		out->area = LittleShort (in->area);
    307 		out->firstleafbrush = LittleShort (in->firstleafbrush);
    308 		out->numleafbrushes = LittleShort (in->numleafbrushes);
    309 
    310 		if (out->cluster >= numclusters)
    311 			numclusters = out->cluster + 1;
    312 	}
    313 
    314 	if (map_leafs[0].contents != CONTENTS_SOLID)
    315 		Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
    316 	solidleaf = 0;
    317 	emptyleaf = -1;
    318 	for (i=1 ; i<numleafs ; i++)
    319 	{
    320 		if (!map_leafs[i].contents)
    321 		{
    322 			emptyleaf = i;
    323 			break;
    324 		}
    325 	}
    326 	if (emptyleaf == -1)
    327 		Com_Error (ERR_DROP, "Map does not have an empty leaf");
    328 }
    329 
    330 /*
    331 =================
    332 CMod_LoadPlanes
    333 =================
    334 */
    335 void CMod_LoadPlanes (lump_t *l)
    336 {
    337 	int			i, j;
    338 	cplane_t	*out;
    339 	dplane_t 	*in;
    340 	int			count;
    341 	int			bits;
    342 	
    343 	in = (void *)(cmod_base + l->fileofs);
    344 	if (l->filelen % sizeof(*in))
    345 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    346 	count = l->filelen / sizeof(*in);
    347 
    348 	if (count < 1)
    349 		Com_Error (ERR_DROP, "Map with no planes");
    350 	// need to save space for box planes
    351 	if (count > MAX_MAP_PLANES)
    352 		Com_Error (ERR_DROP, "Map has too many planes");
    353 
    354 	out = map_planes;	
    355 	numplanes = count;
    356 
    357 	for ( i=0 ; i<count ; i++, in++, out++)
    358 	{
    359 		bits = 0;
    360 		for (j=0 ; j<3 ; j++)
    361 		{
    362 			out->normal[j] = LittleFloat (in->normal[j]);
    363 			if (out->normal[j] < 0)
    364 				bits |= 1<<j;
    365 		}
    366 
    367 		out->dist = LittleFloat (in->dist);
    368 		out->type = LittleLong (in->type);
    369 		out->signbits = bits;
    370 	}
    371 }
    372 
    373 /*
    374 =================
    375 CMod_LoadLeafBrushes
    376 =================
    377 */
    378 void CMod_LoadLeafBrushes (lump_t *l)
    379 {
    380 	int			i;
    381 	unsigned short	*out;
    382 	unsigned short 	*in;
    383 	int			count;
    384 	
    385 	in = (void *)(cmod_base + l->fileofs);
    386 	if (l->filelen % sizeof(*in))
    387 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    388 	count = l->filelen / sizeof(*in);
    389 
    390 	if (count < 1)
    391 		Com_Error (ERR_DROP, "Map with no planes");
    392 	// need to save space for box planes
    393 	if (count > MAX_MAP_LEAFBRUSHES)
    394 		Com_Error (ERR_DROP, "Map has too many leafbrushes");
    395 
    396 	out = map_leafbrushes;
    397 	numleafbrushes = count;
    398 
    399 	for ( i=0 ; i<count ; i++, in++, out++)
    400 		*out = LittleShort (*in);
    401 }
    402 
    403 /*
    404 =================
    405 CMod_LoadBrushSides
    406 =================
    407 */
    408 void CMod_LoadBrushSides (lump_t *l)
    409 {
    410 	int			i, j;
    411 	cbrushside_t	*out;
    412 	dbrushside_t 	*in;
    413 	int			count;
    414 	int			num;
    415 
    416 	in = (void *)(cmod_base + l->fileofs);
    417 	if (l->filelen % sizeof(*in))
    418 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    419 	count = l->filelen / sizeof(*in);
    420 
    421 	// need to save space for box planes
    422 	if (count > MAX_MAP_BRUSHSIDES)
    423 		Com_Error (ERR_DROP, "Map has too many planes");
    424 
    425 	out = map_brushsides;	
    426 	numbrushsides = count;
    427 
    428 	for ( i=0 ; i<count ; i++, in++, out++)
    429 	{
    430 		num = LittleShort (in->planenum);
    431 		out->plane = &map_planes[num];
    432 		j = LittleShort (in->texinfo);
    433 		if (j >= numtexinfo)
    434 			Com_Error (ERR_DROP, "Bad brushside texinfo");
    435 		out->surface = &map_surfaces[j];
    436 	}
    437 }
    438 
    439 /*
    440 =================
    441 CMod_LoadAreas
    442 =================
    443 */
    444 void CMod_LoadAreas (lump_t *l)
    445 {
    446 	int			i;
    447 	carea_t		*out;
    448 	darea_t 	*in;
    449 	int			count;
    450 
    451 	in = (void *)(cmod_base + l->fileofs);
    452 	if (l->filelen % sizeof(*in))
    453 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    454 	count = l->filelen / sizeof(*in);
    455 
    456 	if (count > MAX_MAP_AREAS)
    457 		Com_Error (ERR_DROP, "Map has too many areas");
    458 
    459 	out = map_areas;
    460 	numareas = count;
    461 
    462 	for ( i=0 ; i<count ; i++, in++, out++)
    463 	{
    464 		out->numareaportals = LittleLong (in->numareaportals);
    465 		out->firstareaportal = LittleLong (in->firstareaportal);
    466 		out->floodvalid = 0;
    467 		out->floodnum = 0;
    468 	}
    469 }
    470 
    471 /*
    472 =================
    473 CMod_LoadAreaPortals
    474 =================
    475 */
    476 void CMod_LoadAreaPortals (lump_t *l)
    477 {
    478 	int			i;
    479 	dareaportal_t		*out;
    480 	dareaportal_t 	*in;
    481 	int			count;
    482 
    483 	in = (void *)(cmod_base + l->fileofs);
    484 	if (l->filelen % sizeof(*in))
    485 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
    486 	count = l->filelen / sizeof(*in);
    487 
    488 	if (count > MAX_MAP_AREAS)
    489 		Com_Error (ERR_DROP, "Map has too many areas");
    490 
    491 	out = map_areaportals;
    492 	numareaportals = count;
    493 
    494 	for ( i=0 ; i<count ; i++, in++, out++)
    495 	{
    496 		out->portalnum = LittleLong (in->portalnum);
    497 		out->otherarea = LittleLong (in->otherarea);
    498 	}
    499 }
    500 
    501 /*
    502 =================
    503 CMod_LoadVisibility
    504 =================
    505 */
    506 void CMod_LoadVisibility (lump_t *l)
    507 {
    508 	int		i;
    509 
    510 	numvisibility = l->filelen;
    511 	if (l->filelen > MAX_MAP_VISIBILITY)
    512 		Com_Error (ERR_DROP, "Map has too large visibility lump");
    513 
    514 	memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
    515 
    516 	map_vis->numclusters = LittleLong (map_vis->numclusters);
    517 	for (i=0 ; i<map_vis->numclusters ; i++)
    518 	{
    519 		map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
    520 		map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
    521 	}
    522 }
    523 
    524 
    525 /*
    526 =================
    527 CMod_LoadEntityString
    528 =================
    529 */
    530 void CMod_LoadEntityString (lump_t *l)
    531 {
    532 	numentitychars = l->filelen;
    533 	if (l->filelen > MAX_MAP_ENTSTRING)
    534 		Com_Error (ERR_DROP, "Map has too large entity lump");
    535 
    536 	memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
    537 }
    538 
    539 
    540 
    541 /*
    542 ==================
    543 CM_LoadMap
    544 
    545 Loads in the map and all submodels
    546 ==================
    547 */
    548 cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
    549 {
    550 	unsigned		*buf;
    551 	int				i;
    552 	dheader_t		header;
    553 	int				length;
    554 	static unsigned	last_checksum;
    555 
    556 	map_noareas = Cvar_Get ("map_noareas", "0", 0);
    557 
    558 	if (  !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
    559 	{
    560 		*checksum = last_checksum;
    561 		if (!clientload)
    562 		{
    563 			memset (portalopen, 0, sizeof(portalopen));
    564 			FloodAreaConnections ();
    565 		}
    566 		return &map_cmodels[0];		// still have the right version
    567 	}
    568 
    569 	// free old stuff
    570 	numplanes = 0;
    571 	numnodes = 0;
    572 	numleafs = 0;
    573 	numcmodels = 0;
    574 	numvisibility = 0;
    575 	numentitychars = 0;
    576 	map_entitystring[0] = 0;
    577 	map_name[0] = 0;
    578 
    579 	if (!name || !name[0])
    580 	{
    581 		numleafs = 1;
    582 		numclusters = 1;
    583 		numareas = 1;
    584 		*checksum = 0;
    585 		return &map_cmodels[0];			// cinematic servers won't have anything at all
    586 	}
    587 
    588 	//
    589 	// load the file
    590 	//
    591 	length = FS_LoadFile (name, (void **)&buf);
    592 	if (!buf)
    593 		Com_Error (ERR_DROP, "Couldn't load %s", name);
    594 
    595 	last_checksum = LittleLong (Com_BlockChecksum (buf, length));
    596 	*checksum = last_checksum;
    597 
    598 	header = *(dheader_t *)buf;
    599 	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
    600 		((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
    601 
    602 	if (header.version != BSPVERSION)
    603 		Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
    604 		, name, header.version, BSPVERSION);
    605 
    606 	cmod_base = (byte *)buf;
    607 
    608 	// load into heap
    609 	CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
    610 	CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
    611 	CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
    612 	CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
    613 	CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
    614 	CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
    615 	CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
    616 	CMod_LoadNodes (&header.lumps[LUMP_NODES]);
    617 	CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
    618 	CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
    619 	CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
    620 	CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
    621 
    622 	FS_FreeFile (buf);
    623 
    624 	CM_InitBoxHull ();
    625 
    626 	memset (portalopen, 0, sizeof(portalopen));
    627 	FloodAreaConnections ();
    628 
    629 	strcpy (map_name, name);
    630 
    631 	return &map_cmodels[0];
    632 }
    633 
    634 /*
    635 ==================
    636 CM_InlineModel
    637 ==================
    638 */
    639 cmodel_t	*CM_InlineModel (char *name)
    640 {
    641 	int		num;
    642 
    643 	if (!name || name[0] != '*')
    644 		Com_Error (ERR_DROP, "CM_InlineModel: bad name");
    645 	num = atoi (name+1);
    646 	if (num < 1 || num >= numcmodels)
    647 		Com_Error (ERR_DROP, "CM_InlineModel: bad number");
    648 
    649 	return &map_cmodels[num];
    650 }
    651 
    652 int		CM_NumClusters (void)
    653 {
    654 	return numclusters;
    655 }
    656 
    657 int		CM_NumInlineModels (void)
    658 {
    659 	return numcmodels;
    660 }
    661 
    662 char	*CM_EntityString (void)
    663 {
    664 	return map_entitystring;
    665 }
    666 
    667 int		CM_LeafContents (int leafnum)
    668 {
    669 	if (leafnum < 0 || leafnum >= numleafs)
    670 		Com_Error (ERR_DROP, "CM_LeafContents: bad number");
    671 	return map_leafs[leafnum].contents;
    672 }
    673 
    674 int		CM_LeafCluster (int leafnum)
    675 {
    676 	if (leafnum < 0 || leafnum >= numleafs)
    677 		Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
    678 	return map_leafs[leafnum].cluster;
    679 }
    680 
    681 int		CM_LeafArea (int leafnum)
    682 {
    683 	if (leafnum < 0 || leafnum >= numleafs)
    684 		Com_Error (ERR_DROP, "CM_LeafArea: bad number");
    685 	return map_leafs[leafnum].area;
    686 }
    687 
    688 //=======================================================================
    689 
    690 
    691 cplane_t	*box_planes;
    692 int			box_headnode;
    693 cbrush_t	*box_brush;
    694 cleaf_t		*box_leaf;
    695 
    696 /*
    697 ===================
    698 CM_InitBoxHull
    699 
    700 Set up the planes and nodes so that the six floats of a bounding box
    701 can just be stored out and get a proper clipping hull structure.
    702 ===================
    703 */
    704 void CM_InitBoxHull (void)
    705 {
    706 	int			i;
    707 	int			side;
    708 	cnode_t		*c;
    709 	cplane_t	*p;
    710 	cbrushside_t	*s;
    711 
    712 	box_headnode = numnodes;
    713 	box_planes = &map_planes[numplanes];
    714 	if (numnodes+6 > MAX_MAP_NODES
    715 		|| numbrushes+1 > MAX_MAP_BRUSHES
    716 		|| numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
    717 		|| numbrushsides+6 > MAX_MAP_BRUSHSIDES
    718 		|| numplanes+12 > MAX_MAP_PLANES)
    719 		Com_Error (ERR_DROP, "Not enough room for box tree");
    720 
    721 	box_brush = &map_brushes[numbrushes];
    722 	box_brush->numsides = 6;
    723 	box_brush->firstbrushside = numbrushsides;
    724 	box_brush->contents = CONTENTS_MONSTER;
    725 
    726 	box_leaf = &map_leafs[numleafs];
    727 	box_leaf->contents = CONTENTS_MONSTER;
    728 	box_leaf->firstleafbrush = numleafbrushes;
    729 	box_leaf->numleafbrushes = 1;
    730 
    731 	map_leafbrushes[numleafbrushes] = numbrushes;
    732 
    733 	for (i=0 ; i<6 ; i++)
    734 	{
    735 		side = i&1;
    736 
    737 		// brush sides
    738 		s = &map_brushsides[numbrushsides+i];
    739 		s->plane = 	map_planes + (numplanes+i*2+side);
    740 		s->surface = &nullsurface;
    741 
    742 		// nodes
    743 		c = &map_nodes[box_headnode+i];
    744 		c->plane = map_planes + (numplanes+i*2);
    745 		c->children[side] = -1 - emptyleaf;
    746 		if (i != 5)
    747 			c->children[side^1] = box_headnode+i + 1;
    748 		else
    749 			c->children[side^1] = -1 - numleafs;
    750 
    751 		// planes
    752 		p = &box_planes[i*2];
    753 		p->type = i>>1;
    754 		p->signbits = 0;
    755 		VectorClear (p->normal);
    756 		p->normal[i>>1] = 1;
    757 
    758 		p = &box_planes[i*2+1];
    759 		p->type = 3 + (i>>1);
    760 		p->signbits = 0;
    761 		VectorClear (p->normal);
    762 		p->normal[i>>1] = -1;
    763 	}	
    764 }
    765 
    766 
    767 /*
    768 ===================
    769 CM_HeadnodeForBox
    770 
    771 To keep everything totally uniform, bounding boxes are turned into small
    772 BSP trees instead of being compared directly.
    773 ===================
    774 */
    775 int	CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
    776 {
    777 	box_planes[0].dist = maxs[0];
    778 	box_planes[1].dist = -maxs[0];
    779 	box_planes[2].dist = mins[0];
    780 	box_planes[3].dist = -mins[0];
    781 	box_planes[4].dist = maxs[1];
    782 	box_planes[5].dist = -maxs[1];
    783 	box_planes[6].dist = mins[1];
    784 	box_planes[7].dist = -mins[1];
    785 	box_planes[8].dist = maxs[2];
    786 	box_planes[9].dist = -maxs[2];
    787 	box_planes[10].dist = mins[2];
    788 	box_planes[11].dist = -mins[2];
    789 
    790 	return box_headnode;
    791 }
    792 
    793 
    794 /*
    795 ==================
    796 CM_PointLeafnum_r
    797 
    798 ==================
    799 */
    800 int CM_PointLeafnum_r (vec3_t p, int num)
    801 {
    802 	float		d;
    803 	cnode_t		*node;
    804 	cplane_t	*plane;
    805 
    806 	while (num >= 0)
    807 	{
    808 		node = map_nodes + num;
    809 		plane = node->plane;
    810 		
    811 		if (plane->type < 3)
    812 			d = p[plane->type] - plane->dist;
    813 		else
    814 			d = DotProduct (plane->normal, p) - plane->dist;
    815 		if (d < 0)
    816 			num = node->children[1];
    817 		else
    818 			num = node->children[0];
    819 	}
    820 
    821 	c_pointcontents++;		// optimize counter
    822 
    823 	return -1 - num;
    824 }
    825 
    826 int CM_PointLeafnum (vec3_t p)
    827 {
    828 	if (!numplanes)
    829 		return 0;		// sound may call this without map loaded
    830 	return CM_PointLeafnum_r (p, 0);
    831 }
    832 
    833 
    834 
    835 /*
    836 =============
    837 CM_BoxLeafnums
    838 
    839 Fills in a list of all the leafs touched
    840 =============
    841 */
    842 int		leaf_count, leaf_maxcount;
    843 int		*leaf_list;
    844 float	*leaf_mins, *leaf_maxs;
    845 int		leaf_topnode;
    846 
    847 void CM_BoxLeafnums_r (int nodenum)
    848 {
    849 	cplane_t	*plane;
    850 	cnode_t		*node;
    851 	int		s;
    852 
    853 	while (1)
    854 	{
    855 		if (nodenum < 0)
    856 		{
    857 			if (leaf_count >= leaf_maxcount)
    858 			{
    859 //				Com_Printf ("CM_BoxLeafnums_r: overflow\n");
    860 				return;
    861 			}
    862 			leaf_list[leaf_count++] = -1 - nodenum;
    863 			return;
    864 		}
    865 	
    866 		node = &map_nodes[nodenum];
    867 		plane = node->plane;
    868 //		s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
    869 		s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
    870 		if (s == 1)
    871 			nodenum = node->children[0];
    872 		else if (s == 2)
    873 			nodenum = node->children[1];
    874 		else
    875 		{	// go down both
    876 			if (leaf_topnode == -1)
    877 				leaf_topnode = nodenum;
    878 			CM_BoxLeafnums_r (node->children[0]);
    879 			nodenum = node->children[1];
    880 		}
    881 
    882 	}
    883 }
    884 
    885 int	CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
    886 {
    887 	leaf_list = list;
    888 	leaf_count = 0;
    889 	leaf_maxcount = listsize;
    890 	leaf_mins = mins;
    891 	leaf_maxs = maxs;
    892 
    893 	leaf_topnode = -1;
    894 
    895 	CM_BoxLeafnums_r (headnode);
    896 
    897 	if (topnode)
    898 		*topnode = leaf_topnode;
    899 
    900 	return leaf_count;
    901 }
    902 
    903 int	CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
    904 {
    905 	return CM_BoxLeafnums_headnode (mins, maxs, list,
    906 		listsize, map_cmodels[0].headnode, topnode);
    907 }
    908 
    909 
    910 
    911 /*
    912 ==================
    913 CM_PointContents
    914 
    915 ==================
    916 */
    917 int CM_PointContents (vec3_t p, int headnode)
    918 {
    919 	int		l;
    920 
    921 	if (!numnodes)	// map not loaded
    922 		return 0;
    923 
    924 	l = CM_PointLeafnum_r (p, headnode);
    925 
    926 	return map_leafs[l].contents;
    927 }
    928 
    929 /*
    930 ==================
    931 CM_TransformedPointContents
    932 
    933 Handles offseting and rotation of the end points for moving and
    934 rotating entities
    935 ==================
    936 */
    937 int	CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
    938 {
    939 	vec3_t		p_l;
    940 	vec3_t		temp;
    941 	vec3_t		forward, right, up;
    942 	int			l;
    943 
    944 	// subtract origin offset
    945 	VectorSubtract (p, origin, p_l);
    946 
    947 	// rotate start and end into the models frame of reference
    948 	if (headnode != box_headnode && 
    949 	(angles[0] || angles[1] || angles[2]) )
    950 	{
    951 		AngleVectors (angles, forward, right, up);
    952 
    953 		VectorCopy (p_l, temp);
    954 		p_l[0] = DotProduct (temp, forward);
    955 		p_l[1] = -DotProduct (temp, right);
    956 		p_l[2] = DotProduct (temp, up);
    957 	}
    958 
    959 	l = CM_PointLeafnum_r (p_l, headnode);
    960 
    961 	return map_leafs[l].contents;
    962 }
    963 
    964 
    965 /*
    966 ===============================================================================
    967 
    968 BOX TRACING
    969 
    970 ===============================================================================
    971 */
    972 
    973 // 1/32 epsilon to keep floating point happy
    974 #define	DIST_EPSILON	(0.03125)
    975 
    976 vec3_t	trace_start, trace_end;
    977 vec3_t	trace_mins, trace_maxs;
    978 vec3_t	trace_extents;
    979 
    980 trace_t	trace_trace;
    981 int		trace_contents;
    982 qboolean	trace_ispoint;		// optimized case
    983 
    984 /*
    985 ================
    986 CM_ClipBoxToBrush
    987 ================
    988 */
    989 void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
    990 					  trace_t *trace, cbrush_t *brush)
    991 {
    992 	int			i, j;
    993 	cplane_t	*plane, *clipplane;
    994 	float		dist;
    995 	float		enterfrac, leavefrac;
    996 	vec3_t		ofs;
    997 	float		d1, d2;
    998 	qboolean	getout, startout;
    999 	float		f;
   1000 	cbrushside_t	*side, *leadside;
   1001 
   1002 	enterfrac = -1;
   1003 	leavefrac = 1;
   1004 	clipplane = NULL;
   1005 
   1006 	if (!brush->numsides)
   1007 		return;
   1008 
   1009 	c_brush_traces++;
   1010 
   1011 	getout = false;
   1012 	startout = false;
   1013 	leadside = NULL;
   1014 
   1015 	for (i=0 ; i<brush->numsides ; i++)
   1016 	{
   1017 		side = &map_brushsides[brush->firstbrushside+i];
   1018 		plane = side->plane;
   1019 
   1020 		// FIXME: special case for axial
   1021 
   1022 		if (!trace_ispoint)
   1023 		{	// general box case
   1024 
   1025 			// push the plane out apropriately for mins/maxs
   1026 
   1027 			// FIXME: use signbits into 8 way lookup for each mins/maxs
   1028 			for (j=0 ; j<3 ; j++)
   1029 			{
   1030 				if (plane->normal[j] < 0)
   1031 					ofs[j] = maxs[j];
   1032 				else
   1033 					ofs[j] = mins[j];
   1034 			}
   1035 			dist = DotProduct (ofs, plane->normal);
   1036 			dist = plane->dist - dist;
   1037 		}
   1038 		else
   1039 		{	// special point case
   1040 			dist = plane->dist;
   1041 		}
   1042 
   1043 		d1 = DotProduct (p1, plane->normal) - dist;
   1044 		d2 = DotProduct (p2, plane->normal) - dist;
   1045 
   1046 		if (d2 > 0)
   1047 			getout = true;	// endpoint is not in solid
   1048 		if (d1 > 0)
   1049 			startout = true;
   1050 
   1051 		// if completely in front of face, no intersection
   1052 		if (d1 > 0 && d2 >= d1)
   1053 			return;
   1054 
   1055 		if (d1 <= 0 && d2 <= 0)
   1056 			continue;
   1057 
   1058 		// crosses face
   1059 		if (d1 > d2)
   1060 		{	// enter
   1061 			f = (d1-DIST_EPSILON) / (d1-d2);
   1062 			if (f > enterfrac)
   1063 			{
   1064 				enterfrac = f;
   1065 				clipplane = plane;
   1066 				leadside = side;
   1067 			}
   1068 		}
   1069 		else
   1070 		{	// leave
   1071 			f = (d1+DIST_EPSILON) / (d1-d2);
   1072 			if (f < leavefrac)
   1073 				leavefrac = f;
   1074 		}
   1075 	}
   1076 
   1077 	if (!startout)
   1078 	{	// original point was inside brush
   1079 		trace->startsolid = true;
   1080 		if (!getout)
   1081 			trace->allsolid = true;
   1082 		return;
   1083 	}
   1084 	if (enterfrac < leavefrac)
   1085 	{
   1086 		if (enterfrac > -1 && enterfrac < trace->fraction)
   1087 		{
   1088 			if (enterfrac < 0)
   1089 				enterfrac = 0;
   1090 			trace->fraction = enterfrac;
   1091 			trace->plane = *clipplane;
   1092 			trace->surface = &(leadside->surface->c);
   1093 			trace->contents = brush->contents;
   1094 		}
   1095 	}
   1096 }
   1097 
   1098 /*
   1099 ================
   1100 CM_TestBoxInBrush
   1101 ================
   1102 */
   1103 void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
   1104 					  trace_t *trace, cbrush_t *brush)
   1105 {
   1106 	int			i, j;
   1107 	cplane_t	*plane;
   1108 	float		dist;
   1109 	vec3_t		ofs;
   1110 	float		d1;
   1111 	cbrushside_t	*side;
   1112 
   1113 	if (!brush->numsides)
   1114 		return;
   1115 
   1116 	for (i=0 ; i<brush->numsides ; i++)
   1117 	{
   1118 		side = &map_brushsides[brush->firstbrushside+i];
   1119 		plane = side->plane;
   1120 
   1121 		// FIXME: special case for axial
   1122 
   1123 		// general box case
   1124 
   1125 		// push the plane out apropriately for mins/maxs
   1126 
   1127 		// FIXME: use signbits into 8 way lookup for each mins/maxs
   1128 		for (j=0 ; j<3 ; j++)
   1129 		{
   1130 			if (plane->normal[j] < 0)
   1131 				ofs[j] = maxs[j];
   1132 			else
   1133 				ofs[j] = mins[j];
   1134 		}
   1135 		dist = DotProduct (ofs, plane->normal);
   1136 		dist = plane->dist - dist;
   1137 
   1138 		d1 = DotProduct (p1, plane->normal) - dist;
   1139 
   1140 		// if completely in front of face, no intersection
   1141 		if (d1 > 0)
   1142 			return;
   1143 
   1144 	}
   1145 
   1146 	// inside this brush
   1147 	trace->startsolid = trace->allsolid = true;
   1148 	trace->fraction = 0;
   1149 	trace->contents = brush->contents;
   1150 }
   1151 
   1152 
   1153 /*
   1154 ================
   1155 CM_TraceToLeaf
   1156 ================
   1157 */
   1158 void CM_TraceToLeaf (int leafnum)
   1159 {
   1160 	int			k;
   1161 	int			brushnum;
   1162 	cleaf_t		*leaf;
   1163 	cbrush_t	*b;
   1164 
   1165 	leaf = &map_leafs[leafnum];
   1166 	if ( !(leaf->contents & trace_contents))
   1167 		return;
   1168 	// trace line against all brushes in the leaf
   1169 	for (k=0 ; k<leaf->numleafbrushes ; k++)
   1170 	{
   1171 		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
   1172 		b = &map_brushes[brushnum];
   1173 		if (b->checkcount == checkcount)
   1174 			continue;	// already checked this brush in another leaf
   1175 		b->checkcount = checkcount;
   1176 
   1177 		if ( !(b->contents & trace_contents))
   1178 			continue;
   1179 		CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
   1180 		if (!trace_trace.fraction)
   1181 			return;
   1182 	}
   1183 
   1184 }
   1185 
   1186 
   1187 /*
   1188 ================
   1189 CM_TestInLeaf
   1190 ================
   1191 */
   1192 void CM_TestInLeaf (int leafnum)
   1193 {
   1194 	int			k;
   1195 	int			brushnum;
   1196 	cleaf_t		*leaf;
   1197 	cbrush_t	*b;
   1198 
   1199 	leaf = &map_leafs[leafnum];
   1200 	if ( !(leaf->contents & trace_contents))
   1201 		return;
   1202 	// trace line against all brushes in the leaf
   1203 	for (k=0 ; k<leaf->numleafbrushes ; k++)
   1204 	{
   1205 		brushnum = map_leafbrushes[leaf->firstleafbrush+k];
   1206 		b = &map_brushes[brushnum];
   1207 		if (b->checkcount == checkcount)
   1208 			continue;	// already checked this brush in another leaf
   1209 		b->checkcount = checkcount;
   1210 
   1211 		if ( !(b->contents & trace_contents))
   1212 			continue;
   1213 		CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
   1214 		if (!trace_trace.fraction)
   1215 			return;
   1216 	}
   1217 
   1218 }
   1219 
   1220 
   1221 /*
   1222 ==================
   1223 CM_RecursiveHullCheck
   1224 
   1225 ==================
   1226 */
   1227 void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
   1228 {
   1229 	cnode_t		*node;
   1230 	cplane_t	*plane;
   1231 	float		t1, t2, offset;
   1232 	float		frac, frac2;
   1233 	float		idist;
   1234 	int			i;
   1235 	vec3_t		mid;
   1236 	int			side;
   1237 	float		midf;
   1238 
   1239 	if (trace_trace.fraction <= p1f)
   1240 		return;		// already hit something nearer
   1241 
   1242 	// if < 0, we are in a leaf node
   1243 	if (num < 0)
   1244 	{
   1245 		CM_TraceToLeaf (-1-num);
   1246 		return;
   1247 	}
   1248 
   1249 	//
   1250 	// find the point distances to the seperating plane
   1251 	// and the offset for the size of the box
   1252 	//
   1253 	node = map_nodes + num;
   1254 	plane = node->plane;
   1255 
   1256 	if (plane->type < 3)
   1257 	{
   1258 		t1 = p1[plane->type] - plane->dist;
   1259 		t2 = p2[plane->type] - plane->dist;
   1260 		offset = trace_extents[plane->type];
   1261 	}
   1262 	else
   1263 	{
   1264 		t1 = DotProduct (plane->normal, p1) - plane->dist;
   1265 		t2 = DotProduct (plane->normal, p2) - plane->dist;
   1266 		if (trace_ispoint)
   1267 			offset = 0;
   1268 		else
   1269 			offset = fabs(trace_extents[0]*plane->normal[0]) +
   1270 				fabs(trace_extents[1]*plane->normal[1]) +
   1271 				fabs(trace_extents[2]*plane->normal[2]);
   1272 	}
   1273 
   1274 
   1275 #if 0
   1276 CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
   1277 CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
   1278 return;
   1279 #endif
   1280 
   1281 	// see which sides we need to consider
   1282 	if (t1 >= offset && t2 >= offset)
   1283 	{
   1284 		CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
   1285 		return;
   1286 	}
   1287 	if (t1 < -offset && t2 < -offset)
   1288 	{
   1289 		CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
   1290 		return;
   1291 	}
   1292 
   1293 	// put the crosspoint DIST_EPSILON pixels on the near side
   1294 	if (t1 < t2)
   1295 	{
   1296 		idist = 1.0/(t1-t2);
   1297 		side = 1;
   1298 		frac2 = (t1 + offset + DIST_EPSILON)*idist;
   1299 		frac = (t1 - offset + DIST_EPSILON)*idist;
   1300 	}
   1301 	else if (t1 > t2)
   1302 	{
   1303 		idist = 1.0/(t1-t2);
   1304 		side = 0;
   1305 		frac2 = (t1 - offset - DIST_EPSILON)*idist;
   1306 		frac = (t1 + offset + DIST_EPSILON)*idist;
   1307 	}
   1308 	else
   1309 	{
   1310 		side = 0;
   1311 		frac = 1;
   1312 		frac2 = 0;
   1313 	}
   1314 
   1315 	// move up to the node
   1316 	if (frac < 0)
   1317 		frac = 0;
   1318 	if (frac > 1)
   1319 		frac = 1;
   1320 		
   1321 	midf = p1f + (p2f - p1f)*frac;
   1322 	for (i=0 ; i<3 ; i++)
   1323 		mid[i] = p1[i] + frac*(p2[i] - p1[i]);
   1324 
   1325 	CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
   1326 
   1327 
   1328 	// go past the node
   1329 	if (frac2 < 0)
   1330 		frac2 = 0;
   1331 	if (frac2 > 1)
   1332 		frac2 = 1;
   1333 		
   1334 	midf = p1f + (p2f - p1f)*frac2;
   1335 	for (i=0 ; i<3 ; i++)
   1336 		mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
   1337 
   1338 	CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
   1339 }
   1340 
   1341 
   1342 
   1343 //======================================================================
   1344 
   1345 /*
   1346 ==================
   1347 CM_BoxTrace
   1348 ==================
   1349 */
   1350 trace_t		CM_BoxTrace (vec3_t start, vec3_t end,
   1351 						  vec3_t mins, vec3_t maxs,
   1352 						  int headnode, int brushmask)
   1353 {
   1354 	int		i;
   1355 
   1356 	checkcount++;		// for multi-check avoidance
   1357 
   1358 	c_traces++;			// for statistics, may be zeroed
   1359 
   1360 	// fill in a default trace
   1361 	memset (&trace_trace, 0, sizeof(trace_trace));
   1362 	trace_trace.fraction = 1;
   1363 	trace_trace.surface = &(nullsurface.c);
   1364 
   1365 	if (!numnodes)	// map not loaded
   1366 		return trace_trace;
   1367 
   1368 	trace_contents = brushmask;
   1369 	VectorCopy (start, trace_start);
   1370 	VectorCopy (end, trace_end);
   1371 	VectorCopy (mins, trace_mins);
   1372 	VectorCopy (maxs, trace_maxs);
   1373 
   1374 	//
   1375 	// check for position test special case
   1376 	//
   1377 	if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
   1378 	{
   1379 		int		leafs[1024];
   1380 		int		i, numleafs;
   1381 		vec3_t	c1, c2;
   1382 		int		topnode;
   1383 
   1384 		VectorAdd (start, mins, c1);
   1385 		VectorAdd (start, maxs, c2);
   1386 		for (i=0 ; i<3 ; i++)
   1387 		{
   1388 			c1[i] -= 1;
   1389 			c2[i] += 1;
   1390 		}
   1391 
   1392 		numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
   1393 		for (i=0 ; i<numleafs ; i++)
   1394 		{
   1395 			CM_TestInLeaf (leafs[i]);
   1396 			if (trace_trace.allsolid)
   1397 				break;
   1398 		}
   1399 		VectorCopy (start, trace_trace.endpos);
   1400 		return trace_trace;
   1401 	}
   1402 
   1403 	//
   1404 	// check for point special case
   1405 	//
   1406 	if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
   1407 		&& maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
   1408 	{
   1409 		trace_ispoint = true;
   1410 		VectorClear (trace_extents);
   1411 	}
   1412 	else
   1413 	{
   1414 		trace_ispoint = false;
   1415 		trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
   1416 		trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
   1417 		trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
   1418 	}
   1419 
   1420 	//
   1421 	// general sweeping through world
   1422 	//
   1423 	CM_RecursiveHullCheck (headnode, 0, 1, start, end);
   1424 
   1425 	if (trace_trace.fraction == 1)
   1426 	{
   1427 		VectorCopy (end, trace_trace.endpos);
   1428 	}
   1429 	else
   1430 	{
   1431 		for (i=0 ; i<3 ; i++)
   1432 			trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
   1433 	}
   1434 	return trace_trace;
   1435 }
   1436 
   1437 
   1438 /*
   1439 ==================
   1440 CM_TransformedBoxTrace
   1441 
   1442 Handles offseting and rotation of the end points for moving and
   1443 rotating entities
   1444 ==================
   1445 */
   1446 #ifdef _WIN32
   1447 #pragma optimize( "", off )
   1448 #endif
   1449 
   1450 
   1451 trace_t		CM_TransformedBoxTrace (vec3_t start, vec3_t end,
   1452 						  vec3_t mins, vec3_t maxs,
   1453 						  int headnode, int brushmask,
   1454 						  vec3_t origin, vec3_t angles)
   1455 {
   1456 	trace_t		trace;
   1457 	vec3_t		start_l, end_l;
   1458 	vec3_t		a;
   1459 	vec3_t		forward, right, up;
   1460 	vec3_t		temp;
   1461 	qboolean	rotated;
   1462 
   1463 	// subtract origin offset
   1464 	VectorSubtract (start, origin, start_l);
   1465 	VectorSubtract (end, origin, end_l);
   1466 
   1467 	// rotate start and end into the models frame of reference
   1468 	if (headnode != box_headnode && 
   1469 	(angles[0] || angles[1] || angles[2]) )
   1470 		rotated = true;
   1471 	else
   1472 		rotated = false;
   1473 
   1474 	if (rotated)
   1475 	{
   1476 		AngleVectors (angles, forward, right, up);
   1477 
   1478 		VectorCopy (start_l, temp);
   1479 		start_l[0] = DotProduct (temp, forward);
   1480 		start_l[1] = -DotProduct (temp, right);
   1481 		start_l[2] = DotProduct (temp, up);
   1482 
   1483 		VectorCopy (end_l, temp);
   1484 		end_l[0] = DotProduct (temp, forward);
   1485 		end_l[1] = -DotProduct (temp, right);
   1486 		end_l[2] = DotProduct (temp, up);
   1487 	}
   1488 
   1489 	// sweep the box through the model
   1490 	trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
   1491 
   1492 	if (rotated && trace.fraction != 1.0)
   1493 	{
   1494 		// FIXME: figure out how to do this with existing angles
   1495 		VectorNegate (angles, a);
   1496 		AngleVectors (a, forward, right, up);
   1497 
   1498 		VectorCopy (trace.plane.normal, temp);
   1499 		trace.plane.normal[0] = DotProduct (temp, forward);
   1500 		trace.plane.normal[1] = -DotProduct (temp, right);
   1501 		trace.plane.normal[2] = DotProduct (temp, up);
   1502 	}
   1503 
   1504 	trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
   1505 	trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
   1506 	trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
   1507 
   1508 	return trace;
   1509 }
   1510 
   1511 #ifdef _WIN32
   1512 #pragma optimize( "", on )
   1513 #endif
   1514 
   1515 
   1516 
   1517 /*
   1518 ===============================================================================
   1519 
   1520 PVS / PHS
   1521 
   1522 ===============================================================================
   1523 */
   1524 
   1525 /*
   1526 ===================
   1527 CM_DecompressVis
   1528 ===================
   1529 */
   1530 void CM_DecompressVis (byte *in, byte *out)
   1531 {
   1532 	int		c;
   1533 	byte	*out_p;
   1534 	int		row;
   1535 
   1536 	row = (numclusters+7)>>3;	
   1537 	out_p = out;
   1538 
   1539 	if (!in || !numvisibility)
   1540 	{	// no vis info, so make all visible
   1541 		while (row)
   1542 		{
   1543 			*out_p++ = 0xff;
   1544 			row--;
   1545 		}
   1546 		return;		
   1547 	}
   1548 
   1549 	do
   1550 	{
   1551 		if (*in)
   1552 		{
   1553 			*out_p++ = *in++;
   1554 			continue;
   1555 		}
   1556 	
   1557 		c = in[1];
   1558 		in += 2;
   1559 		if ((out_p - out) + c > row)
   1560 		{
   1561 			c = row - (out_p - out);
   1562 			Com_DPrintf ("warning: Vis decompression overrun\n");
   1563 		}
   1564 		while (c)
   1565 		{
   1566 			*out_p++ = 0;
   1567 			c--;
   1568 		}
   1569 	} while (out_p - out < row);
   1570 }
   1571 
   1572 byte	pvsrow[MAX_MAP_LEAFS/8];
   1573 byte	phsrow[MAX_MAP_LEAFS/8];
   1574 
   1575 byte	*CM_ClusterPVS (int cluster)
   1576 {
   1577 	if (cluster == -1)
   1578 		memset (pvsrow, 0, (numclusters+7)>>3);
   1579 	else
   1580 		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
   1581 	return pvsrow;
   1582 }
   1583 
   1584 byte	*CM_ClusterPHS (int cluster)
   1585 {
   1586 	if (cluster == -1)
   1587 		memset (phsrow, 0, (numclusters+7)>>3);
   1588 	else
   1589 		CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
   1590 	return phsrow;
   1591 }
   1592 
   1593 
   1594 /*
   1595 ===============================================================================
   1596 
   1597 AREAPORTALS
   1598 
   1599 ===============================================================================
   1600 */
   1601 
   1602 void FloodArea_r (carea_t *area, int floodnum)
   1603 {
   1604 	int		i;
   1605 	dareaportal_t	*p;
   1606 
   1607 	if (area->floodvalid == floodvalid)
   1608 	{
   1609 		if (area->floodnum == floodnum)
   1610 			return;
   1611 		Com_Error (ERR_DROP, "FloodArea_r: reflooded");
   1612 	}
   1613 
   1614 	area->floodnum = floodnum;
   1615 	area->floodvalid = floodvalid;
   1616 	p = &map_areaportals[area->firstareaportal];
   1617 	for (i=0 ; i<area->numareaportals ; i++, p++)
   1618 	{
   1619 		if (portalopen[p->portalnum])
   1620 			FloodArea_r (&map_areas[p->otherarea], floodnum);
   1621 	}
   1622 }
   1623 
   1624 /*
   1625 ====================
   1626 FloodAreaConnections
   1627 
   1628 
   1629 ====================
   1630 */
   1631 void	FloodAreaConnections (void)
   1632 {
   1633 	int		i;
   1634 	carea_t	*area;
   1635 	int		floodnum;
   1636 
   1637 	// all current floods are now invalid
   1638 	floodvalid++;
   1639 	floodnum = 0;
   1640 
   1641 	// area 0 is not used
   1642 	for (i=1 ; i<numareas ; i++)
   1643 	{
   1644 		area = &map_areas[i];
   1645 		if (area->floodvalid == floodvalid)
   1646 			continue;		// already flooded into
   1647 		floodnum++;
   1648 		FloodArea_r (area, floodnum);
   1649 	}
   1650 
   1651 }
   1652 
   1653 void	CM_SetAreaPortalState (int portalnum, qboolean open)
   1654 {
   1655 	if (portalnum > numareaportals)
   1656 		Com_Error (ERR_DROP, "areaportal > numareaportals");
   1657 
   1658 	portalopen[portalnum] = open;
   1659 	FloodAreaConnections ();
   1660 }
   1661 
   1662 qboolean	CM_AreasConnected (int area1, int area2)
   1663 {
   1664 	if (map_noareas->value)
   1665 		return true;
   1666 
   1667 	if (area1 > numareas || area2 > numareas)
   1668 		Com_Error (ERR_DROP, "area > numareas");
   1669 
   1670 	if (map_areas[area1].floodnum == map_areas[area2].floodnum)
   1671 		return true;
   1672 	return false;
   1673 }
   1674 
   1675 
   1676 /*
   1677 =================
   1678 CM_WriteAreaBits
   1679 
   1680 Writes a length byte followed by a bit vector of all the areas
   1681 that area in the same flood as the area parameter
   1682 
   1683 This is used by the client refreshes to cull visibility
   1684 =================
   1685 */
   1686 int CM_WriteAreaBits (byte *buffer, int area)
   1687 {
   1688 	int		i;
   1689 	int		floodnum;
   1690 	int		bytes;
   1691 
   1692 	bytes = (numareas+7)>>3;
   1693 
   1694 	if (map_noareas->value)
   1695 	{	// for debugging, send everything
   1696 		memset (buffer, 255, bytes);
   1697 	}
   1698 	else
   1699 	{
   1700 		memset (buffer, 0, bytes);
   1701 
   1702 		floodnum = map_areas[area].floodnum;
   1703 		for (i=0 ; i<numareas ; i++)
   1704 		{
   1705 			if (map_areas[i].floodnum == floodnum || !area)
   1706 				buffer[i>>3] |= 1<<(i&7);
   1707 		}
   1708 	}
   1709 
   1710 	return bytes;
   1711 }
   1712 
   1713 
   1714 /*
   1715 ===================
   1716 CM_WritePortalState
   1717 
   1718 Writes the portal state to a savegame file
   1719 ===================
   1720 */
   1721 void	CM_WritePortalState (FILE *f)
   1722 {
   1723 	fwrite (portalopen, sizeof(portalopen), 1, f);
   1724 }
   1725 
   1726 /*
   1727 ===================
   1728 CM_ReadPortalState
   1729 
   1730 Reads the portal state from a savegame file
   1731 and recalculates the area connections
   1732 ===================
   1733 */
   1734 void	CM_ReadPortalState (FILE *f)
   1735 {
   1736 	FS_Read (portalopen, sizeof(portalopen), f);
   1737 	FloodAreaConnections ();
   1738 }
   1739 
   1740 /*
   1741 =============
   1742 CM_HeadnodeVisible
   1743 
   1744 Returns true if any leaf under headnode has a cluster that
   1745 is potentially visible
   1746 =============
   1747 */
   1748 qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
   1749 {
   1750 	int		leafnum;
   1751 	int		cluster;
   1752 	cnode_t	*node;
   1753 
   1754 	if (nodenum < 0)
   1755 	{
   1756 		leafnum = -1-nodenum;
   1757 		cluster = map_leafs[leafnum].cluster;
   1758 		if (cluster == -1)
   1759 			return false;
   1760 		if (visbits[cluster>>3] & (1<<(cluster&7)))
   1761 			return true;
   1762 		return false;
   1763 	}
   1764 
   1765 	node = &map_nodes[nodenum];
   1766 	if (CM_HeadnodeVisible(node->children[0], visbits))
   1767 		return true;
   1768 	return CM_HeadnodeVisible(node->children[1], visbits);
   1769 }
   1770