Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 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 // world.c -- world query functions
     21 
     22 #include "quakedef.h"
     23 
     24 /*
     25 
     26 entities never clip against themselves, or their owner
     27 
     28 line of sight checks trace->crosscontent, but bullets don't
     29 
     30 */
     31 
     32 
     33 typedef struct
     34 {
     35 	vec3_t		boxmins, boxmaxs;// enclose the test object along entire move
     36 	float		*mins, *maxs;	// size of the moving object
     37 	vec3_t		mins2, maxs2;	// size when clipping against mosnters
     38 	float		*start, *end;
     39 	trace_t		trace;
     40 	int			type;
     41 	edict_t		*passedict;
     42 } moveclip_t;
     43 
     44 
     45 int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
     46 
     47 /*
     48 ===============================================================================
     49 
     50 HULL BOXES
     51 
     52 ===============================================================================
     53 */
     54 
     55 
     56 static	hull_t		box_hull;
     57 static	dclipnode_t	box_clipnodes[6];
     58 static	mplane_t	box_planes[6];
     59 
     60 /*
     61 ===================
     62 SV_InitBoxHull
     63 
     64 Set up the planes and clipnodes so that the six floats of a bounding box
     65 can just be stored out and get a proper hull_t structure.
     66 ===================
     67 */
     68 void SV_InitBoxHull (void)
     69 {
     70 	int		i;
     71 	int		side;
     72 
     73 	box_hull.clipnodes = box_clipnodes;
     74 	box_hull.planes = box_planes;
     75 	box_hull.firstclipnode = 0;
     76 	box_hull.lastclipnode = 5;
     77 
     78 	for (i=0 ; i<6 ; i++)
     79 	{
     80 		box_clipnodes[i].planenum = i;
     81 
     82 		side = i&1;
     83 
     84 		box_clipnodes[i].children[side] = CONTENTS_EMPTY;
     85 		if (i != 5)
     86 			box_clipnodes[i].children[side^1] = i + 1;
     87 		else
     88 			box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
     89 
     90 		box_planes[i].type = i>>1;
     91 		box_planes[i].normal[i>>1] = 1;
     92 	}
     93 
     94 }
     95 
     96 
     97 /*
     98 ===================
     99 SV_HullForBox
    100 
    101 To keep everything totally uniform, bounding boxes are turned into small
    102 BSP trees instead of being compared directly.
    103 ===================
    104 */
    105 hull_t	*SV_HullForBox (vec3_t mins, vec3_t maxs)
    106 {
    107 	box_planes[0].dist = maxs[0];
    108 	box_planes[1].dist = mins[0];
    109 	box_planes[2].dist = maxs[1];
    110 	box_planes[3].dist = mins[1];
    111 	box_planes[4].dist = maxs[2];
    112 	box_planes[5].dist = mins[2];
    113 
    114 	return &box_hull;
    115 }
    116 
    117 
    118 
    119 /*
    120 ================
    121 SV_HullForEntity
    122 
    123 Returns a hull that can be used for testing or clipping an object of mins/maxs
    124 size.
    125 Offset is filled in to contain the adjustment that must be added to the
    126 testing object's origin to get a point to use with the returned hull.
    127 ================
    128 */
    129 hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
    130 {
    131 	model_t		*model;
    132 	vec3_t		size;
    133 	vec3_t		hullmins, hullmaxs;
    134 	hull_t		*hull;
    135 
    136 // decide which clipping hull to use, based on the size
    137 	if (ent->u.v.solid == SOLID_BSP)
    138 	{	// explicit hulls in the BSP model
    139 		if (ent->u.v.movetype != MOVETYPE_PUSH)
    140 			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");
    141 
    142 		model = sv.models[ (int)ent->u.v.modelindex ];
    143 
    144 		if (!model || model->type != mod_brush)
    145 			Sys_Error ("MOVETYPE_PUSH with a non bsp model");
    146 
    147 		VectorSubtract (maxs, mins, size);
    148 		if (size[0] < 3)
    149 			hull = &model->hulls[0];
    150 		else if (size[0] <= 32)
    151 			hull = &model->hulls[1];
    152 		else
    153 			hull = &model->hulls[2];
    154 
    155 // calculate an offset value to center the origin
    156 		VectorSubtract (hull->clip_mins, mins, offset);
    157 		VectorAdd (offset, ent->u.v.origin, offset);
    158 	}
    159 	else
    160 	{	// create a temp hull from bounding box sizes
    161 
    162 		VectorSubtract (ent->u.v.mins, maxs, hullmins);
    163 		VectorSubtract (ent->u.v.maxs, mins, hullmaxs);
    164 		hull = SV_HullForBox (hullmins, hullmaxs);
    165 
    166 		VectorCopy (ent->u.v.origin, offset);
    167 	}
    168 
    169 
    170 	return hull;
    171 }
    172 
    173 /*
    174 ===============================================================================
    175 
    176 ENTITY AREA CHECKING
    177 
    178 ===============================================================================
    179 */
    180 
    181 typedef struct areanode_s
    182 {
    183 	int		axis;		// -1 = leaf node
    184 	float	dist;
    185 	struct areanode_s	*children[2];
    186 	link_t	trigger_edicts;
    187 	link_t	solid_edicts;
    188 } areanode_t;
    189 
    190 #define	AREA_DEPTH	4
    191 #define	AREA_NODES	32
    192 
    193 static	areanode_t	sv_areanodes[AREA_NODES];
    194 static	int			sv_numareanodes;
    195 
    196 /*
    197 ===============
    198 SV_CreateAreaNode
    199 
    200 ===============
    201 */
    202 areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
    203 {
    204 	areanode_t	*anode;
    205 	vec3_t		size;
    206 	vec3_t		mins1, maxs1, mins2, maxs2;
    207 
    208 	anode = &sv_areanodes[sv_numareanodes];
    209 	sv_numareanodes++;
    210 
    211 	ClearLink (&anode->trigger_edicts);
    212 	ClearLink (&anode->solid_edicts);
    213 
    214 	if (depth == AREA_DEPTH)
    215 	{
    216 		anode->axis = -1;
    217 		anode->children[0] = anode->children[1] = NULL;
    218 		return anode;
    219 	}
    220 
    221 	VectorSubtract (maxs, mins, size);
    222 	if (size[0] > size[1])
    223 		anode->axis = 0;
    224 	else
    225 		anode->axis = 1;
    226 
    227 	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
    228 	VectorCopy (mins, mins1);
    229 	VectorCopy (mins, mins2);
    230 	VectorCopy (maxs, maxs1);
    231 	VectorCopy (maxs, maxs2);
    232 
    233 	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
    234 
    235 	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
    236 	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
    237 
    238 	return anode;
    239 }
    240 
    241 /*
    242 ===============
    243 SV_ClearWorld
    244 
    245 ===============
    246 */
    247 void SV_ClearWorld (void)
    248 {
    249 	SV_InitBoxHull ();
    250 
    251 	memset (sv_areanodes, 0, sizeof(sv_areanodes));
    252 	sv_numareanodes = 0;
    253 	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
    254 }
    255 
    256 
    257 /*
    258 ===============
    259 SV_UnlinkEdict
    260 
    261 ===============
    262 */
    263 void SV_UnlinkEdict (edict_t *ent)
    264 {
    265 	if (!ent->area.prev)
    266 		return;		// not linked in anywhere
    267 	RemoveLink (&ent->area);
    268 	ent->area.prev = ent->area.next = NULL;
    269 }
    270 
    271 
    272 /*
    273 ====================
    274 SV_TouchLinks
    275 ====================
    276 */
    277 void SV_TouchLinks ( edict_t *ent, areanode_t *node )
    278 {
    279 	link_t		*l, *next;
    280 	edict_t		*touch;
    281 	int			old_self, old_other;
    282 
    283 // touch linked edicts
    284 	for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
    285 	{
    286 		next = l->next;
    287 		touch = EDICT_FROM_AREA(l);
    288 		if (touch == ent)
    289 			continue;
    290 		if (!touch->u.v.touch || touch->u.v.solid != SOLID_TRIGGER)
    291 			continue;
    292 		if (ent->u.v.absmin[0] > touch->u.v.absmax[0]
    293 		|| ent->u.v.absmin[1] > touch->u.v.absmax[1]
    294 		|| ent->u.v.absmin[2] > touch->u.v.absmax[2]
    295 		|| ent->u.v.absmax[0] < touch->u.v.absmin[0]
    296 		|| ent->u.v.absmax[1] < touch->u.v.absmin[1]
    297 		|| ent->u.v.absmax[2] < touch->u.v.absmin[2] )
    298 			continue;
    299 		old_self = pr_global_struct->self;
    300 		old_other = pr_global_struct->other;
    301 
    302 		pr_global_struct->self = EDICT_TO_PROG(touch);
    303 		pr_global_struct->other = EDICT_TO_PROG(ent);
    304 		pr_global_struct->time = sv.time;
    305 		PR_ExecuteProgram (touch->u.v.touch);
    306 
    307 		pr_global_struct->self = old_self;
    308 		pr_global_struct->other = old_other;
    309 	}
    310 
    311 // recurse down both sides
    312 	if (node->axis == -1)
    313 		return;
    314 
    315 	if ( ent->u.v.absmax[node->axis] > node->dist )
    316 		SV_TouchLinks ( ent, node->children[0] );
    317 	if ( ent->u.v.absmin[node->axis] < node->dist )
    318 		SV_TouchLinks ( ent, node->children[1] );
    319 }
    320 
    321 
    322 /*
    323 ===============
    324 SV_FindTouchedLeafs
    325 
    326 ===============
    327 */
    328 void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
    329 {
    330 	mplane_t	*splitplane;
    331 	mleaf_t		*leaf;
    332 	int			sides;
    333 	int			leafnum;
    334 
    335 	if (node->contents == CONTENTS_SOLID)
    336 		return;
    337 
    338 // add an efrag if the node is a leaf
    339 
    340 	if ( node->contents < 0)
    341 	{
    342 		if (ent->num_leafs == MAX_ENT_LEAFS)
    343 			return;
    344 
    345 		leaf = (mleaf_t *)node;
    346 		leafnum = leaf - sv.worldmodel->leafs - 1;
    347 
    348 		ent->leafnums[ent->num_leafs] = leafnum;
    349 		ent->num_leafs++;
    350 		return;
    351 	}
    352 
    353 // NODE_MIXED
    354 
    355 	splitplane = node->plane;
    356 	sides = BOX_ON_PLANE_SIDE(ent->u.v.absmin, ent->u.v.absmax, splitplane);
    357 
    358 // recurse down the contacted sides
    359 	if (sides & 1)
    360 		SV_FindTouchedLeafs (ent, node->children[0]);
    361 
    362 	if (sides & 2)
    363 		SV_FindTouchedLeafs (ent, node->children[1]);
    364 }
    365 
    366 /*
    367 ===============
    368 SV_LinkEdict
    369 
    370 ===============
    371 */
    372 void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
    373 {
    374 	areanode_t	*node;
    375 
    376 	if (ent->area.prev)
    377 		SV_UnlinkEdict (ent);	// unlink from old position
    378 
    379 	if (ent == sv.edicts)
    380 		return;		// don't add the world
    381 
    382 	if (ent->free)
    383 		return;
    384 
    385 // set the abs box
    386 
    387 #ifdef QUAKE2
    388 	if (ent->u.v.solid == SOLID_BSP &&
    389 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
    390 	{	// expand for rotation
    391 		float		max, v;
    392 		int			i;
    393 
    394 		max = 0;
    395 		for (i=0 ; i<3 ; i++)
    396 		{
    397 			v =fabs( ent->u.v.mins[i]);
    398 			if (v > max)
    399 				max = v;
    400 			v =fabs( ent->u.v.maxs[i]);
    401 			if (v > max)
    402 				max = v;
    403 		}
    404 		for (i=0 ; i<3 ; i++)
    405 		{
    406 			ent->u.v.absmin[i] = ent->u.v.origin[i] - max;
    407 			ent->u.v.absmax[i] = ent->u.v.origin[i] + max;
    408 		}
    409 	}
    410 	else
    411 #endif
    412 	{
    413 		VectorAdd (ent->u.v.origin, ent->u.v.mins, ent->u.v.absmin);
    414 		VectorAdd (ent->u.v.origin, ent->u.v.maxs, ent->u.v.absmax);
    415 	}
    416 
    417 //
    418 // to make items easier to pick up and allow them to be grabbed off
    419 // of shelves, the abs sizes are expanded
    420 //
    421 	if ((int)ent->u.v.flags & FL_ITEM)
    422 	{
    423 		ent->u.v.absmin[0] -= 15;
    424 		ent->u.v.absmin[1] -= 15;
    425 		ent->u.v.absmax[0] += 15;
    426 		ent->u.v.absmax[1] += 15;
    427 	}
    428 	else
    429 	{	// because movement is clipped an epsilon away from an actual edge,
    430 		// we must fully check even when bounding boxes don't quite touch
    431 		ent->u.v.absmin[0] -= 1;
    432 		ent->u.v.absmin[1] -= 1;
    433 		ent->u.v.absmin[2] -= 1;
    434 		ent->u.v.absmax[0] += 1;
    435 		ent->u.v.absmax[1] += 1;
    436 		ent->u.v.absmax[2] += 1;
    437 	}
    438 
    439 // link to PVS leafs
    440 	ent->num_leafs = 0;
    441 	if (ent->u.v.modelindex)
    442 		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
    443 
    444 	if (ent->u.v.solid == SOLID_NOT)
    445 		return;
    446 
    447 // find the first node that the ent's box crosses
    448 	node = sv_areanodes;
    449 	while (1)
    450 	{
    451 		if (node->axis == -1)
    452 			break;
    453 		if (ent->u.v.absmin[node->axis] > node->dist)
    454 			node = node->children[0];
    455 		else if (ent->u.v.absmax[node->axis] < node->dist)
    456 			node = node->children[1];
    457 		else
    458 			break;		// crosses the node
    459 	}
    460 
    461 // link it in
    462 
    463 	if (ent->u.v.solid == SOLID_TRIGGER)
    464 		InsertLinkBefore (&ent->area, &node->trigger_edicts);
    465 	else
    466 		InsertLinkBefore (&ent->area, &node->solid_edicts);
    467 
    468 // if touch_triggers, touch all entities at this node and decend for more
    469 	if (touch_triggers)
    470 		SV_TouchLinks ( ent, sv_areanodes );
    471 }
    472 
    473 
    474 
    475 /*
    476 ===============================================================================
    477 
    478 POINT TESTING IN HULLS
    479 
    480 ===============================================================================
    481 */
    482 
    483 #if	!id386
    484 
    485 /*
    486 ==================
    487 SV_HullPointContents
    488 
    489 ==================
    490 */
    491 int SV_HullPointContents (hull_t *hull, int num, vec3_t p)
    492 {
    493 	float		d;
    494 	dclipnode_t	*node;
    495 	mplane_t	*plane;
    496 
    497 	while (num >= 0)
    498 	{
    499 		if (num < hull->firstclipnode || num > hull->lastclipnode)
    500 			Sys_Error ("SV_HullPointContents: bad node number");
    501 
    502 		node = hull->clipnodes + num;
    503 		plane = hull->planes + node->planenum;
    504 
    505 		if (plane->type < 3)
    506 			d = p[plane->type] - plane->dist;
    507 		else
    508 			d = DotProduct (plane->normal, p) - plane->dist;
    509 		if (d < 0)
    510 			num = node->children[1];
    511 		else
    512 			num = node->children[0];
    513 	}
    514 
    515 	return num;
    516 }
    517 
    518 #endif	// !id386
    519 
    520 
    521 /*
    522 ==================
    523 SV_PointContents
    524 
    525 ==================
    526 */
    527 int SV_PointContents (vec3_t p)
    528 {
    529 	int		cont;
    530 
    531 	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
    532 	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
    533 		cont = CONTENTS_WATER;
    534 	return cont;
    535 }
    536 
    537 int SV_TruePointContents (vec3_t p)
    538 {
    539 	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
    540 }
    541 
    542 //===========================================================================
    543 
    544 /*
    545 ============
    546 SV_TestEntityPosition
    547 
    548 This could be a lot more efficient...
    549 ============
    550 */
    551 edict_t	*SV_TestEntityPosition (edict_t *ent)
    552 {
    553 	trace_t	trace;
    554 
    555 	trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, ent->u.v.origin, 0, ent);
    556 
    557 	if (trace.startsolid)
    558 		return sv.edicts;
    559 
    560 	return NULL;
    561 }
    562 
    563 
    564 /*
    565 ===============================================================================
    566 
    567 LINE TESTING IN HULLS
    568 
    569 ===============================================================================
    570 */
    571 
    572 // 1/32 epsilon to keep floating point happy
    573 #define	DIST_EPSILON	(0.03125)
    574 
    575 /*
    576 ==================
    577 SV_RecursiveHullCheck
    578 
    579 ==================
    580 */
    581 qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
    582 {
    583 	dclipnode_t	*node;
    584 	mplane_t	*plane;
    585 	float		t1, t2;
    586 	float		frac;
    587 	int			i;
    588 	vec3_t		mid;
    589 	int			side;
    590 	float		midf;
    591 
    592 // check for empty
    593 	if (num < 0)
    594 	{
    595 		if (num != CONTENTS_SOLID)
    596 		{
    597 			trace->allsolid = false;
    598 			if (num == CONTENTS_EMPTY)
    599 				trace->inopen = true;
    600 			else
    601 				trace->inwater = true;
    602 		}
    603 		else
    604 			trace->startsolid = true;
    605 		return true;		// empty
    606 	}
    607 
    608 	if (num < hull->firstclipnode || num > hull->lastclipnode)
    609 		Sys_Error ("SV_RecursiveHullCheck: bad node number");
    610 
    611 //
    612 // find the point distances
    613 //
    614 	node = hull->clipnodes + num;
    615 	plane = hull->planes + node->planenum;
    616 
    617 	if (plane->type < 3)
    618 	{
    619 		t1 = p1[plane->type] - plane->dist;
    620 		t2 = p2[plane->type] - plane->dist;
    621 	}
    622 	else
    623 	{
    624 		t1 = DotProduct (plane->normal, p1) - plane->dist;
    625 		t2 = DotProduct (plane->normal, p2) - plane->dist;
    626 	}
    627 
    628 #if 1
    629 	if (t1 >= 0 && t2 >= 0)
    630 		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
    631 	if (t1 < 0 && t2 < 0)
    632 		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
    633 #else
    634 	if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
    635 		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
    636 	if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
    637 		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
    638 #endif
    639 
    640 // put the crosspoint DIST_EPSILON pixels on the near side
    641 	if (t1 < 0)
    642 		frac = (t1 + DIST_EPSILON)/(t1-t2);
    643 	else
    644 		frac = (t1 - DIST_EPSILON)/(t1-t2);
    645 	if (frac < 0)
    646 		frac = 0;
    647 	if (frac > 1)
    648 		frac = 1;
    649 
    650 	midf = p1f + (p2f - p1f)*frac;
    651 	for (i=0 ; i<3 ; i++)
    652 		mid[i] = p1[i] + frac*(p2[i] - p1[i]);
    653 
    654 	side = (t1 < 0);
    655 
    656 // move up to the node
    657 	if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
    658 		return false;
    659 
    660 #ifdef PARANOID
    661 	if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])
    662 	== CONTENTS_SOLID)
    663 	{
    664 		Con_Printf ("mid PointInHullSolid\n");
    665 		return false;
    666 	}
    667 #endif
    668 
    669 	if (SV_HullPointContents (hull, node->children[side^1], mid)
    670 	!= CONTENTS_SOLID)
    671 // go past the node
    672 		return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
    673 
    674 	if (trace->allsolid)
    675 		return false;		// never got out of the solid area
    676 
    677 //==================
    678 // the other side of the node is solid, this is the impact point
    679 //==================
    680 	if (!side)
    681 	{
    682 		VectorCopy (plane->normal, trace->plane.normal);
    683 		trace->plane.dist = plane->dist;
    684 	}
    685 	else
    686 	{
    687 		VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
    688 		trace->plane.dist = -plane->dist;
    689 	}
    690 
    691 	while (SV_HullPointContents (hull, hull->firstclipnode, mid)
    692 	== CONTENTS_SOLID)
    693 	{ // shouldn't really happen, but does occasionally
    694 		frac -= 0.1;
    695 		if (frac < 0)
    696 		{
    697 			trace->fraction = midf;
    698 			VectorCopy (mid, trace->endpos);
    699 			Con_DPrintf ("backup past 0\n");
    700 			return false;
    701 		}
    702 		midf = p1f + (p2f - p1f)*frac;
    703 		for (i=0 ; i<3 ; i++)
    704 			mid[i] = p1[i] + frac*(p2[i] - p1[i]);
    705 	}
    706 
    707 	trace->fraction = midf;
    708 	VectorCopy (mid, trace->endpos);
    709 
    710 	return false;
    711 }
    712 
    713 
    714 /*
    715 ==================
    716 SV_ClipMoveToEntity
    717 
    718 Handles selection or creation of a clipping hull, and offseting (and
    719 eventually rotation) of the end points
    720 ==================
    721 */
    722 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
    723 {
    724 	trace_t		trace;
    725 	vec3_t		offset;
    726 	vec3_t		start_l, end_l;
    727 	hull_t		*hull;
    728 
    729 // fill in a default trace
    730 	memset (&trace, 0, sizeof(trace_t));
    731 	trace.fraction = 1;
    732 	trace.allsolid = true;
    733 	VectorCopy (end, trace.endpos);
    734 
    735 // get the clipping hull
    736 	hull = SV_HullForEntity (ent, mins, maxs, offset);
    737 
    738 	VectorSubtract (start, offset, start_l);
    739 	VectorSubtract (end, offset, end_l);
    740 
    741 #ifdef QUAKE2
    742 	// rotate start and end into the models frame of reference
    743 	if (ent->u.v.solid == SOLID_BSP &&
    744 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
    745 	{
    746 		vec3_t	a;
    747 		vec3_t	forward, right, up;
    748 		vec3_t	temp;
    749 
    750 		AngleVectors (ent->u.v.angles, forward, right, up);
    751 
    752 		VectorCopy (start_l, temp);
    753 		start_l[0] = DotProduct (temp, forward);
    754 		start_l[1] = -DotProduct (temp, right);
    755 		start_l[2] = DotProduct (temp, up);
    756 
    757 		VectorCopy (end_l, temp);
    758 		end_l[0] = DotProduct (temp, forward);
    759 		end_l[1] = -DotProduct (temp, right);
    760 		end_l[2] = DotProduct (temp, up);
    761 	}
    762 #endif
    763 
    764 // trace a line through the apropriate clipping hull
    765 	SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
    766 
    767 #ifdef QUAKE2
    768 	// rotate endpos back to world frame of reference
    769 	if (ent->u.v.solid == SOLID_BSP &&
    770 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
    771 	{
    772 		vec3_t	a;
    773 		vec3_t	forward, right, up;
    774 		vec3_t	temp;
    775 
    776 		if (trace.fraction != 1)
    777 		{
    778 			VectorSubtract (vec3_origin, ent->u.v.angles, a);
    779 			AngleVectors (a, forward, right, up);
    780 
    781 			VectorCopy (trace.endpos, temp);
    782 			trace.endpos[0] = DotProduct (temp, forward);
    783 			trace.endpos[1] = -DotProduct (temp, right);
    784 			trace.endpos[2] = DotProduct (temp, up);
    785 
    786 			VectorCopy (trace.plane.normal, temp);
    787 			trace.plane.normal[0] = DotProduct (temp, forward);
    788 			trace.plane.normal[1] = -DotProduct (temp, right);
    789 			trace.plane.normal[2] = DotProduct (temp, up);
    790 		}
    791 	}
    792 #endif
    793 
    794 // fix trace up by the offset
    795 	if (trace.fraction != 1)
    796 		VectorAdd (trace.endpos, offset, trace.endpos);
    797 
    798 // did we clip the move?
    799 	if (trace.fraction < 1 || trace.startsolid  )
    800 		trace.ent = ent;
    801 
    802 	return trace;
    803 }
    804 
    805 //===========================================================================
    806 
    807 /*
    808 ====================
    809 SV_ClipToLinks
    810 
    811 Mins and maxs enclose the entire area swept by the move
    812 ====================
    813 */
    814 void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
    815 {
    816 	link_t		*l, *next;
    817 	edict_t		*touch;
    818 	trace_t		trace;
    819 
    820 // touch linked edicts
    821 	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
    822 	{
    823 		next = l->next;
    824 		touch = EDICT_FROM_AREA(l);
    825 		if (touch->u.v.solid == SOLID_NOT)
    826 			continue;
    827 		if (touch == clip->passedict)
    828 			continue;
    829 		if (touch->u.v.solid == SOLID_TRIGGER)
    830 			Sys_Error ("Trigger in clipping list");
    831 
    832 		if (clip->type == MOVE_NOMONSTERS && touch->u.v.solid != SOLID_BSP)
    833 			continue;
    834 
    835 		if (clip->boxmins[0] > touch->u.v.absmax[0]
    836 		|| clip->boxmins[1] > touch->u.v.absmax[1]
    837 		|| clip->boxmins[2] > touch->u.v.absmax[2]
    838 		|| clip->boxmaxs[0] < touch->u.v.absmin[0]
    839 		|| clip->boxmaxs[1] < touch->u.v.absmin[1]
    840 		|| clip->boxmaxs[2] < touch->u.v.absmin[2] )
    841 			continue;
    842 
    843 		if (clip->passedict && clip->passedict->u.v.size[0] && !touch->u.v.size[0])
    844 			continue;	// points never interact
    845 
    846 	// might intersect, so do an exact clip
    847 		if (clip->trace.allsolid)
    848 			return;
    849 		if (clip->passedict)
    850 		{
    851 		 	if (PROG_TO_EDICT(touch->u.v.owner) == clip->passedict)
    852 				continue;	// don't clip against own missiles
    853 			if (PROG_TO_EDICT(clip->passedict->u.v.owner) == touch)
    854 				continue;	// don't clip against owner
    855 		}
    856 
    857 		if ((int)touch->u.v.flags & FL_MONSTER)
    858 			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
    859 		else
    860 			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
    861 		if (trace.allsolid || trace.startsolid ||
    862 		trace.fraction < clip->trace.fraction)
    863 		{
    864 			trace.ent = touch;
    865 		 	if (clip->trace.startsolid)
    866 			{
    867 				clip->trace = trace;
    868 				clip->trace.startsolid = true;
    869 			}
    870 			else
    871 				clip->trace = trace;
    872 		}
    873 		else if (trace.startsolid)
    874 			clip->trace.startsolid = true;
    875 	}
    876 
    877 // recurse down both sides
    878 	if (node->axis == -1)
    879 		return;
    880 
    881 	if ( clip->boxmaxs[node->axis] > node->dist )
    882 		SV_ClipToLinks ( node->children[0], clip );
    883 	if ( clip->boxmins[node->axis] < node->dist )
    884 		SV_ClipToLinks ( node->children[1], clip );
    885 }
    886 
    887 
    888 /*
    889 ==================
    890 SV_MoveBounds
    891 ==================
    892 */
    893 void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
    894 {
    895 #if 0
    896 // debug to test against everything
    897 boxmins[0] = boxmins[1] = boxmins[2] = -9999;
    898 boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
    899 #else
    900 	int		i;
    901 
    902 	for (i=0 ; i<3 ; i++)
    903 	{
    904 		if (end[i] > start[i])
    905 		{
    906 			boxmins[i] = start[i] + mins[i] - 1;
    907 			boxmaxs[i] = end[i] + maxs[i] + 1;
    908 		}
    909 		else
    910 		{
    911 			boxmins[i] = end[i] + mins[i] - 1;
    912 			boxmaxs[i] = start[i] + maxs[i] + 1;
    913 		}
    914 	}
    915 #endif
    916 }
    917 
    918 /*
    919 ==================
    920 SV_Move
    921 ==================
    922 */
    923 trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
    924 {
    925 	moveclip_t	clip;
    926 	int			i;
    927 
    928 	memset ( &clip, 0, sizeof ( moveclip_t ) );
    929 
    930 // clip to world
    931 	clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );
    932 
    933 	clip.start = start;
    934 	clip.end = end;
    935 	clip.mins = mins;
    936 	clip.maxs = maxs;
    937 	clip.type = type;
    938 	clip.passedict = passedict;
    939 
    940 	if (type == MOVE_MISSILE)
    941 	{
    942 		for (i=0 ; i<3 ; i++)
    943 		{
    944 			clip.mins2[i] = -15;
    945 			clip.maxs2[i] = 15;
    946 		}
    947 	}
    948 	else
    949 	{
    950 		VectorCopy (mins, clip.mins2);
    951 		VectorCopy (maxs, clip.maxs2);
    952 	}
    953 
    954 // create the bounding box of the entire move
    955 	SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
    956 
    957 // clip to entities
    958 	SV_ClipToLinks ( sv_areanodes, &clip );
    959 
    960 	return clip.trace;
    961 }
    962 
    963