1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "cm_local.h"
30 
31 // always use bbox vs. bbox collision and never capsule vs. bbox or vice versa
32 //#define ALWAYS_BBOX_VS_BBOX
33 // always use capsule vs. capsule collision and never capsule vs. bbox or vice versa
34 //#define ALWAYS_CAPSULE_VS_CAPSULE
35 
36 //#define CAPSULE_DEBUG
37 
38 /*
39 ===============================================================================
40 
41 BASIC MATH
42 
43 ===============================================================================
44 */
45 
46 /*
47 ================
48 RotatePoint
49 ================
50 */
RotatePoint(vec3_t point,const vec3_t matrix[3])51 void RotatePoint( vec3_t point, const vec3_t matrix[3] ) {
52 	vec3_t tvec;
53 
54 	VectorCopy( point, tvec );
55 	point[0] = DotProduct( matrix[0], tvec );
56 	point[1] = DotProduct( matrix[1], tvec );
57 	point[2] = DotProduct( matrix[2], tvec );
58 }
59 
60 /*
61 ================
62 TransposeMatrix
63 ================
64 */
TransposeMatrix(const vec3_t matrix[3],vec3_t transpose[3])65 void TransposeMatrix( const vec3_t matrix[3], vec3_t transpose[3] ) {
66 	int i, j;
67 	for ( i = 0; i < 3; i++ ) {
68 		for ( j = 0; j < 3; j++ ) {
69 			transpose[i][j] = matrix[j][i];
70 		}
71 	}
72 }
73 
74 /*
75 ================
76 CreateRotationMatrix
77 ================
78 */
CreateRotationMatrix(const vec3_t angles,vec3_t matrix[3])79 void CreateRotationMatrix( const vec3_t angles, vec3_t matrix[3] ) {
80 	AngleVectors( angles, matrix[0], matrix[1], matrix[2] );
81 	VectorInverse( matrix[1] );
82 }
83 
84 /*
85 ================
86 CM_ProjectPointOntoVector
87 ================
88 */
CM_ProjectPointOntoVector(vec3_t point,vec3_t vStart,vec3_t vDir,vec3_t vProj)89 void CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj ) {
90 	vec3_t pVec;
91 
92 	VectorSubtract( point, vStart, pVec );
93 	// project onto the directional vector for this segment
94 	VectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );
95 }
96 
97 /*
98 ================
99 CM_DistanceFromLineSquared
100 ================
101 */
CM_DistanceFromLineSquared(vec3_t p,vec3_t lp1,vec3_t lp2,vec3_t dir)102 float CM_DistanceFromLineSquared( vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir ) {
103 	vec3_t proj, t;
104 	int j;
105 
106 	CM_ProjectPointOntoVector( p, lp1, dir, proj );
107 	for ( j = 0; j < 3; j++ )
108 		if ( ( proj[j] > lp1[j] && proj[j] > lp2[j] ) ||
109 			 ( proj[j] < lp1[j] && proj[j] < lp2[j] ) ) {
110 			break;
111 		}
112 	if ( j < 3 ) {
113 		if ( fabs( proj[j] - lp1[j] ) < fabs( proj[j] - lp2[j] ) ) {
114 			VectorSubtract( p, lp1, t );
115 		} else {
116 			VectorSubtract( p, lp2, t );
117 		}
118 		return VectorLengthSquared( t );
119 	}
120 	VectorSubtract( p, proj, t );
121 	return VectorLengthSquared( t );
122 }
123 
124 /*
125 ================
126 CM_VectorDistanceSquared
127 ================
128 */
CM_VectorDistanceSquared(vec3_t p1,vec3_t p2)129 float CM_VectorDistanceSquared( vec3_t p1, vec3_t p2 ) {
130 	vec3_t dir;
131 
132 	VectorSubtract( p2, p1, dir );
133 	return VectorLengthSquared( dir );
134 }
135 
136 /*
137 ================
138 SquareRootFloat
139 ================
140 */
SquareRootFloat(float number)141 float SquareRootFloat( float number ) {
142 	floatint_t t;
143 	float x, y;
144 	const float f = 1.5F;
145 
146 	x = number * 0.5F;
147 	t.f  = number;
148 	t.i  = 0x5f3759df - ( t.i >> 1 );
149 	y  = t.f;
150 	y  = y * ( f - ( x * y * y ) );
151 	y  = y * ( f - ( x * y * y ) );
152 	return number * y;
153 }
154 
155 
156 /*
157 ===============================================================================
158 
159 POSITION TESTING
160 
161 ===============================================================================
162 */
163 
164 /*
165 ================
166 CM_TestBoxInBrush
167 ================
168 */
CM_TestBoxInBrush(traceWork_t * tw,cbrush_t * brush)169 void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {
170 	int i;
171 	cplane_t    *plane;
172 	float dist;
173 	float d1;
174 	cbrushside_t    *side;
175 	float t;
176 	vec3_t startp;
177 
178 	if ( !brush->numsides ) {
179 		return;
180 	}
181 
182 	// special test for axial
183 	// the first 6 brush planes are always axial
184 	if ( tw->bounds[0][0] > brush->bounds[1][0]
185 		 || tw->bounds[0][1] > brush->bounds[1][1]
186 		 || tw->bounds[0][2] > brush->bounds[1][2]
187 		 || tw->bounds[1][0] < brush->bounds[0][0]
188 		 || tw->bounds[1][1] < brush->bounds[0][1]
189 		 || tw->bounds[1][2] < brush->bounds[0][2]
190 		 ) {
191 		return;
192 	}
193 
194 	if ( tw->sphere.use ) {
195 		// the first six planes are the axial planes, so we only
196 		// need to test the remainder
197 		for ( i = 6 ; i < brush->numsides ; i++ ) {
198 			side = brush->sides + i;
199 			plane = side->plane;
200 
201 			// adjust the plane distance apropriately for radius
202 			dist = plane->dist + tw->sphere.radius;
203 			// find the closest point on the capsule to the plane
204 			t = DotProduct( plane->normal, tw->sphere.offset );
205 			if ( t > 0 ) {
206 				VectorSubtract( tw->start, tw->sphere.offset, startp );
207 			} else
208 			{
209 				VectorAdd( tw->start, tw->sphere.offset, startp );
210 			}
211 			d1 = DotProduct( startp, plane->normal ) - dist;
212 			// if completely in front of face, no intersection
213 			if ( d1 > 0 ) {
214 				return;
215 			}
216 		}
217 	} else {
218 		// the first six planes are the axial planes, so we only
219 		// need to test the remainder
220 		for ( i = 6 ; i < brush->numsides ; i++ ) {
221 			side = brush->sides + i;
222 			plane = side->plane;
223 
224 			// adjust the plane distance apropriately for mins/maxs
225 			dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
226 
227 			d1 = DotProduct( tw->start, plane->normal ) - dist;
228 
229 			// if completely in front of face, no intersection
230 			if ( d1 > 0 ) {
231 				return;
232 			}
233 		}
234 	}
235 
236 	// inside this brush
237 	tw->trace.startsolid = tw->trace.allsolid = qtrue;
238 	tw->trace.fraction = 0;
239 	tw->trace.contents = brush->contents;
240 }
241 
242 
243 
244 /*
245 ================
246 CM_TestInLeaf
247 ================
248 */
CM_TestInLeaf(traceWork_t * tw,cLeaf_t * leaf)249 void CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
250 	int k;
251 	int brushnum;
252 	cbrush_t    *b;
253 	cPatch_t    *patch;
254 
255 	// test box position against all brushes in the leaf
256 	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
257 		brushnum = cm.leafbrushes[leaf->firstLeafBrush + k];
258 		b = &cm.brushes[brushnum];
259 		if ( b->checkcount == cm.checkcount ) {
260 			continue;   // already checked this brush in another leaf
261 		}
262 		b->checkcount = cm.checkcount;
263 
264 		if ( !( b->contents & tw->contents ) ) {
265 			continue;
266 		}
267 
268 		CM_TestBoxInBrush( tw, b );
269 		if ( tw->trace.allsolid ) {
270 			return;
271 		}
272 	}
273 
274 	// test against all patches
275 #ifdef BSPC
276 	if ( 1 ) {
277 #else
278 	if ( !cm_noCurves->integer ) {
279 #endif //BSPC
280 		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
281 			patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
282 			if ( !patch ) {
283 				continue;
284 			}
285 			if ( patch->checkcount == cm.checkcount ) {
286 				continue;   // already checked this brush in another leaf
287 			}
288 			patch->checkcount = cm.checkcount;
289 
290 			if ( !( patch->contents & tw->contents ) ) {
291 				continue;
292 			}
293 
294 			if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
295 				tw->trace.startsolid = tw->trace.allsolid = qtrue;
296 				tw->trace.fraction = 0;
297 				return;
298 			}
299 		}
300 	}
301 }
302 
303 /*
304 ==================
305 CM_TestCapsuleInCapsule
306 
307 capsule inside capsule check
308 ==================
309 */
310 void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {
311 	int i;
312 	vec3_t mins, maxs;
313 	vec3_t top, bottom;
314 	vec3_t p1, p2, tmp;
315 	vec3_t offset, symetricSize[2];
316 	float radius, halfwidth, halfheight, offs, r;
317 
318 	CM_ModelBounds( model, mins, maxs );
319 
320 	VectorAdd( tw->start, tw->sphere.offset, top );
321 	VectorSubtract( tw->start, tw->sphere.offset, bottom );
322 	for ( i = 0 ; i < 3 ; i++ ) {
323 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
324 		symetricSize[0][i] = mins[i] - offset[i];
325 		symetricSize[1][i] = maxs[i] - offset[i];
326 	}
327 	halfwidth = symetricSize[ 1 ][ 0 ];
328 	halfheight = symetricSize[ 1 ][ 2 ];
329 	radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
330 	offs = halfheight - radius;
331 
332 	r = Square( tw->sphere.radius + radius );
333 	// check if any of the spheres overlap
334 	VectorCopy( offset, p1 );
335 	p1[2] += offs;
336 	VectorSubtract( p1, top, tmp );
337 	if ( VectorLengthSquared( tmp ) < r ) {
338 		tw->trace.startsolid = tw->trace.allsolid = qtrue;
339 		tw->trace.fraction = 0;
340 	}
341 	VectorSubtract( p1, bottom, tmp );
342 	if ( VectorLengthSquared( tmp ) < r ) {
343 		tw->trace.startsolid = tw->trace.allsolid = qtrue;
344 		tw->trace.fraction = 0;
345 	}
346 	VectorCopy( offset, p2 );
347 	p2[2] -= offs;
348 	VectorSubtract( p2, top, tmp );
349 	if ( VectorLengthSquared( tmp ) < r ) {
350 		tw->trace.startsolid = tw->trace.allsolid = qtrue;
351 		tw->trace.fraction = 0;
352 	}
353 	VectorSubtract( p2, bottom, tmp );
354 	if ( VectorLengthSquared( tmp ) < r ) {
355 		tw->trace.startsolid = tw->trace.allsolid = qtrue;
356 		tw->trace.fraction = 0;
357 	}
358 	// if between cylinder up and lower bounds
359 	if ( ( top[2] >= p1[2] && top[2] <= p2[2] ) ||
360 		 ( bottom[2] >= p1[2] && bottom[2] <= p2[2] ) ) {
361 		// 2d coordinates
362 		top[2] = p1[2] = 0;
363 		// if the cylinders overlap
364 		VectorSubtract( top, p1, tmp );
365 		if ( VectorLengthSquared( tmp ) < r ) {
366 			tw->trace.startsolid = tw->trace.allsolid = qtrue;
367 			tw->trace.fraction = 0;
368 		}
369 	}
370 }
371 
372 /*
373 ==================
374 CM_TestBoundingBoxInCapsule
375 
376 bounding box inside capsule check
377 ==================
378 */
379 void CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) {
380 	vec3_t mins, maxs, offset, size[2];
381 	clipHandle_t h;
382 	cmodel_t *cmod;
383 	int i;
384 
385 	// mins maxs of the capsule
386 	CM_ModelBounds( model, mins, maxs );
387 
388 	// offset for capsule center
389 	for ( i = 0 ; i < 3 ; i++ ) {
390 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
391 		size[0][i] = mins[i] - offset[i];
392 		size[1][i] = maxs[i] - offset[i];
393 		tw->start[i] -= offset[i];
394 		tw->end[i] -= offset[i];
395 	}
396 
397 	// replace the bounding box with the capsule
398 	tw->sphere.use = qtrue;
399 	tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2] : size[1][0];
400 	tw->sphere.halfheight = size[1][2];
401 	VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
402 
403 	// replace the capsule with the bounding box
404 	h = CM_TempBoxModel( tw->size[0], tw->size[1], qfalse );
405 	// calculate collision
406 	cmod = CM_ClipHandleToModel( h );
407 	CM_TestInLeaf( tw, &cmod->leaf );
408 }
409 
410 /*
411 ==================
412 CM_PositionTest
413 ==================
414 */
415 #define MAX_POSITION_LEAFS  1024
416 void CM_PositionTest( traceWork_t *tw ) {
417 	int leafs[MAX_POSITION_LEAFS];
418 	int i;
419 	leafList_t ll;
420 
421 	// identify the leafs we are touching
422 	VectorAdd( tw->start, tw->size[0], ll.bounds[0] );
423 	VectorAdd( tw->start, tw->size[1], ll.bounds[1] );
424 
425 	for ( i = 0 ; i < 3 ; i++ ) {
426 		ll.bounds[0][i] -= 1;
427 		ll.bounds[1][i] += 1;
428 	}
429 
430 	ll.count = 0;
431 	ll.maxcount = MAX_POSITION_LEAFS;
432 	ll.list = leafs;
433 	ll.storeLeafs = CM_StoreLeafs;
434 	ll.lastLeaf = 0;
435 	ll.overflowed = qfalse;
436 
437 	cm.checkcount++;
438 
439 	CM_BoxLeafnums_r( &ll, 0 );
440 
441 
442 	cm.checkcount++;
443 
444 	// test the contents of the leafs
445 	for ( i = 0 ; i < ll.count ; i++ ) {
446 		CM_TestInLeaf( tw, &cm.leafs[leafs[i]] );
447 		if ( tw->trace.allsolid ) {
448 			break;
449 		}
450 	}
451 }
452 
453 /*
454 ===============================================================================
455 
456 TRACING
457 
458 ===============================================================================
459 */
460 
461 
462 /*
463 ================
464 CM_TraceThroughPatch
465 ================
466 */
467 
468 void CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {
469 	float oldFrac;
470 
471 	c_patch_traces++;
472 
473 	oldFrac = tw->trace.fraction;
474 
475 	CM_TraceThroughPatchCollide( tw, patch->pc );
476 
477 	if ( tw->trace.fraction < oldFrac ) {
478 		tw->trace.surfaceFlags = patch->surfaceFlags;
479 		tw->trace.contents = patch->contents;
480 	}
481 }
482 
483 /*
484 ================
485 CM_TraceThroughBrush
486 ================
487 */
488 void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {
489 	int i;
490 	cplane_t    *plane, *clipplane;
491 	float dist;
492 	float enterFrac, leaveFrac;
493 	float d1, d2;
494 	qboolean getout, startout;
495 	float f;
496 	cbrushside_t    *side, *leadside;
497 	float t;
498 	vec3_t startp;
499 	vec3_t endp;
500 
501 	enterFrac = -1.0;
502 	leaveFrac = 1.0;
503 	clipplane = NULL;
504 
505 	if ( !brush->numsides ) {
506 		return;
507 	}
508 
509 	c_brush_traces++;
510 
511 	getout = qfalse;
512 	startout = qfalse;
513 
514 	leadside = NULL;
515 
516 	if ( tw->sphere.use ) {
517 		//
518 		// compare the trace against all planes of the brush
519 		// find the latest time the trace crosses a plane towards the interior
520 		// and the earliest time the trace crosses a plane towards the exterior
521 		//
522 		for ( i = 0; i < brush->numsides; i++ ) {
523 			side = brush->sides + i;
524 			plane = side->plane;
525 
526 			// adjust the plane distance apropriately for radius
527 			dist = plane->dist + tw->sphere.radius;
528 
529 			// find the closest point on the capsule to the plane
530 			t = DotProduct( plane->normal, tw->sphere.offset );
531 			if ( t > 0 ) {
532 				VectorSubtract( tw->start, tw->sphere.offset, startp );
533 				VectorSubtract( tw->end, tw->sphere.offset, endp );
534 			} else
535 			{
536 				VectorAdd( tw->start, tw->sphere.offset, startp );
537 				VectorAdd( tw->end, tw->sphere.offset, endp );
538 			}
539 
540 			d1 = DotProduct( startp, plane->normal ) - dist;
541 			d2 = DotProduct( endp, plane->normal ) - dist;
542 
543 			if ( d2 > 0 ) {
544 				getout = qtrue; // endpoint is not in solid
545 			}
546 			if ( d1 > 0 ) {
547 				startout = qtrue;
548 			}
549 
550 			// if completely in front of face, no intersection with the entire brush
551 			if ( d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {
552 				return;
553 			}
554 
555 			// if it doesn't cross the plane, the plane isn't relevent
556 			if ( d1 <= 0 && d2 <= 0 ) {
557 				continue;
558 			}
559 
560 			// crosses face
561 			if ( d1 > d2 ) {  // enter
562 				f = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
563 				if ( f < 0 ) {
564 					f = 0;
565 				}
566 				if ( f > enterFrac ) {
567 					enterFrac = f;
568 					clipplane = plane;
569 					leadside = side;
570 				}
571 			} else {    // leave
572 				f = ( d1 + SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
573 				if ( f > 1 ) {
574 					f = 1;
575 				}
576 				if ( f < leaveFrac ) {
577 					leaveFrac = f;
578 				}
579 			}
580 		}
581 	} else {
582 		//
583 		// compare the trace against all planes of the brush
584 		// find the latest time the trace crosses a plane towards the interior
585 		// and the earliest time the trace crosses a plane towards the exterior
586 		//
587 		for ( i = 0; i < brush->numsides; i++ ) {
588 			side = brush->sides + i;
589 			plane = side->plane;
590 
591 			// adjust the plane distance apropriately for mins/maxs
592 			dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
593 
594 			d1 = DotProduct( tw->start, plane->normal ) - dist;
595 			d2 = DotProduct( tw->end, plane->normal ) - dist;
596 
597 			if ( d2 > 0 ) {
598 				getout = qtrue; // endpoint is not in solid
599 			}
600 			if ( d1 > 0 ) {
601 				startout = qtrue;
602 			}
603 
604 			// if completely in front of face, no intersection with the entire brush
605 			if ( d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {
606 				return;
607 			}
608 
609 			// if it doesn't cross the plane, the plane isn't relevent
610 			if ( d1 <= 0 && d2 <= 0 ) {
611 				continue;
612 			}
613 
614 			// crosses face
615 			if ( d1 > d2 ) {  // enter
616 				f = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
617 				if ( f < 0 ) {
618 					f = 0;
619 				}
620 				if ( f > enterFrac ) {
621 					enterFrac = f;
622 					clipplane = plane;
623 					leadside = side;
624 				}
625 			} else {    // leave
626 				f = ( d1 + SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
627 				if ( f > 1 ) {
628 					f = 1;
629 				}
630 				if ( f < leaveFrac ) {
631 					leaveFrac = f;
632 				}
633 			}
634 		}
635 	}
636 
637 	//
638 	// all planes have been checked, and the trace was not
639 	// completely outside the brush
640 	//
641 	if ( !startout ) {    // original point was inside brush
642 		tw->trace.startsolid = qtrue;
643 		if ( !getout ) {
644 			tw->trace.allsolid = qtrue;
645 			tw->trace.fraction = 0;
646 		}
647 		return;
648 	}
649 
650 	if ( enterFrac < leaveFrac ) {
651 		if ( enterFrac > -1 && enterFrac < tw->trace.fraction ) {
652 			if ( enterFrac < 0 ) {
653 				enterFrac = 0;
654 			}
655 			tw->trace.fraction = enterFrac;
656 			if (clipplane != NULL) {
657 				tw->trace.plane = *clipplane;
658 			}
659 			if (leadside != NULL) {
660 				tw->trace.surfaceFlags = leadside->surfaceFlags;
661 			}
662 			tw->trace.contents = brush->contents;
663 		}
664 	}
665 }
666 
667 /*
668 ================
669 CM_TraceThroughLeaf
670 ================
671 */
672 void CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
673 	int k;
674 	int brushnum;
675 	cbrush_t    *b;
676 	cPatch_t    *patch;
677 
678 	// trace line against all brushes in the leaf
679 	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
680 		brushnum = cm.leafbrushes[leaf->firstLeafBrush + k];
681 
682 		b = &cm.brushes[brushnum];
683 		if ( b->checkcount == cm.checkcount ) {
684 			continue;   // already checked this brush in another leaf
685 		}
686 		b->checkcount = cm.checkcount;
687 
688 		if ( !( b->contents & tw->contents ) ) {
689 			continue;
690 		}
691 
692 		if ( !CM_BoundsIntersect( tw->bounds[0], tw->bounds[1],
693 					b->bounds[0], b->bounds[1] ) ) {
694 			continue;
695 		}
696 
697 		CM_TraceThroughBrush( tw, b );
698 		if ( !tw->trace.fraction ) {
699 			return;
700 		}
701 	}
702 
703 	// trace line against all patches in the leaf
704 #ifdef BSPC
705 	if ( 1 ) {
706 #else
707 	if ( !cm_noCurves->integer ) {
708 #endif
709 		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
710 			patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
711 			if ( !patch ) {
712 				continue;
713 			}
714 			if ( patch->checkcount == cm.checkcount ) {
715 				continue;   // already checked this patch in another leaf
716 			}
717 			patch->checkcount = cm.checkcount;
718 
719 			if ( !( patch->contents & tw->contents ) ) {
720 				continue;
721 			}
722 
723 			CM_TraceThroughPatch( tw, patch );
724 			if ( !tw->trace.fraction ) {
725 				return;
726 			}
727 		}
728 	}
729 }
730 
731 #define RADIUS_EPSILON      1.0f
732 
733 /*
734 ================
735 CM_TraceThroughSphere
736 
737 get the first intersection of the ray with the sphere
738 ================
739 */
740 void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
741 	float l1, l2, length, scale, fraction;
742 	//float a;
743 	float b, c, d, sqrtd;
744 	vec3_t v1, dir, intersection;
745 
746 	// if inside the sphere
747 	VectorSubtract( start, origin, dir );
748 	l1 = VectorLengthSquared( dir );
749 	if ( l1 < Square( radius ) ) {
750 		tw->trace.fraction = 0;
751 		tw->trace.startsolid = qtrue;
752 		// test for allsolid
753 		VectorSubtract( end, origin, dir );
754 		l1 = VectorLengthSquared( dir );
755 		if ( l1 < Square( radius ) ) {
756 			tw->trace.allsolid = qtrue;
757 		}
758 		return;
759 	}
760 	//
761 	VectorSubtract( end, start, dir );
762 	length = VectorNormalize( dir );
763 	//
764 	l1 = CM_DistanceFromLineSquared( origin, start, end, dir );
765 	VectorSubtract( end, origin, v1 );
766 	l2 = VectorLengthSquared( v1 );
767 	// if no intersection with the sphere and the end point is at least an epsilon away
768 	if ( l1 >= Square( radius ) && l2 > Square( radius + SURFACE_CLIP_EPSILON ) ) {
769 		return;
770 	}
771 	//
772 	//	| origin - (start + t * dir) | = radius
773 	//	a = dir[0]^2 + dir[1]^2 + dir[2]^2;
774 	//	b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
775 	//	c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
776 	//
777 	VectorSubtract( start, origin, v1 );
778 	// dir is normalized so a = 1
779 	//a = 1.0f; //dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
780 	b = 2.0f * ( dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2] );
781 	c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - ( radius + RADIUS_EPSILON ) * ( radius + RADIUS_EPSILON );
782 
783 	d = b * b - 4.0f * c; // * a;
784 	if ( d > 0 ) {
785 		sqrtd = SquareRootFloat( d );
786 		// = (- b + sqrtd) * 0.5f; // / (2.0f * a);
787 		fraction = ( -b - sqrtd ) * 0.5f; // / (2.0f * a);
788 		//
789 		if ( fraction < 0 ) {
790 			fraction = 0;
791 		} else {
792 			fraction /= length;
793 		}
794 		if ( fraction < tw->trace.fraction ) {
795 			tw->trace.fraction = fraction;
796 			VectorSubtract( end, start, dir );
797 			VectorMA( start, fraction, dir, intersection );
798 			VectorSubtract( intersection, origin, dir );
799 			#ifdef CAPSULE_DEBUG
800 			l2 = VectorLength( dir );
801 			if ( l2 < radius ) {
802 				int bah = 1;
803 			}
804 			#endif
805 			scale = 1 / ( radius + RADIUS_EPSILON );
806 			VectorScale( dir, scale, dir );
807 			VectorCopy( dir, tw->trace.plane.normal );
808 			VectorAdd( tw->modelOrigin, intersection, intersection );
809 			tw->trace.plane.dist = DotProduct( tw->trace.plane.normal, intersection );
810 			tw->trace.contents = CONTENTS_BODY;
811 		}
812 	} else if ( d == 0 )     {
813 		//t1 = (- b ) / 2;
814 		// slide along the sphere
815 	}
816 	// no intersection at all
817 }
818 
819 /*
820 ================
821 CM_TraceThroughVerticalCylinder
822 
823 get the first intersection of the ray with the cylinder
824 the cylinder extends halfheight above and below the origin
825 ================
826 */
827 void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end ) {
828 	float length, scale, fraction, l1, l2;
829 	//float a;
830 	float b, c, d, sqrtd;
831 	vec3_t v1, dir, start2d, end2d, org2d, intersection;
832 
833 	// 2d coordinates
834 	VectorSet( start2d, start[0], start[1], 0 );
835 	VectorSet( end2d, end[0], end[1], 0 );
836 	VectorSet( org2d, origin[0], origin[1], 0 );
837 	// if between lower and upper cylinder bounds
838 	if ( start[2] <= origin[2] + halfheight &&
839 		 start[2] >= origin[2] - halfheight ) {
840 		// if inside the cylinder
841 		VectorSubtract( start2d, org2d, dir );
842 		l1 = VectorLengthSquared( dir );
843 		if ( l1 < Square( radius ) ) {
844 			tw->trace.fraction = 0;
845 			tw->trace.startsolid = qtrue;
846 			VectorSubtract( end2d, org2d, dir );
847 			l1 = VectorLengthSquared( dir );
848 			if ( l1 < Square( radius ) ) {
849 				tw->trace.allsolid = qtrue;
850 			}
851 			return;
852 		}
853 	}
854 	//
855 	VectorSubtract( end2d, start2d, dir );
856 	length = VectorNormalize( dir );
857 	//
858 	l1 = CM_DistanceFromLineSquared( org2d, start2d, end2d, dir );
859 	VectorSubtract( end2d, org2d, v1 );
860 	l2 = VectorLengthSquared( v1 );
861 	// if no intersection with the cylinder and the end point is at least an epsilon away
862 	if ( l1 >= Square( radius ) && l2 > Square( radius + SURFACE_CLIP_EPSILON ) ) {
863 		return;
864 	}
865 	//
866 	//
867 	// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
868 	// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
869 	// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
870 	//						v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
871 	// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
872 	//						v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
873 	//
874 	VectorSubtract( start, origin, v1 );
875 	// dir is normalized so we can use a = 1
876 	//a = 1.0f; // * (dir[0] * dir[0] + dir[1] * dir[1]);
877 	b = 2.0f * ( v1[0] * dir[0] + v1[1] * dir[1] );
878 	c = v1[0] * v1[0] + v1[1] * v1[1] - ( radius + RADIUS_EPSILON ) * ( radius + RADIUS_EPSILON );
879 
880 	d = b * b - 4.0f * c; // * a;
881 	if ( d > 0 ) {
882 		sqrtd = SquareRootFloat( d );
883 		// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
884 		fraction = ( -b - sqrtd ) * 0.5f; // / (2.0f * a);
885 		//
886 		if ( fraction < 0 ) {
887 			fraction = 0;
888 		} else {
889 			fraction /= length;
890 		}
891 		if ( fraction < tw->trace.fraction ) {
892 			VectorSubtract( end, start, dir );
893 			VectorMA( start, fraction, dir, intersection );
894 			// if the intersection is between the cylinder lower and upper bound
895 			if ( intersection[2] <= origin[2] + halfheight &&
896 				 intersection[2] >= origin[2] - halfheight ) {
897 				//
898 				tw->trace.fraction = fraction;
899 				VectorSubtract( intersection, origin, dir );
900 				dir[2] = 0;
901 				#ifdef CAPSULE_DEBUG
902 				l2 = VectorLength( dir );
903 				if ( l2 <= radius ) {
904 					int bah = 1;
905 				}
906 				#endif
907 				scale = 1 / ( radius + RADIUS_EPSILON );
908 				VectorScale( dir, scale, dir );
909 				VectorCopy( dir, tw->trace.plane.normal );
910 				VectorAdd( tw->modelOrigin, intersection, intersection );
911 				tw->trace.plane.dist = DotProduct( tw->trace.plane.normal, intersection );
912 				tw->trace.contents = CONTENTS_BODY;
913 			}
914 		}
915 	} else if ( d == 0 )     {
916 		//t[0] = (- b ) / 2 * a;
917 		// slide along the cylinder
918 	}
919 	// no intersection at all
920 }
921 
922 /*
923 ================
924 CM_TraceCapsuleThroughCapsule
925 
926 capsule vs. capsule collision (not rotated)
927 ================
928 */
929 void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
930 	int i;
931 	vec3_t mins, maxs;
932 	vec3_t top, bottom, starttop, startbottom, endtop, endbottom;
933 	vec3_t offset, symetricSize[2];
934 	float radius, halfwidth, halfheight, offs, h;
935 
936 	CM_ModelBounds( model, mins, maxs );
937 	// test trace bounds vs. capsule bounds
938 	if ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON
939 		 || tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON
940 		 || tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON
941 		 || tw->bounds[1][0] < mins[0] - RADIUS_EPSILON
942 		 || tw->bounds[1][1] < mins[1] - RADIUS_EPSILON
943 		 || tw->bounds[1][2] < mins[2] - RADIUS_EPSILON
944 		 ) {
945 		return;
946 	}
947 	// top origin and bottom origin of each sphere at start and end of trace
948 	VectorAdd( tw->start, tw->sphere.offset, starttop );
949 	VectorSubtract( tw->start, tw->sphere.offset, startbottom );
950 	VectorAdd( tw->end, tw->sphere.offset, endtop );
951 	VectorSubtract( tw->end, tw->sphere.offset, endbottom );
952 
953 	// calculate top and bottom of the capsule spheres to collide with
954 	for ( i = 0 ; i < 3 ; i++ ) {
955 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
956 		symetricSize[0][i] = mins[i] - offset[i];
957 		symetricSize[1][i] = maxs[i] - offset[i];
958 	}
959 	halfwidth = symetricSize[ 1 ][ 0 ];
960 	halfheight = symetricSize[ 1 ][ 2 ];
961 	radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
962 	offs = halfheight - radius;
963 	VectorCopy( offset, top );
964 	top[2] += offs;
965 	VectorCopy( offset, bottom );
966 	bottom[2] -= offs;
967 	// expand radius of spheres
968 	radius += tw->sphere.radius;
969 	// if there is horizontal movement
970 	if ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) {
971 		// height of the expanded cylinder is the height of both cylinders minus the radius of both spheres
972 		h = halfheight + tw->sphere.halfheight - radius;
973 		// if the cylinder has a height
974 		if ( h > 0 ) {
975 			// test for collisions between the cylinders
976 			CM_TraceThroughVerticalCylinder( tw, offset, radius, h, tw->start, tw->end );
977 		}
978 	}
979 	// test for collision between the spheres
980 	CM_TraceThroughSphere( tw, top, radius, startbottom, endbottom );
981 	CM_TraceThroughSphere( tw, bottom, radius, starttop, endtop );
982 }
983 
984 /*
985 ================
986 CM_TraceBoundingBoxThroughCapsule
987 
988 bounding box vs. capsule collision
989 ================
990 */
991 void CM_TraceBoundingBoxThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
992 	vec3_t mins, maxs, offset, size[2];
993 	clipHandle_t h;
994 	cmodel_t *cmod;
995 	int i;
996 
997 	// mins maxs of the capsule
998 	CM_ModelBounds( model, mins, maxs );
999 
1000 	// offset for capsule center
1001 	for ( i = 0 ; i < 3 ; i++ ) {
1002 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
1003 		size[0][i] = mins[i] - offset[i];
1004 		size[1][i] = maxs[i] - offset[i];
1005 		tw->start[i] -= offset[i];
1006 		tw->end[i] -= offset[i];
1007 	}
1008 
1009 	// replace the bounding box with the capsule
1010 	tw->sphere.use = qtrue;
1011 	tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2] : size[1][0];
1012 	tw->sphere.halfheight = size[1][2];
1013 	VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
1014 
1015 	// replace the capsule with the bounding box
1016 	h = CM_TempBoxModel( tw->size[0], tw->size[1], qfalse );
1017 	// calculate collision
1018 	cmod = CM_ClipHandleToModel( h );
1019 	CM_TraceThroughLeaf( tw, &cmod->leaf );
1020 }
1021 
1022 //=========================================================================================
1023 
1024 /*
1025 ==================
1026 CM_TraceThroughTree
1027 
1028 Traverse all the contacted leafs from the start to the end position.
1029 If the trace is a point, they will be exactly in order, but for larger
1030 trace volumes it is possible to hit something in a later leaf with
1031 a smaller intercept fraction.
1032 ==================
1033 */
1034 void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2 ) {
1035 	cNode_t     *node;
1036 	cplane_t    *plane;
1037 	float t1, t2, offset;
1038 	float frac, frac2;
1039 	float idist;
1040 	vec3_t mid;
1041 	int side;
1042 	float midf;
1043 
1044 	if ( tw->trace.fraction <= p1f ) {
1045 		return;     // already hit something nearer
1046 	}
1047 
1048 	// if < 0, we are in a leaf node
1049 	if ( num < 0 ) {
1050 		CM_TraceThroughLeaf( tw, &cm.leafs[-1 - num] );
1051 		return;
1052 	}
1053 
1054 	//
1055 	// find the point distances to the separating plane
1056 	// and the offset for the size of the box
1057 	//
1058 	node = cm.nodes + num;
1059 	plane = node->plane;
1060 
1061 	// adjust the plane distance apropriately for mins/maxs
1062 	if ( plane->type < 3 ) {
1063 		t1 = p1[plane->type] - plane->dist;
1064 		t2 = p2[plane->type] - plane->dist;
1065 		offset = tw->extents[plane->type];
1066 	} else {
1067 		t1 = DotProduct( plane->normal, p1 ) - plane->dist;
1068 		t2 = DotProduct( plane->normal, p2 ) - plane->dist;
1069 		if ( tw->isPoint ) {
1070 			offset = 0;
1071 		} else {
1072 			// this is silly
1073 			offset = 2048;
1074 		}
1075 	}
1076 
1077 	// see which sides we need to consider
1078 	if ( t1 >= offset + 1 && t2 >= offset + 1 ) {
1079 		CM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 );
1080 		return;
1081 	}
1082 	if ( t1 < -offset - 1 && t2 < -offset - 1 ) {
1083 		CM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 );
1084 		return;
1085 	}
1086 
1087 	// put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
1088 	if ( t1 < t2 ) {
1089 		idist = 1.0 / ( t1 - t2 );
1090 		side = 1;
1091 		frac2 = ( t1 + offset + SURFACE_CLIP_EPSILON ) * idist;
1092 		frac = ( t1 - offset + SURFACE_CLIP_EPSILON ) * idist;
1093 	} else if ( t1 > t2 ) {
1094 		idist = 1.0 / ( t1 - t2 );
1095 		side = 0;
1096 		frac2 = ( t1 - offset - SURFACE_CLIP_EPSILON ) * idist;
1097 		frac = ( t1 + offset + SURFACE_CLIP_EPSILON ) * idist;
1098 	} else {
1099 		side = 0;
1100 		frac = 1;
1101 		frac2 = 0;
1102 	}
1103 
1104 	// move up to the node
1105 	if ( frac < 0 ) {
1106 		frac = 0;
1107 	}
1108 	if ( frac > 1 ) {
1109 		frac = 1;
1110 	}
1111 
1112 	midf = p1f + ( p2f - p1f ) * frac;
1113 
1114 	mid[0] = p1[0] + frac * ( p2[0] - p1[0] );
1115 	mid[1] = p1[1] + frac * ( p2[1] - p1[1] );
1116 	mid[2] = p1[2] + frac * ( p2[2] - p1[2] );
1117 
1118 	CM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, mid );
1119 
1120 
1121 	// go past the node
1122 	if ( frac2 < 0 ) {
1123 		frac2 = 0;
1124 	}
1125 	if ( frac2 > 1 ) {
1126 		frac2 = 1;
1127 	}
1128 
1129 	midf = p1f + ( p2f - p1f ) * frac2;
1130 
1131 	mid[0] = p1[0] + frac2 * ( p2[0] - p1[0] );
1132 	mid[1] = p1[1] + frac2 * ( p2[1] - p1[1] );
1133 	mid[2] = p1[2] + frac2 * ( p2[2] - p1[2] );
1134 
1135 	CM_TraceThroughTree( tw, node->children[side ^ 1], midf, p2f, mid, p2 );
1136 }
1137 
1138 
1139 //======================================================================
1140 
1141 
1142 /*
1143 ==================
1144 CM_Trace
1145 ==================
1146 */
1147 void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end,
1148 			   const vec3_t mins, const vec3_t maxs,
1149 			   clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {
1150 	int i;
1151 	traceWork_t tw;
1152 	vec3_t offset;
1153 	cmodel_t    *cmod;
1154 
1155 	cmod = CM_ClipHandleToModel( model );
1156 
1157 	cm.checkcount++;        // for multi-check avoidance
1158 
1159 	c_traces++;             // for statistics, may be zeroed
1160 
1161 	// fill in a default trace
1162 	memset( &tw, 0, sizeof( tw ) );
1163 	tw.trace.fraction = 1;  // assume it goes the entire distance until shown otherwise
1164 	VectorCopy( origin, tw.modelOrigin );
1165 
1166 	if ( !cm.numNodes ) {
1167 		*results = tw.trace;
1168 
1169 		return; // map not loaded, shouldn't happen
1170 	}
1171 
1172 	// allow NULL to be passed in for 0,0,0
1173 	if ( !mins ) {
1174 		mins = vec3_origin;
1175 	}
1176 	if ( !maxs ) {
1177 		maxs = vec3_origin;
1178 	}
1179 
1180 	// set basic parms
1181 	tw.contents = brushmask;
1182 
1183 	// adjust so that mins and maxs are always symetric, which
1184 	// avoids some complications with plane expanding of rotated
1185 	// bmodels
1186 	for ( i = 0 ; i < 3 ; i++ ) {
1187 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
1188 		tw.size[0][i] = mins[i] - offset[i];
1189 		tw.size[1][i] = maxs[i] - offset[i];
1190 		tw.start[i] = start[i] + offset[i];
1191 		tw.end[i] = end[i] + offset[i];
1192 	}
1193 
1194 	// if a sphere is already specified
1195 	if ( sphere ) {
1196 		tw.sphere = *sphere;
1197 	} else {
1198 		tw.sphere.use = capsule;
1199 		tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2] : tw.size[1][0];
1200 		tw.sphere.halfheight = tw.size[1][2];
1201 		VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
1202 	}
1203 
1204 	tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];
1205 
1206 	// tw.offsets[signbits] = vector to apropriate corner from origin
1207 	tw.offsets[0][0] = tw.size[0][0];
1208 	tw.offsets[0][1] = tw.size[0][1];
1209 	tw.offsets[0][2] = tw.size[0][2];
1210 
1211 	tw.offsets[1][0] = tw.size[1][0];
1212 	tw.offsets[1][1] = tw.size[0][1];
1213 	tw.offsets[1][2] = tw.size[0][2];
1214 
1215 	tw.offsets[2][0] = tw.size[0][0];
1216 	tw.offsets[2][1] = tw.size[1][1];
1217 	tw.offsets[2][2] = tw.size[0][2];
1218 
1219 	tw.offsets[3][0] = tw.size[1][0];
1220 	tw.offsets[3][1] = tw.size[1][1];
1221 	tw.offsets[3][2] = tw.size[0][2];
1222 
1223 	tw.offsets[4][0] = tw.size[0][0];
1224 	tw.offsets[4][1] = tw.size[0][1];
1225 	tw.offsets[4][2] = tw.size[1][2];
1226 
1227 	tw.offsets[5][0] = tw.size[1][0];
1228 	tw.offsets[5][1] = tw.size[0][1];
1229 	tw.offsets[5][2] = tw.size[1][2];
1230 
1231 	tw.offsets[6][0] = tw.size[0][0];
1232 	tw.offsets[6][1] = tw.size[1][1];
1233 	tw.offsets[6][2] = tw.size[1][2];
1234 
1235 	tw.offsets[7][0] = tw.size[1][0];
1236 	tw.offsets[7][1] = tw.size[1][1];
1237 	tw.offsets[7][2] = tw.size[1][2];
1238 
1239 	//
1240 	// calculate bounds
1241 	//
1242 	if ( tw.sphere.use ) {
1243 		for ( i = 0 ; i < 3 ; i++ ) {
1244 			if ( tw.start[i] < tw.end[i] ) {
1245 				tw.bounds[0][i] = tw.start[i] - fabs( tw.sphere.offset[i] ) - tw.sphere.radius;
1246 				tw.bounds[1][i] = tw.end[i] + fabs( tw.sphere.offset[i] ) + tw.sphere.radius;
1247 			} else {
1248 				tw.bounds[0][i] = tw.end[i] - fabs( tw.sphere.offset[i] ) - tw.sphere.radius;
1249 				tw.bounds[1][i] = tw.start[i] + fabs( tw.sphere.offset[i] ) + tw.sphere.radius;
1250 			}
1251 		}
1252 	} else {
1253 		for ( i = 0 ; i < 3 ; i++ ) {
1254 			if ( tw.start[i] < tw.end[i] ) {
1255 				tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
1256 				tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
1257 			} else {
1258 				tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
1259 				tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
1260 			}
1261 		}
1262 	}
1263 
1264 	//
1265 	// check for position test special case
1266 	//
1267 	if ( start[0] == end[0] && start[1] == end[1] && start[2] == end[2] ) {
1268 		if ( model ) {
1269 #ifdef ALWAYS_BBOX_VS_BBOX
1270 			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) {
1271 				tw.sphere.use = qfalse;
1272 				CM_TestInLeaf( &tw, &cmod->leaf );
1273 			} else
1274 #elif defined( ALWAYS_CAPSULE_VS_CAPSULE )
1275 			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) {
1276 				CM_TestCapsuleInCapsule( &tw, model );
1277 			} else
1278 #endif
1279 			if ( model == CAPSULE_MODEL_HANDLE ) {
1280 				if ( tw.sphere.use ) {
1281 					CM_TestCapsuleInCapsule( &tw, model );
1282 				} else {
1283 					CM_TestBoundingBoxInCapsule( &tw, model );
1284 				}
1285 			} else {
1286 				CM_TestInLeaf( &tw, &cmod->leaf );
1287 			}
1288 		} else {
1289 			CM_PositionTest( &tw );
1290 		}
1291 	} else {
1292 		//
1293 		// check for point special case
1294 		//
1295 		if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
1296 			tw.isPoint = qtrue;
1297 			VectorClear( tw.extents );
1298 		} else {
1299 			tw.isPoint = qfalse;
1300 			tw.extents[0] = tw.size[1][0];
1301 			tw.extents[1] = tw.size[1][1];
1302 			tw.extents[2] = tw.size[1][2];
1303 		}
1304 
1305 		//
1306 		// general sweeping through world
1307 		//
1308 		if ( model ) {
1309 #ifdef ALWAYS_BBOX_VS_BBOX
1310 			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) {
1311 				tw.sphere.use = qfalse;
1312 				CM_TraceThroughLeaf( &tw, &cmod->leaf );
1313 			} else
1314 #elif defined( ALWAYS_CAPSULE_VS_CAPSULE )
1315 			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) {
1316 				CM_TraceCapsuleThroughCapsule( &tw, model );
1317 			} else
1318 #endif
1319 			if ( model == CAPSULE_MODEL_HANDLE ) {
1320 				if ( tw.sphere.use ) {
1321 					CM_TraceCapsuleThroughCapsule( &tw, model );
1322 				} else {
1323 					CM_TraceBoundingBoxThroughCapsule( &tw, model );
1324 				}
1325 			} else {
1326 				CM_TraceThroughLeaf( &tw, &cmod->leaf );
1327 			}
1328 		} else {
1329 			CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );
1330 		}
1331 	}
1332 
1333 	// generate endpos from the original, unmodified start/end
1334 	if ( tw.trace.fraction == 1 ) {
1335 		VectorCopy( end, tw.trace.endpos );
1336 	} else {
1337 		for ( i = 0 ; i < 3 ; i++ ) {
1338 			tw.trace.endpos[i] = start[i] + tw.trace.fraction * ( end[i] - start[i] );
1339 		}
1340 	}
1341 
1342 	*results = tw.trace;
1343 }
1344 
1345 /*
1346 ==================
1347 CM_BoxTrace
1348 ==================
1349 */
1350 void CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
1351 				  const vec3_t mins, const vec3_t maxs,
1352 				  clipHandle_t model, int brushmask, int capsule ) {
1353 	CM_Trace( results, start, end, mins, maxs, model, vec3_origin, brushmask, capsule, NULL );
1354 }
1355 
1356 /*
1357 ==================
1358 CM_TransformedBoxTrace
1359 
1360 Handles offseting and rotation of the end points for moving and
1361 rotating entities
1362 ==================
1363 */
1364 void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
1365 							 const vec3_t mins, const vec3_t maxs,
1366 							 clipHandle_t model, int brushmask,
1367 							 const vec3_t origin, const vec3_t angles, int capsule ) {
1368 	trace_t trace;
1369 	vec3_t start_l, end_l;
1370 	qboolean rotated;
1371 	vec3_t offset;
1372 	vec3_t symetricSize[2];
1373 	vec3_t matrix[3], transpose[3];
1374 	int i;
1375 	float halfwidth;
1376 	float halfheight;
1377 	float t;
1378 	sphere_t sphere;
1379 
1380 	if ( !mins ) {
1381 		mins = vec3_origin;
1382 	}
1383 	if ( !maxs ) {
1384 		maxs = vec3_origin;
1385 	}
1386 
1387 	// adjust so that mins and maxs are always symetric, which
1388 	// avoids some complications with plane expanding of rotated
1389 	// bmodels
1390 	for ( i = 0 ; i < 3 ; i++ ) {
1391 		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
1392 		symetricSize[0][i] = mins[i] - offset[i];
1393 		symetricSize[1][i] = maxs[i] - offset[i];
1394 		start_l[i] = start[i] + offset[i];
1395 		end_l[i] = end[i] + offset[i];
1396 	}
1397 
1398 	// subtract origin offset
1399 	VectorSubtract( start_l, origin, start_l );
1400 	VectorSubtract( end_l, origin, end_l );
1401 
1402 	// rotate start and end into the models frame of reference
1403 	if ( model != BOX_MODEL_HANDLE &&
1404 		 ( angles[0] || angles[1] || angles[2] ) ) {
1405 		rotated = qtrue;
1406 	} else {
1407 		rotated = qfalse;
1408 	}
1409 
1410 	halfwidth = symetricSize[ 1 ][ 0 ];
1411 	halfheight = symetricSize[ 1 ][ 2 ];
1412 
1413 	sphere.use = capsule;
1414 	sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
1415 	sphere.halfheight = halfheight;
1416 	t = halfheight - sphere.radius;
1417 
1418 	if ( rotated ) {
1419 		// rotation on trace line (start-end) instead of rotating the bmodel
1420 		// NOTE: This is still incorrect for bounding boxes because the actual bounding
1421 		//		 box that is swept through the model is not rotated. We cannot rotate
1422 		//		 the bounding box or the bmodel because that would make all the brush
1423 		//		 bevels invalid.
1424 		//		 However this is correct for capsules since a capsule itself is rotated too.
1425 		CreateRotationMatrix( angles, matrix );
1426 		// NOTE TTimo gcc doesn't like the vec3_t m[3] to const vec3_t m[3] casting
1427 		RotatePoint( start_l, (const vec3_t *)matrix );
1428 		RotatePoint( end_l, (const vec3_t *)matrix );
1429 		// rotated sphere offset for capsule
1430 		sphere.offset[0] = matrix[0][ 2 ] * t;
1431 		sphere.offset[1] = -matrix[1][ 2 ] * t;
1432 		sphere.offset[2] = matrix[2][ 2 ] * t;
1433 	} else {
1434 		VectorSet( sphere.offset, 0, 0, t );
1435 	}
1436 
1437 	// sweep the box through the model
1438 	CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere );
1439 
1440 	// if the bmodel was rotated and there was a collision
1441 	if ( rotated && trace.fraction != 1.0 ) {
1442 		// rotation of bmodel collision plane
1443 		TransposeMatrix( (const vec3_t *)matrix, transpose );
1444 		RotatePoint( trace.plane.normal, (const vec3_t *)transpose );
1445 	}
1446 
1447 	// re-calculate the end position of the trace because the trace.endpos
1448 	// calculated by CM_Trace could be rotated and have an offset
1449 	trace.endpos[0] = start[0] + trace.fraction * ( end[0] - start[0] );
1450 	trace.endpos[1] = start[1] + trace.fraction * ( end[1] - start[1] );
1451 	trace.endpos[2] = start[2] + trace.fraction * ( end[2] - start[2] );
1452 
1453 	*results = trace;
1454 }
1455