Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cm_patch.c (43759B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #include "cm_local.h"
     24 #include "cm_patch.h"
     25 
     26 /*
     27 
     28 This file does not reference any globals, and has these entry points:
     29 
     30 void CM_ClearLevelPatches( void );
     31 struct patchCollide_s	*CM_GeneratePatchCollide( int width, int height, const vec3_t *points );
     32 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
     33 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc );
     34 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, flaot *points) );
     35 
     36 
     37 WARNING: this may misbehave with meshes that have rows or columns that only
     38 degenerate a few triangles.  Completely degenerate rows and columns are handled
     39 properly.
     40 */
     41 
     42 /*
     43 #define	MAX_FACETS			1024
     44 #define	MAX_PATCH_PLANES	2048
     45 
     46 typedef struct {
     47 	float	plane[4];
     48 	int		signbits;		// signx + (signy<<1) + (signz<<2), used as lookup during collision
     49 } patchPlane_t;
     50 
     51 typedef struct {
     52 	int			surfacePlane;
     53 	int			numBorders;		// 3 or four + 6 axial bevels + 4 or 3 * 4 edge bevels
     54 	int			borderPlanes[4+6+16];
     55 	int			borderInward[4+6+16];
     56 	qboolean	borderNoAdjust[4+6+16];
     57 } facet_t;
     58 
     59 typedef struct patchCollide_s {
     60 	vec3_t	bounds[2];
     61 	int		numPlanes;			// surface planes plus edge planes
     62 	patchPlane_t	*planes;
     63 	int		numFacets;
     64 	facet_t	*facets;
     65 } patchCollide_t;
     66 
     67 
     68 #define	MAX_GRID_SIZE	129
     69 
     70 typedef struct {
     71 	int			width;
     72 	int			height;
     73 	qboolean	wrapWidth;
     74 	qboolean	wrapHeight;
     75 	vec3_t	points[MAX_GRID_SIZE][MAX_GRID_SIZE];	// [width][height]
     76 } cGrid_t;
     77 
     78 #define	SUBDIVIDE_DISTANCE	16	//4	// never more than this units away from curve
     79 #define	PLANE_TRI_EPSILON	0.1
     80 #define	WRAP_POINT_EPSILON	0.1
     81 */
     82 
     83 int	c_totalPatchBlocks;
     84 int	c_totalPatchSurfaces;
     85 int	c_totalPatchEdges;
     86 
     87 static const patchCollide_t	*debugPatchCollide;
     88 static const facet_t		*debugFacet;
     89 static qboolean		debugBlock;
     90 static vec3_t		debugBlockPoints[4];
     91 
     92 /*
     93 =================
     94 CM_ClearLevelPatches
     95 =================
     96 */
     97 void CM_ClearLevelPatches( void ) {
     98 	debugPatchCollide = NULL;
     99 	debugFacet = NULL;
    100 }
    101 
    102 /*
    103 =================
    104 CM_SignbitsForNormal
    105 =================
    106 */
    107 static int CM_SignbitsForNormal( vec3_t normal ) {
    108 	int	bits, j;
    109 
    110 	bits = 0;
    111 	for (j=0 ; j<3 ; j++) {
    112 		if ( normal[j] < 0 ) {
    113 			bits |= 1<<j;
    114 		}
    115 	}
    116 	return bits;
    117 }
    118 
    119 /*
    120 =====================
    121 CM_PlaneFromPoints
    122 
    123 Returns false if the triangle is degenrate.
    124 The normal will point out of the clock for clockwise ordered points
    125 =====================
    126 */
    127 static qboolean CM_PlaneFromPoints( vec4_t plane, vec3_t a, vec3_t b, vec3_t c ) {
    128 	vec3_t	d1, d2;
    129 
    130 	VectorSubtract( b, a, d1 );
    131 	VectorSubtract( c, a, d2 );
    132 	CrossProduct( d2, d1, plane );
    133 	if ( VectorNormalize( plane ) == 0 ) {
    134 		return qfalse;
    135 	}
    136 
    137 	plane[3] = DotProduct( a, plane );
    138 	return qtrue;
    139 }
    140 
    141 
    142 /*
    143 ================================================================================
    144 
    145 GRID SUBDIVISION
    146 
    147 ================================================================================
    148 */
    149 
    150 /*
    151 =================
    152 CM_NeedsSubdivision
    153 
    154 Returns true if the given quadratic curve is not flat enough for our
    155 collision detection purposes
    156 =================
    157 */
    158 static qboolean	CM_NeedsSubdivision( vec3_t a, vec3_t b, vec3_t c ) {
    159 	vec3_t		cmid;
    160 	vec3_t		lmid;
    161 	vec3_t		delta;
    162 	float		dist;
    163 	int			i;
    164 
    165 	// calculate the linear midpoint
    166 	for ( i = 0 ; i < 3 ; i++ ) {
    167 		lmid[i] = 0.5*(a[i] + c[i]);
    168 	}
    169 
    170 	// calculate the exact curve midpoint
    171 	for ( i = 0 ; i < 3 ; i++ ) {
    172 		cmid[i] = 0.5 * ( 0.5*(a[i] + b[i]) + 0.5*(b[i] + c[i]) );
    173 	}
    174 
    175 	// see if the curve is far enough away from the linear mid
    176 	VectorSubtract( cmid, lmid, delta );
    177 	dist = VectorLength( delta );
    178 	
    179 	return dist >= SUBDIVIDE_DISTANCE;
    180 }
    181 
    182 /*
    183 ===============
    184 CM_Subdivide
    185 
    186 a, b, and c are control points.
    187 the subdivided sequence will be: a, out1, out2, out3, c
    188 ===============
    189 */
    190 static void CM_Subdivide( vec3_t a, vec3_t b, vec3_t c, vec3_t out1, vec3_t out2, vec3_t out3 ) {
    191 	int		i;
    192 
    193 	for ( i = 0 ; i < 3 ; i++ ) {
    194 		out1[i] = 0.5 * (a[i] + b[i]);
    195 		out3[i] = 0.5 * (b[i] + c[i]);
    196 		out2[i] = 0.5 * (out1[i] + out3[i]);
    197 	}
    198 }
    199 
    200 /*
    201 =================
    202 CM_TransposeGrid
    203 
    204 Swaps the rows and columns in place
    205 =================
    206 */
    207 static void CM_TransposeGrid( cGrid_t *grid ) {
    208 	int			i, j, l;
    209 	vec3_t		temp;
    210 	qboolean	tempWrap;
    211 
    212 	if ( grid->width > grid->height ) {
    213 		for ( i = 0 ; i < grid->height ; i++ ) {
    214 			for ( j = i + 1 ; j < grid->width ; j++ ) {
    215 				if ( j < grid->height ) {
    216 					// swap the value
    217 					VectorCopy( grid->points[i][j], temp );
    218 					VectorCopy( grid->points[j][i], grid->points[i][j] );
    219 					VectorCopy( temp, grid->points[j][i] );
    220 				} else {
    221 					// just copy
    222 					VectorCopy( grid->points[j][i], grid->points[i][j] );
    223 				}
    224 			}
    225 		}
    226 	} else {
    227 		for ( i = 0 ; i < grid->width ; i++ ) {
    228 			for ( j = i + 1 ; j < grid->height ; j++ ) {
    229 				if ( j < grid->width ) {
    230 					// swap the value
    231 					VectorCopy( grid->points[j][i], temp );
    232 					VectorCopy( grid->points[i][j], grid->points[j][i] );
    233 					VectorCopy( temp, grid->points[i][j] );
    234 				} else {
    235 					// just copy
    236 					VectorCopy( grid->points[i][j], grid->points[j][i] );
    237 				}
    238 			}
    239 		}
    240 	}
    241 
    242 	l = grid->width;
    243 	grid->width = grid->height;
    244 	grid->height = l;
    245 
    246 	tempWrap = grid->wrapWidth;
    247 	grid->wrapWidth = grid->wrapHeight;
    248 	grid->wrapHeight = tempWrap;
    249 }
    250 
    251 /*
    252 ===================
    253 CM_SetGridWrapWidth
    254 
    255 If the left and right columns are exactly equal, set grid->wrapWidth qtrue
    256 ===================
    257 */
    258 static void CM_SetGridWrapWidth( cGrid_t *grid ) {
    259 	int		i, j;
    260 	float	d;
    261 
    262 	for ( i = 0 ; i < grid->height ; i++ ) {
    263 		for ( j = 0 ; j < 3 ; j++ ) {
    264 			d = grid->points[0][i][j] - grid->points[grid->width-1][i][j];
    265 			if ( d < -WRAP_POINT_EPSILON || d > WRAP_POINT_EPSILON ) {
    266 				break;
    267 			}
    268 		}
    269 		if ( j != 3 ) {
    270 			break;
    271 		}
    272 	}
    273 	if ( i == grid->height ) {
    274 		grid->wrapWidth = qtrue;
    275 	} else {
    276 		grid->wrapWidth = qfalse;
    277 	}
    278 }
    279 
    280 /*
    281 =================
    282 CM_SubdivideGridColumns
    283 
    284 Adds columns as necessary to the grid until
    285 all the aproximating points are within SUBDIVIDE_DISTANCE
    286 from the true curve
    287 =================
    288 */
    289 static void CM_SubdivideGridColumns( cGrid_t *grid ) {
    290 	int		i, j, k;
    291 
    292 	for ( i = 0 ; i < grid->width - 2 ;  ) {
    293 		// grid->points[i][x] is an interpolating control point
    294 		// grid->points[i+1][x] is an aproximating control point
    295 		// grid->points[i+2][x] is an interpolating control point
    296 
    297 		//
    298 		// first see if we can collapse the aproximating collumn away
    299 		//
    300 		for ( j = 0 ; j < grid->height ; j++ ) {
    301 			if ( CM_NeedsSubdivision( grid->points[i][j], grid->points[i+1][j], grid->points[i+2][j] ) ) {
    302 				break;
    303 			}
    304 		}
    305 		if ( j == grid->height ) {
    306 			// all of the points were close enough to the linear midpoints
    307 			// that we can collapse the entire column away
    308 			for ( j = 0 ; j < grid->height ; j++ ) {
    309 				// remove the column
    310 				for ( k = i + 2 ; k < grid->width ; k++ ) {
    311 					VectorCopy( grid->points[k][j], grid->points[k-1][j] );
    312 				}
    313 			}
    314 
    315 			grid->width--;
    316 
    317 			// go to the next curve segment
    318 			i++;
    319 			continue;
    320 		}
    321 
    322 		//
    323 		// we need to subdivide the curve
    324 		//
    325 		for ( j = 0 ; j < grid->height ; j++ ) {
    326 			vec3_t	prev, mid, next;
    327 
    328 			// save the control points now
    329 			VectorCopy( grid->points[i][j], prev );
    330 			VectorCopy( grid->points[i+1][j], mid );
    331 			VectorCopy( grid->points[i+2][j], next );
    332 
    333 			// make room for two additional columns in the grid
    334 			// columns i+1 will be replaced, column i+2 will become i+4
    335 			// i+1, i+2, and i+3 will be generated
    336 			for ( k = grid->width - 1 ; k > i + 1 ; k-- ) {
    337 				VectorCopy( grid->points[k][j], grid->points[k+2][j] );
    338 			}
    339 
    340 			// generate the subdivided points
    341 			CM_Subdivide( prev, mid, next, grid->points[i+1][j], grid->points[i+2][j], grid->points[i+3][j] );
    342 		}
    343 
    344 		grid->width += 2;
    345 
    346 		// the new aproximating point at i+1 may need to be removed
    347 		// or subdivided farther, so don't advance i
    348 	}
    349 }
    350 
    351 /*
    352 ======================
    353 CM_ComparePoints
    354 ======================
    355 */
    356 #define	POINT_EPSILON	0.1
    357 static qboolean CM_ComparePoints( float *a, float *b ) {
    358 	float		d;
    359 
    360 	d = a[0] - b[0];
    361 	if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
    362 		return qfalse;
    363 	}
    364 	d = a[1] - b[1];
    365 	if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
    366 		return qfalse;
    367 	}
    368 	d = a[2] - b[2];
    369 	if ( d < -POINT_EPSILON || d > POINT_EPSILON ) {
    370 		return qfalse;
    371 	}
    372 	return qtrue;
    373 }
    374 
    375 /*
    376 =================
    377 CM_RemoveDegenerateColumns
    378 
    379 If there are any identical columns, remove them
    380 =================
    381 */
    382 static void CM_RemoveDegenerateColumns( cGrid_t *grid ) {
    383 	int		i, j, k;
    384 
    385 	for ( i = 0 ; i < grid->width - 1 ; i++ ) {
    386 		for ( j = 0 ; j < grid->height ; j++ ) {
    387 			if ( !CM_ComparePoints( grid->points[i][j], grid->points[i+1][j] ) ) {
    388 				break;
    389 			}
    390 		}
    391 
    392 		if ( j != grid->height ) {
    393 			continue;	// not degenerate
    394 		}
    395 
    396 		for ( j = 0 ; j < grid->height ; j++ ) {
    397 			// remove the column
    398 			for ( k = i + 2 ; k < grid->width ; k++ ) {
    399 				VectorCopy( grid->points[k][j], grid->points[k-1][j] );
    400 			}
    401 		}
    402 		grid->width--;
    403 
    404 		// check against the next column
    405 		i--;
    406 	}
    407 }
    408 
    409 /*
    410 ================================================================================
    411 
    412 PATCH COLLIDE GENERATION
    413 
    414 ================================================================================
    415 */
    416 
    417 static	int				numPlanes;
    418 static	patchPlane_t	planes[MAX_PATCH_PLANES];
    419 
    420 static	int				numFacets;
    421 static	facet_t			facets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ??
    422 
    423 #define	NORMAL_EPSILON	0.0001
    424 #define	DIST_EPSILON	0.02
    425 
    426 /*
    427 ==================
    428 CM_PlaneEqual
    429 ==================
    430 */
    431 int CM_PlaneEqual(patchPlane_t *p, float plane[4], int *flipped) {
    432 	float invplane[4];
    433 
    434 	if (
    435 	   fabs(p->plane[0] - plane[0]) < NORMAL_EPSILON
    436 	&& fabs(p->plane[1] - plane[1]) < NORMAL_EPSILON
    437 	&& fabs(p->plane[2] - plane[2]) < NORMAL_EPSILON
    438 	&& fabs(p->plane[3] - plane[3]) < DIST_EPSILON )
    439 	{
    440 		*flipped = qfalse;
    441 		return qtrue;
    442 	}
    443 
    444 	VectorNegate(plane, invplane);
    445 	invplane[3] = -plane[3];
    446 
    447 	if (
    448 	   fabs(p->plane[0] - invplane[0]) < NORMAL_EPSILON
    449 	&& fabs(p->plane[1] - invplane[1]) < NORMAL_EPSILON
    450 	&& fabs(p->plane[2] - invplane[2]) < NORMAL_EPSILON
    451 	&& fabs(p->plane[3] - invplane[3]) < DIST_EPSILON )
    452 	{
    453 		*flipped = qtrue;
    454 		return qtrue;
    455 	}
    456 
    457 	return qfalse;
    458 }
    459 
    460 /*
    461 ==================
    462 CM_SnapVector
    463 ==================
    464 */
    465 void CM_SnapVector(vec3_t normal) {
    466 	int		i;
    467 
    468 	for (i=0 ; i<3 ; i++)
    469 	{
    470 		if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
    471 		{
    472 			VectorClear (normal);
    473 			normal[i] = 1;
    474 			break;
    475 		}
    476 		if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
    477 		{
    478 			VectorClear (normal);
    479 			normal[i] = -1;
    480 			break;
    481 		}
    482 	}
    483 }
    484 
    485 /*
    486 ==================
    487 CM_FindPlane2
    488 ==================
    489 */
    490 int CM_FindPlane2(float plane[4], int *flipped) {
    491 	int i;
    492 
    493 	// see if the points are close enough to an existing plane
    494 	for ( i = 0 ; i < numPlanes ; i++ ) {
    495 		if (CM_PlaneEqual(&planes[i], plane, flipped)) return i;
    496 	}
    497 
    498 	// add a new plane
    499 	if ( numPlanes == MAX_PATCH_PLANES ) {
    500 		Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
    501 	}
    502 
    503 	Vector4Copy( plane, planes[numPlanes].plane );
    504 	planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
    505 
    506 	numPlanes++;
    507 
    508 	*flipped = qfalse;
    509 
    510 	return numPlanes-1;
    511 }
    512 
    513 /*
    514 ==================
    515 CM_FindPlane
    516 ==================
    517 */
    518 static int CM_FindPlane( float *p1, float *p2, float *p3 ) {
    519 	float	plane[4];
    520 	int		i;
    521 	float	d;
    522 
    523 	if ( !CM_PlaneFromPoints( plane, p1, p2, p3 ) ) {
    524 		return -1;
    525 	}
    526 
    527 	// see if the points are close enough to an existing plane
    528 	for ( i = 0 ; i < numPlanes ; i++ ) {
    529 		if ( DotProduct( plane, planes[i].plane ) < 0 ) {
    530 			continue;	// allow backwards planes?
    531 		}
    532 
    533 		d = DotProduct( p1, planes[i].plane ) - planes[i].plane[3];
    534 		if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
    535 			continue;
    536 		}
    537 
    538 		d = DotProduct( p2, planes[i].plane ) - planes[i].plane[3];
    539 		if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
    540 			continue;
    541 		}
    542 
    543 		d = DotProduct( p3, planes[i].plane ) - planes[i].plane[3];
    544 		if ( d < -PLANE_TRI_EPSILON || d > PLANE_TRI_EPSILON ) {
    545 			continue;
    546 		}
    547 
    548 		// found it
    549 		return i;
    550 	}
    551 
    552 	// add a new plane
    553 	if ( numPlanes == MAX_PATCH_PLANES ) {
    554 		Com_Error( ERR_DROP, "MAX_PATCH_PLANES" );
    555 	}
    556 
    557 	Vector4Copy( plane, planes[numPlanes].plane );
    558 	planes[numPlanes].signbits = CM_SignbitsForNormal( plane );
    559 
    560 	numPlanes++;
    561 
    562 	return numPlanes-1;
    563 }
    564 
    565 /*
    566 ==================
    567 CM_PointOnPlaneSide
    568 ==================
    569 */
    570 static int CM_PointOnPlaneSide( float *p, int planeNum ) {
    571 	float	*plane;
    572 	float	d;
    573 
    574 	if ( planeNum == -1 ) {
    575 		return SIDE_ON;
    576 	}
    577 	plane = planes[ planeNum ].plane;
    578 
    579 	d = DotProduct( p, plane ) - plane[3];
    580 
    581 	if ( d > PLANE_TRI_EPSILON ) {
    582 		return SIDE_FRONT;
    583 	}
    584 
    585 	if ( d < -PLANE_TRI_EPSILON ) {
    586 		return SIDE_BACK;
    587 	}
    588 
    589 	return SIDE_ON;
    590 }
    591 
    592 /*
    593 ==================
    594 CM_GridPlane
    595 ==================
    596 */
    597 static int	CM_GridPlane( int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int tri ) {
    598 	int		p;
    599 
    600 	p = gridPlanes[i][j][tri];
    601 	if ( p != -1 ) {
    602 		return p;
    603 	}
    604 	p = gridPlanes[i][j][!tri];
    605 	if ( p != -1 ) {
    606 		return p;
    607 	}
    608 
    609 	// should never happen
    610 	Com_Printf( "WARNING: CM_GridPlane unresolvable\n" );
    611 	return -1;
    612 }
    613 
    614 /*
    615 ==================
    616 CM_EdgePlaneNum
    617 ==================
    618 */
    619 static int CM_EdgePlaneNum( cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2], int i, int j, int k ) {
    620 	float	*p1, *p2;
    621 	vec3_t		up;
    622 	int			p;
    623 
    624 	switch ( k ) {
    625 	case 0:	// top border
    626 		p1 = grid->points[i][j];
    627 		p2 = grid->points[i+1][j];
    628 		p = CM_GridPlane( gridPlanes, i, j, 0 );
    629 		VectorMA( p1, 4, planes[ p ].plane, up );
    630 		return CM_FindPlane( p1, p2, up );
    631 
    632 	case 2:	// bottom border
    633 		p1 = grid->points[i][j+1];
    634 		p2 = grid->points[i+1][j+1];
    635 		p = CM_GridPlane( gridPlanes, i, j, 1 );
    636 		VectorMA( p1, 4, planes[ p ].plane, up );
    637 		return CM_FindPlane( p2, p1, up );
    638 
    639 	case 3: // left border
    640 		p1 = grid->points[i][j];
    641 		p2 = grid->points[i][j+1];
    642 		p = CM_GridPlane( gridPlanes, i, j, 1 );
    643 		VectorMA( p1, 4, planes[ p ].plane, up );
    644 		return CM_FindPlane( p2, p1, up );
    645 
    646 	case 1:	// right border
    647 		p1 = grid->points[i+1][j];
    648 		p2 = grid->points[i+1][j+1];
    649 		p = CM_GridPlane( gridPlanes, i, j, 0 );
    650 		VectorMA( p1, 4, planes[ p ].plane, up );
    651 		return CM_FindPlane( p1, p2, up );
    652 
    653 	case 4:	// diagonal out of triangle 0
    654 		p1 = grid->points[i+1][j+1];
    655 		p2 = grid->points[i][j];
    656 		p = CM_GridPlane( gridPlanes, i, j, 0 );
    657 		VectorMA( p1, 4, planes[ p ].plane, up );
    658 		return CM_FindPlane( p1, p2, up );
    659 
    660 	case 5:	// diagonal out of triangle 1
    661 		p1 = grid->points[i][j];
    662 		p2 = grid->points[i+1][j+1];
    663 		p = CM_GridPlane( gridPlanes, i, j, 1 );
    664 		VectorMA( p1, 4, planes[ p ].plane, up );
    665 		return CM_FindPlane( p1, p2, up );
    666 
    667 	}
    668 
    669 	Com_Error( ERR_DROP, "CM_EdgePlaneNum: bad k" );
    670 	return -1;
    671 }
    672 
    673 /*
    674 ===================
    675 CM_SetBorderInward
    676 ===================
    677 */
    678 static void CM_SetBorderInward( facet_t *facet, cGrid_t *grid, int gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2],
    679 						  int i, int j, int which ) {
    680 	int		k, l;
    681 	float	*points[4];
    682 	int		numPoints;
    683 
    684 	switch ( which ) {
    685 	case -1:
    686 		points[0] = grid->points[i][j];
    687 		points[1] = grid->points[i+1][j];
    688 		points[2] = grid->points[i+1][j+1];
    689 		points[3] = grid->points[i][j+1];
    690 		numPoints = 4;
    691 		break;
    692 	case 0:
    693 		points[0] = grid->points[i][j];
    694 		points[1] = grid->points[i+1][j];
    695 		points[2] = grid->points[i+1][j+1];
    696 		numPoints = 3;
    697 		break;
    698 	case 1:
    699 		points[0] = grid->points[i+1][j+1];
    700 		points[1] = grid->points[i][j+1];
    701 		points[2] = grid->points[i][j];
    702 		numPoints = 3;
    703 		break;
    704 	default:
    705 		Com_Error( ERR_FATAL, "CM_SetBorderInward: bad parameter" );
    706 		numPoints = 0;
    707 		break;
    708 	}
    709 
    710 	for ( k = 0 ; k < facet->numBorders ; k++ ) {
    711 		int		front, back;
    712 
    713 		front = 0;
    714 		back = 0;
    715 
    716 		for ( l = 0 ; l < numPoints ; l++ ) {
    717 			int		side;
    718 
    719 			side = CM_PointOnPlaneSide( points[l], facet->borderPlanes[k] );
    720 			if ( side == SIDE_FRONT ) {
    721 				front++;
    722 			} if ( side == SIDE_BACK ) {
    723 				back++;
    724 			}
    725 		}
    726 
    727 		if ( front && !back ) {
    728 			facet->borderInward[k] = qtrue;
    729 		} else if ( back && !front ) {
    730 			facet->borderInward[k] = qfalse;
    731 		} else if ( !front && !back ) {
    732 			// flat side border
    733 			facet->borderPlanes[k] = -1;
    734 		} else {
    735 			// bisecting side border
    736 			Com_DPrintf( "WARNING: CM_SetBorderInward: mixed plane sides\n" );
    737 			facet->borderInward[k] = qfalse;
    738 			if ( !debugBlock ) {
    739 				debugBlock = qtrue;
    740 				VectorCopy( grid->points[i][j], debugBlockPoints[0] );
    741 				VectorCopy( grid->points[i+1][j], debugBlockPoints[1] );
    742 				VectorCopy( grid->points[i+1][j+1], debugBlockPoints[2] );
    743 				VectorCopy( grid->points[i][j+1], debugBlockPoints[3] );
    744 			}
    745 		}
    746 	}
    747 }
    748 
    749 /*
    750 ==================
    751 CM_ValidateFacet
    752 
    753 If the facet isn't bounded by its borders, we screwed up.
    754 ==================
    755 */
    756 static qboolean CM_ValidateFacet( facet_t *facet ) {
    757 	float		plane[4];
    758 	int			j;
    759 	winding_t	*w;
    760 	vec3_t		bounds[2];
    761 
    762 	if ( facet->surfacePlane == -1 ) {
    763 		return qfalse;
    764 	}
    765 
    766 	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
    767 	w = BaseWindingForPlane( plane,  plane[3] );
    768 	for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
    769 		if ( facet->borderPlanes[j] == -1 ) {
    770 			return qfalse;
    771 		}
    772 		Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
    773 		if ( !facet->borderInward[j] ) {
    774 			VectorSubtract( vec3_origin, plane, plane );
    775 			plane[3] = -plane[3];
    776 		}
    777 		ChopWindingInPlace( &w, plane, plane[3], 0.1f );
    778 	}
    779 
    780 	if ( !w ) {
    781 		return qfalse;		// winding was completely chopped away
    782 	}
    783 
    784 	// see if the facet is unreasonably large
    785 	WindingBounds( w, bounds[0], bounds[1] );
    786 	FreeWinding( w );
    787 	
    788 	for ( j = 0 ; j < 3 ; j++ ) {
    789 		if ( bounds[1][j] - bounds[0][j] > MAX_MAP_BOUNDS ) {
    790 			return qfalse;		// we must be missing a plane
    791 		}
    792 		if ( bounds[0][j] >= MAX_MAP_BOUNDS ) {
    793 			return qfalse;
    794 		}
    795 		if ( bounds[1][j] <= -MAX_MAP_BOUNDS ) {
    796 			return qfalse;
    797 		}
    798 	}
    799 	return qtrue;		// winding is fine
    800 }
    801 
    802 /*
    803 ==================
    804 CM_AddFacetBevels
    805 ==================
    806 */
    807 void CM_AddFacetBevels( facet_t *facet ) {
    808 
    809 	int i, j, k, l;
    810 	int axis, dir, order, flipped;
    811 	float plane[4], d, newplane[4];
    812 	winding_t *w, *w2;
    813 	vec3_t mins, maxs, vec, vec2;
    814 
    815 	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );
    816 
    817 	w = BaseWindingForPlane( plane,  plane[3] );
    818 	for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
    819 		if (facet->borderPlanes[j] == facet->surfacePlane) continue;
    820 		Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );
    821 
    822 		if ( !facet->borderInward[j] ) {
    823 			VectorSubtract( vec3_origin, plane, plane );
    824 			plane[3] = -plane[3];
    825 		}
    826 
    827 		ChopWindingInPlace( &w, plane, plane[3], 0.1f );
    828 	}
    829 	if ( !w ) {
    830 		return;
    831 	}
    832 
    833 	WindingBounds(w, mins, maxs);
    834 
    835 	// add the axial planes
    836 	order = 0;
    837 	for ( axis = 0 ; axis < 3 ; axis++ )
    838 	{
    839 		for ( dir = -1 ; dir <= 1 ; dir += 2, order++ )
    840 		{
    841 			VectorClear(plane);
    842 			plane[axis] = dir;
    843 			if (dir == 1) {
    844 				plane[3] = maxs[axis];
    845 			}
    846 			else {
    847 				plane[3] = -mins[axis];
    848 			}
    849 			//if it's the surface plane
    850 			if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
    851 				continue;
    852 			}
    853 			// see if the plane is allready present
    854 			for ( i = 0 ; i < facet->numBorders ; i++ ) {
    855 				if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped))
    856 					break;
    857 			}
    858 
    859 			if ( i == facet->numBorders ) {
    860 				if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
    861 				facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
    862 				facet->borderNoAdjust[facet->numBorders] = 0;
    863 				facet->borderInward[facet->numBorders] = flipped;
    864 				facet->numBorders++;
    865 			}
    866 		}
    867 	}
    868 	//
    869 	// add the edge bevels
    870 	//
    871 	// test the non-axial plane edges
    872 	for ( j = 0 ; j < w->numpoints ; j++ )
    873 	{
    874 		k = (j+1)%w->numpoints;
    875 		VectorSubtract (w->p[j], w->p[k], vec);
    876 		//if it's a degenerate edge
    877 		if (VectorNormalize (vec) < 0.5)
    878 			continue;
    879 		CM_SnapVector(vec);
    880 		for ( k = 0; k < 3 ; k++ )
    881 			if ( vec[k] == -1 || vec[k] == 1 )
    882 				break;	// axial
    883 		if ( k < 3 )
    884 			continue;	// only test non-axial edges
    885 
    886 		// try the six possible slanted axials from this edge
    887 		for ( axis = 0 ; axis < 3 ; axis++ )
    888 		{
    889 			for ( dir = -1 ; dir <= 1 ; dir += 2 )
    890 			{
    891 				// construct a plane
    892 				VectorClear (vec2);
    893 				vec2[axis] = dir;
    894 				CrossProduct (vec, vec2, plane);
    895 				if (VectorNormalize (plane) < 0.5)
    896 					continue;
    897 				plane[3] = DotProduct (w->p[j], plane);
    898 
    899 				// if all the points of the facet winding are
    900 				// behind this plane, it is a proper edge bevel
    901 				for ( l = 0 ; l < w->numpoints ; l++ )
    902 				{
    903 					d = DotProduct (w->p[l], plane) - plane[3];
    904 					if (d > 0.1)
    905 						break;	// point in front
    906 				}
    907 				if ( l < w->numpoints )
    908 					continue;
    909 
    910 				//if it's the surface plane
    911 				if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) {
    912 					continue;
    913 				}
    914 				// see if the plane is allready present
    915 				for ( i = 0 ; i < facet->numBorders ; i++ ) {
    916 					if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) {
    917 							break;
    918 					}
    919 				}
    920 
    921 				if ( i == facet->numBorders ) {
    922 					if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
    923 					facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
    924 
    925 					for ( k = 0 ; k < facet->numBorders ; k++ ) {
    926 						if (facet->borderPlanes[facet->numBorders] ==
    927 							facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n");
    928 					}
    929 
    930 					facet->borderNoAdjust[facet->numBorders] = 0;
    931 					facet->borderInward[facet->numBorders] = flipped;
    932 					//
    933 					w2 = CopyWinding(w);
    934 					Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane);
    935 					if (!facet->borderInward[facet->numBorders])
    936 					{
    937 						VectorNegate(newplane, newplane);
    938 						newplane[3] = -newplane[3];
    939 					} //end if
    940 					ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
    941 					if (!w2) {
    942 						Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
    943 						continue;
    944 					}
    945 					else {
    946 						FreeWinding(w2);
    947 					}
    948 					//
    949 					facet->numBorders++;
    950 					//already got a bevel
    951 //					break;
    952 				}
    953 			}
    954 		}
    955 	}
    956 	FreeWinding( w );
    957 
    958 #ifndef BSPC
    959 	//add opposite plane
    960 	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
    961 	facet->borderNoAdjust[facet->numBorders] = 0;
    962 	facet->borderInward[facet->numBorders] = qtrue;
    963 	facet->numBorders++;
    964 #endif //BSPC
    965 
    966 }
    967 
    968 typedef enum {
    969 	EN_TOP,
    970 	EN_RIGHT,
    971 	EN_BOTTOM,
    972 	EN_LEFT
    973 } edgeName_t;
    974 
    975 /*
    976 ==================
    977 CM_PatchCollideFromGrid
    978 ==================
    979 */
    980 static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) {
    981 	int				i, j;
    982 	float			*p1, *p2, *p3;
    983 	MAC_STATIC int				gridPlanes[MAX_GRID_SIZE][MAX_GRID_SIZE][2];
    984 	facet_t			*facet;
    985 	int				borders[4];
    986 	int				noAdjust[4];
    987 
    988 	numPlanes = 0;
    989 	numFacets = 0;
    990 
    991 	// find the planes for each triangle of the grid
    992 	for ( i = 0 ; i < grid->width - 1 ; i++ ) {
    993 		for ( j = 0 ; j < grid->height - 1 ; j++ ) {
    994 			p1 = grid->points[i][j];
    995 			p2 = grid->points[i+1][j];
    996 			p3 = grid->points[i+1][j+1];
    997 			gridPlanes[i][j][0] = CM_FindPlane( p1, p2, p3 );
    998 
    999 			p1 = grid->points[i+1][j+1];
   1000 			p2 = grid->points[i][j+1];
   1001 			p3 = grid->points[i][j];
   1002 			gridPlanes[i][j][1] = CM_FindPlane( p1, p2, p3 );
   1003 		}
   1004 	}
   1005 
   1006 	// create the borders for each facet
   1007 	for ( i = 0 ; i < grid->width - 1 ; i++ ) {
   1008 		for ( j = 0 ; j < grid->height - 1 ; j++ ) {
   1009 			 
   1010 			borders[EN_TOP] = -1;
   1011 			if ( j > 0 ) {
   1012 				borders[EN_TOP] = gridPlanes[i][j-1][1];
   1013 			} else if ( grid->wrapHeight ) {
   1014 				borders[EN_TOP] = gridPlanes[i][grid->height-2][1];
   1015 			} 
   1016 			noAdjust[EN_TOP] = ( borders[EN_TOP] == gridPlanes[i][j][0] );
   1017 			if ( borders[EN_TOP] == -1 || noAdjust[EN_TOP] ) {
   1018 				borders[EN_TOP] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 0 );
   1019 			}
   1020 
   1021 			borders[EN_BOTTOM] = -1;
   1022 			if ( j < grid->height - 2 ) {
   1023 				borders[EN_BOTTOM] = gridPlanes[i][j+1][0];
   1024 			} else if ( grid->wrapHeight ) {
   1025 				borders[EN_BOTTOM] = gridPlanes[i][0][0];
   1026 			}
   1027 			noAdjust[EN_BOTTOM] = ( borders[EN_BOTTOM] == gridPlanes[i][j][1] );
   1028 			if ( borders[EN_BOTTOM] == -1 || noAdjust[EN_BOTTOM] ) {
   1029 				borders[EN_BOTTOM] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 2 );
   1030 			}
   1031 
   1032 			borders[EN_LEFT] = -1;
   1033 			if ( i > 0 ) {
   1034 				borders[EN_LEFT] = gridPlanes[i-1][j][0];
   1035 			} else if ( grid->wrapWidth ) {
   1036 				borders[EN_LEFT] = gridPlanes[grid->width-2][j][0];
   1037 			}
   1038 			noAdjust[EN_LEFT] = ( borders[EN_LEFT] == gridPlanes[i][j][1] );
   1039 			if ( borders[EN_LEFT] == -1 || noAdjust[EN_LEFT] ) {
   1040 				borders[EN_LEFT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 3 );
   1041 			}
   1042 
   1043 			borders[EN_RIGHT] = -1;
   1044 			if ( i < grid->width - 2 ) {
   1045 				borders[EN_RIGHT] = gridPlanes[i+1][j][1];
   1046 			} else if ( grid->wrapWidth ) {
   1047 				borders[EN_RIGHT] = gridPlanes[0][j][1];
   1048 			}
   1049 			noAdjust[EN_RIGHT] = ( borders[EN_RIGHT] == gridPlanes[i][j][0] );
   1050 			if ( borders[EN_RIGHT] == -1 || noAdjust[EN_RIGHT] ) {
   1051 				borders[EN_RIGHT] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 1 );
   1052 			}
   1053 
   1054 			if ( numFacets == MAX_FACETS ) {
   1055 				Com_Error( ERR_DROP, "MAX_FACETS" );
   1056 			}
   1057 			facet = &facets[numFacets];
   1058 			Com_Memset( facet, 0, sizeof( *facet ) );
   1059 
   1060 			if ( gridPlanes[i][j][0] == gridPlanes[i][j][1] ) {
   1061 				if ( gridPlanes[i][j][0] == -1 ) {
   1062 					continue;		// degenrate
   1063 				}
   1064 				facet->surfacePlane = gridPlanes[i][j][0];
   1065 				facet->numBorders = 4;
   1066 				facet->borderPlanes[0] = borders[EN_TOP];
   1067 				facet->borderNoAdjust[0] = noAdjust[EN_TOP];
   1068 				facet->borderPlanes[1] = borders[EN_RIGHT];
   1069 				facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
   1070 				facet->borderPlanes[2] = borders[EN_BOTTOM];
   1071 				facet->borderNoAdjust[2] = noAdjust[EN_BOTTOM];
   1072 				facet->borderPlanes[3] = borders[EN_LEFT];
   1073 				facet->borderNoAdjust[3] = noAdjust[EN_LEFT];
   1074 				CM_SetBorderInward( facet, grid, gridPlanes, i, j, -1 );
   1075 				if ( CM_ValidateFacet( facet ) ) {
   1076 					CM_AddFacetBevels( facet );
   1077 					numFacets++;
   1078 				}
   1079 			} else {
   1080 				// two seperate triangles
   1081 				facet->surfacePlane = gridPlanes[i][j][0];
   1082 				facet->numBorders = 3;
   1083 				facet->borderPlanes[0] = borders[EN_TOP];
   1084 				facet->borderNoAdjust[0] = noAdjust[EN_TOP];
   1085 				facet->borderPlanes[1] = borders[EN_RIGHT];
   1086 				facet->borderNoAdjust[1] = noAdjust[EN_RIGHT];
   1087 				facet->borderPlanes[2] = gridPlanes[i][j][1];
   1088 				if ( facet->borderPlanes[2] == -1 ) {
   1089 					facet->borderPlanes[2] = borders[EN_BOTTOM];
   1090 					if ( facet->borderPlanes[2] == -1 ) {
   1091 						facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 4 );
   1092 					}
   1093 				}
   1094  				CM_SetBorderInward( facet, grid, gridPlanes, i, j, 0 );
   1095 				if ( CM_ValidateFacet( facet ) ) {
   1096 					CM_AddFacetBevels( facet );
   1097 					numFacets++;
   1098 				}
   1099 
   1100 				if ( numFacets == MAX_FACETS ) {
   1101 					Com_Error( ERR_DROP, "MAX_FACETS" );
   1102 				}
   1103 				facet = &facets[numFacets];
   1104 				Com_Memset( facet, 0, sizeof( *facet ) );
   1105 
   1106 				facet->surfacePlane = gridPlanes[i][j][1];
   1107 				facet->numBorders = 3;
   1108 				facet->borderPlanes[0] = borders[EN_BOTTOM];
   1109 				facet->borderNoAdjust[0] = noAdjust[EN_BOTTOM];
   1110 				facet->borderPlanes[1] = borders[EN_LEFT];
   1111 				facet->borderNoAdjust[1] = noAdjust[EN_LEFT];
   1112 				facet->borderPlanes[2] = gridPlanes[i][j][0];
   1113 				if ( facet->borderPlanes[2] == -1 ) {
   1114 					facet->borderPlanes[2] = borders[EN_TOP];
   1115 					if ( facet->borderPlanes[2] == -1 ) {
   1116 						facet->borderPlanes[2] = CM_EdgePlaneNum( grid, gridPlanes, i, j, 5 );
   1117 					}
   1118 				}
   1119 				CM_SetBorderInward( facet, grid, gridPlanes, i, j, 1 );
   1120 				if ( CM_ValidateFacet( facet ) ) {
   1121 					CM_AddFacetBevels( facet );
   1122 					numFacets++;
   1123 				}
   1124 			}
   1125 		}
   1126 	}
   1127 
   1128 	// copy the results out
   1129 	pf->numPlanes = numPlanes;
   1130 	pf->numFacets = numFacets;
   1131 	pf->facets = Hunk_Alloc( numFacets * sizeof( *pf->facets ), h_high );
   1132 	Com_Memcpy( pf->facets, facets, numFacets * sizeof( *pf->facets ) );
   1133 	pf->planes = Hunk_Alloc( numPlanes * sizeof( *pf->planes ), h_high );
   1134 	Com_Memcpy( pf->planes, planes, numPlanes * sizeof( *pf->planes ) );
   1135 }
   1136 
   1137 
   1138 /*
   1139 ===================
   1140 CM_GeneratePatchCollide
   1141 
   1142 Creates an internal structure that will be used to perform
   1143 collision detection with a patch mesh.
   1144 
   1145 Points is packed as concatenated rows.
   1146 ===================
   1147 */
   1148 struct patchCollide_s	*CM_GeneratePatchCollide( int width, int height, vec3_t *points ) {
   1149 	patchCollide_t	*pf;
   1150 	MAC_STATIC cGrid_t			grid;
   1151 	int				i, j;
   1152 
   1153 	if ( width <= 2 || height <= 2 || !points ) {
   1154 		Com_Error( ERR_DROP, "CM_GeneratePatchFacets: bad parameters: (%i, %i, %p)",
   1155 			width, height, points );
   1156 	}
   1157 
   1158 	if ( !(width & 1) || !(height & 1) ) {
   1159 		Com_Error( ERR_DROP, "CM_GeneratePatchFacets: even sizes are invalid for quadratic meshes" );
   1160 	}
   1161 
   1162 	if ( width > MAX_GRID_SIZE || height > MAX_GRID_SIZE ) {
   1163 		Com_Error( ERR_DROP, "CM_GeneratePatchFacets: source is > MAX_GRID_SIZE" );
   1164 	}
   1165 
   1166 	// build a grid
   1167 	grid.width = width;
   1168 	grid.height = height;
   1169 	grid.wrapWidth = qfalse;
   1170 	grid.wrapHeight = qfalse;
   1171 	for ( i = 0 ; i < width ; i++ ) {
   1172 		for ( j = 0 ; j < height ; j++ ) {
   1173 			VectorCopy( points[j*width + i], grid.points[i][j] );
   1174 		}
   1175 	}
   1176 
   1177 	// subdivide the grid
   1178 	CM_SetGridWrapWidth( &grid );
   1179 	CM_SubdivideGridColumns( &grid );
   1180 	CM_RemoveDegenerateColumns( &grid );
   1181 
   1182 	CM_TransposeGrid( &grid );
   1183 
   1184 	CM_SetGridWrapWidth( &grid );
   1185 	CM_SubdivideGridColumns( &grid );
   1186 	CM_RemoveDegenerateColumns( &grid );
   1187 
   1188 	// we now have a grid of points exactly on the curve
   1189 	// the aproximate surface defined by these points will be
   1190 	// collided against
   1191 	pf = Hunk_Alloc( sizeof( *pf ), h_high );
   1192 	ClearBounds( pf->bounds[0], pf->bounds[1] );
   1193 	for ( i = 0 ; i < grid.width ; i++ ) {
   1194 		for ( j = 0 ; j < grid.height ; j++ ) {
   1195 			AddPointToBounds( grid.points[i][j], pf->bounds[0], pf->bounds[1] );
   1196 		}
   1197 	}
   1198 
   1199 	c_totalPatchBlocks += ( grid.width - 1 ) * ( grid.height - 1 );
   1200 
   1201 	// generate a bsp tree for the surface
   1202 	CM_PatchCollideFromGrid( &grid, pf );
   1203 
   1204 	// expand by one unit for epsilon purposes
   1205 	pf->bounds[0][0] -= 1;
   1206 	pf->bounds[0][1] -= 1;
   1207 	pf->bounds[0][2] -= 1;
   1208 
   1209 	pf->bounds[1][0] += 1;
   1210 	pf->bounds[1][1] += 1;
   1211 	pf->bounds[1][2] += 1;
   1212 
   1213 	return pf;
   1214 }
   1215 
   1216 /*
   1217 ================================================================================
   1218 
   1219 TRACE TESTING
   1220 
   1221 ================================================================================
   1222 */
   1223 
   1224 /*
   1225 ====================
   1226 CM_TracePointThroughPatchCollide
   1227 
   1228   special case for point traces because the patch collide "brushes" have no volume
   1229 ====================
   1230 */
   1231 void CM_TracePointThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
   1232 	qboolean	frontFacing[MAX_PATCH_PLANES];
   1233 	float		intersection[MAX_PATCH_PLANES];
   1234 	float		intersect;
   1235 	const patchPlane_t	*planes;
   1236 	const facet_t	*facet;
   1237 	int			i, j, k;
   1238 	float		offset;
   1239 	float		d1, d2;
   1240 #ifndef BSPC
   1241 	static cvar_t *cv;
   1242 #endif //BSPC
   1243 
   1244 #ifndef BSPC
   1245 	if ( !cm_playerCurveClip->integer || !tw->isPoint ) {
   1246 		return;
   1247 	}
   1248 #endif
   1249 
   1250 	// determine the trace's relationship to all planes
   1251 	planes = pc->planes;
   1252 	for ( i = 0 ; i < pc->numPlanes ; i++, planes++ ) {
   1253 		offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
   1254 		d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
   1255 		d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
   1256 		if ( d1 <= 0 ) {
   1257 			frontFacing[i] = qfalse;
   1258 		} else {
   1259 			frontFacing[i] = qtrue;
   1260 		}
   1261 		if ( d1 == d2 ) {
   1262 			intersection[i] = 99999;
   1263 		} else {
   1264 			intersection[i] = d1 / ( d1 - d2 );
   1265 			if ( intersection[i] <= 0 ) {
   1266 				intersection[i] = 99999;
   1267 			}
   1268 		}
   1269 	}
   1270 
   1271 
   1272 	// see if any of the surface planes are intersected
   1273 	facet = pc->facets;
   1274 	for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
   1275 		if ( !frontFacing[facet->surfacePlane] ) {
   1276 			continue;
   1277 		}
   1278 		intersect = intersection[facet->surfacePlane];
   1279 		if ( intersect < 0 ) {
   1280 			continue;		// surface is behind the starting point
   1281 		}
   1282 		if ( intersect > tw->trace.fraction ) {
   1283 			continue;		// already hit something closer
   1284 		}
   1285 		for ( j = 0 ; j < facet->numBorders ; j++ ) {
   1286 			k = facet->borderPlanes[j];
   1287 			if ( frontFacing[k] ^ facet->borderInward[j] ) {
   1288 				if ( intersection[k] > intersect ) {
   1289 					break;
   1290 				}
   1291 			} else {
   1292 				if ( intersection[k] < intersect ) {
   1293 					break;
   1294 				}
   1295 			}
   1296 		}
   1297 		if ( j == facet->numBorders ) {
   1298 			// we hit this facet
   1299 #ifndef BSPC
   1300 			if (!cv) {
   1301 				cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
   1302 			}
   1303 			if (cv->integer) {
   1304 				debugPatchCollide = pc;
   1305 				debugFacet = facet;
   1306 			}
   1307 #endif //BSPC
   1308 			planes = &pc->planes[facet->surfacePlane];
   1309 
   1310 			// calculate intersection with a slight pushoff
   1311 			offset = DotProduct( tw->offsets[ planes->signbits ], planes->plane );
   1312 			d1 = DotProduct( tw->start, planes->plane ) - planes->plane[3] + offset;
   1313 			d2 = DotProduct( tw->end, planes->plane ) - planes->plane[3] + offset;
   1314 			tw->trace.fraction = ( d1 - SURFACE_CLIP_EPSILON ) / ( d1 - d2 );
   1315 
   1316 			if ( tw->trace.fraction < 0 ) {
   1317 				tw->trace.fraction = 0;
   1318 			}
   1319 
   1320 			VectorCopy( planes->plane,  tw->trace.plane.normal );
   1321 			tw->trace.plane.dist = planes->plane[3];
   1322 		}
   1323 	}
   1324 }
   1325 
   1326 /*
   1327 ====================
   1328 CM_CheckFacetPlane
   1329 ====================
   1330 */
   1331 int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, float *leaveFrac, int *hit) {
   1332 	float d1, d2, f;
   1333 
   1334 	*hit = qfalse;
   1335 
   1336 	d1 = DotProduct( start, plane ) - plane[3];
   1337 	d2 = DotProduct( end, plane ) - plane[3];
   1338 
   1339 	// if completely in front of face, no intersection with the entire facet
   1340 	if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 )  ) {
   1341 		return qfalse;
   1342 	}
   1343 
   1344 	// if it doesn't cross the plane, the plane isn't relevent
   1345 	if (d1 <= 0 && d2 <= 0 ) {
   1346 		return qtrue;
   1347 	}
   1348 
   1349 	// crosses face
   1350 	if (d1 > d2) {	// enter
   1351 		f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
   1352 		if ( f < 0 ) {
   1353 			f = 0;
   1354 		}
   1355 		//always favor previous plane hits and thus also the surface plane hit
   1356 		if (f > *enterFrac) {
   1357 			*enterFrac = f;
   1358 			*hit = qtrue;
   1359 		}
   1360 	} else {	// leave
   1361 		f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
   1362 		if ( f > 1 ) {
   1363 			f = 1;
   1364 		}
   1365 		if (f < *leaveFrac) {
   1366 			*leaveFrac = f;
   1367 		}
   1368 	}
   1369 	return qtrue;
   1370 }
   1371 
   1372 /*
   1373 ====================
   1374 CM_TraceThroughPatchCollide
   1375 ====================
   1376 */
   1377 void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
   1378 	int i, j, hit, hitnum;
   1379 	float offset, enterFrac, leaveFrac, t;
   1380 	patchPlane_t *planes;
   1381 	facet_t	*facet;
   1382 	float plane[4], bestplane[4];
   1383 	vec3_t startp, endp;
   1384 #ifndef BSPC
   1385 	static cvar_t *cv;
   1386 #endif //BSPC
   1387 
   1388 	if (tw->isPoint) {
   1389 		CM_TracePointThroughPatchCollide( tw, pc );
   1390 		return;
   1391 	}
   1392 
   1393 	facet = pc->facets;
   1394 	for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
   1395 		enterFrac = -1.0;
   1396 		leaveFrac = 1.0;
   1397 		hitnum = -1;
   1398 		//
   1399 		planes = &pc->planes[ facet->surfacePlane ];
   1400 		VectorCopy(planes->plane, plane);
   1401 		plane[3] = planes->plane[3];
   1402 		if ( tw->sphere.use ) {
   1403 			// adjust the plane distance apropriately for radius
   1404 			plane[3] += tw->sphere.radius;
   1405 
   1406 			// find the closest point on the capsule to the plane
   1407 			t = DotProduct( plane, tw->sphere.offset );
   1408 			if ( t > 0.0f ) {
   1409 				VectorSubtract( tw->start, tw->sphere.offset, startp );
   1410 				VectorSubtract( tw->end, tw->sphere.offset, endp );
   1411 			}
   1412 			else {
   1413 				VectorAdd( tw->start, tw->sphere.offset, startp );
   1414 				VectorAdd( tw->end, tw->sphere.offset, endp );
   1415 			}
   1416 		}
   1417 		else {
   1418 			offset = DotProduct( tw->offsets[ planes->signbits ], plane);
   1419 			plane[3] -= offset;
   1420 			VectorCopy( tw->start, startp );
   1421 			VectorCopy( tw->end, endp );
   1422 		}
   1423 
   1424 		if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
   1425 			continue;
   1426 		}
   1427 		if (hit) {
   1428 			Vector4Copy(plane, bestplane);
   1429 		}
   1430 
   1431 		for ( j = 0; j < facet->numBorders; j++ ) {
   1432 			planes = &pc->planes[ facet->borderPlanes[j] ];
   1433 			if (facet->borderInward[j]) {
   1434 				VectorNegate(planes->plane, plane);
   1435 				plane[3] = -planes->plane[3];
   1436 			}
   1437 			else {
   1438 				VectorCopy(planes->plane, plane);
   1439 				plane[3] = planes->plane[3];
   1440 			}
   1441 			if ( tw->sphere.use ) {
   1442 				// adjust the plane distance apropriately for radius
   1443 				plane[3] += tw->sphere.radius;
   1444 
   1445 				// find the closest point on the capsule to the plane
   1446 				t = DotProduct( plane, tw->sphere.offset );
   1447 				if ( t > 0.0f ) {
   1448 					VectorSubtract( tw->start, tw->sphere.offset, startp );
   1449 					VectorSubtract( tw->end, tw->sphere.offset, endp );
   1450 				}
   1451 				else {
   1452 					VectorAdd( tw->start, tw->sphere.offset, startp );
   1453 					VectorAdd( tw->end, tw->sphere.offset, endp );
   1454 				}
   1455 			}
   1456 			else {
   1457 				// NOTE: this works even though the plane might be flipped because the bbox is centered
   1458 				offset = DotProduct( tw->offsets[ planes->signbits ], plane);
   1459 				plane[3] += fabs(offset);
   1460 				VectorCopy( tw->start, startp );
   1461 				VectorCopy( tw->end, endp );
   1462 			}
   1463 
   1464 			if (!CM_CheckFacetPlane(plane, startp, endp, &enterFrac, &leaveFrac, &hit)) {
   1465 				break;
   1466 			}
   1467 			if (hit) {
   1468 				hitnum = j;
   1469 				Vector4Copy(plane, bestplane);
   1470 			}
   1471 		}
   1472 		if (j < facet->numBorders) continue;
   1473 		//never clip against the back side
   1474 		if (hitnum == facet->numBorders - 1) continue;
   1475 
   1476 		if (enterFrac < leaveFrac && enterFrac >= 0) {
   1477 			if (enterFrac < tw->trace.fraction) {
   1478 				if (enterFrac < 0) {
   1479 					enterFrac = 0;
   1480 				}
   1481 #ifndef BSPC
   1482 				if (!cv) {
   1483 					cv = Cvar_Get( "r_debugSurfaceUpdate", "1", 0 );
   1484 				}
   1485 				if (cv && cv->integer) {
   1486 					debugPatchCollide = pc;
   1487 					debugFacet = facet;
   1488 				}
   1489 #endif //BSPC
   1490 
   1491 				tw->trace.fraction = enterFrac;
   1492 				VectorCopy( bestplane, tw->trace.plane.normal );
   1493 				tw->trace.plane.dist = bestplane[3];
   1494 			}
   1495 		}
   1496 	}
   1497 }
   1498 
   1499 
   1500 /*
   1501 =======================================================================
   1502 
   1503 POSITION TEST
   1504 
   1505 =======================================================================
   1506 */
   1507 
   1508 /*
   1509 ====================
   1510 CM_PositionTestInPatchCollide
   1511 ====================
   1512 */
   1513 qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ) {
   1514 	int i, j;
   1515 	float offset, t;
   1516 	patchPlane_t *planes;
   1517 	facet_t	*facet;
   1518 	float plane[4];
   1519 	vec3_t startp;
   1520 
   1521 	if (tw->isPoint) {
   1522 		return qfalse;
   1523 	}
   1524 	//
   1525 	facet = pc->facets;
   1526 	for ( i = 0 ; i < pc->numFacets ; i++, facet++ ) {
   1527 		planes = &pc->planes[ facet->surfacePlane ];
   1528 		VectorCopy(planes->plane, plane);
   1529 		plane[3] = planes->plane[3];
   1530 		if ( tw->sphere.use ) {
   1531 			// adjust the plane distance apropriately for radius
   1532 			plane[3] += tw->sphere.radius;
   1533 
   1534 			// find the closest point on the capsule to the plane
   1535 			t = DotProduct( plane, tw->sphere.offset );
   1536 			if ( t > 0 ) {
   1537 				VectorSubtract( tw->start, tw->sphere.offset, startp );
   1538 			}
   1539 			else {
   1540 				VectorAdd( tw->start, tw->sphere.offset, startp );
   1541 			}
   1542 		}
   1543 		else {
   1544 			offset = DotProduct( tw->offsets[ planes->signbits ], plane);
   1545 			plane[3] -= offset;
   1546 			VectorCopy( tw->start, startp );
   1547 		}
   1548 
   1549 		if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
   1550 			continue;
   1551 		}
   1552 
   1553 		for ( j = 0; j < facet->numBorders; j++ ) {
   1554 			planes = &pc->planes[ facet->borderPlanes[j] ];
   1555 			if (facet->borderInward[j]) {
   1556 				VectorNegate(planes->plane, plane);
   1557 				plane[3] = -planes->plane[3];
   1558 			}
   1559 			else {
   1560 				VectorCopy(planes->plane, plane);
   1561 				plane[3] = planes->plane[3];
   1562 			}
   1563 			if ( tw->sphere.use ) {
   1564 				// adjust the plane distance apropriately for radius
   1565 				plane[3] += tw->sphere.radius;
   1566 
   1567 				// find the closest point on the capsule to the plane
   1568 				t = DotProduct( plane, tw->sphere.offset );
   1569 				if ( t > 0.0f ) {
   1570 					VectorSubtract( tw->start, tw->sphere.offset, startp );
   1571 				}
   1572 				else {
   1573 					VectorAdd( tw->start, tw->sphere.offset, startp );
   1574 				}
   1575 			}
   1576 			else {
   1577 				// NOTE: this works even though the plane might be flipped because the bbox is centered
   1578 				offset = DotProduct( tw->offsets[ planes->signbits ], plane);
   1579 				plane[3] += fabs(offset);
   1580 				VectorCopy( tw->start, startp );
   1581 			}
   1582 
   1583 			if ( DotProduct( plane, startp ) - plane[3] > 0.0f ) {
   1584 				break;
   1585 			}
   1586 		}
   1587 		if (j < facet->numBorders) {
   1588 			continue;
   1589 		}
   1590 		// inside this patch facet
   1591 		return qtrue;
   1592 	}
   1593 	return qfalse;
   1594 }
   1595 
   1596 /*
   1597 =======================================================================
   1598 
   1599 DEBUGGING
   1600 
   1601 =======================================================================
   1602 */
   1603 
   1604 
   1605 /*
   1606 ==================
   1607 CM_DrawDebugSurface
   1608 
   1609 Called from the renderer
   1610 ==================
   1611 */
   1612 #ifndef BSPC
   1613 void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value);
   1614 #endif
   1615 
   1616 void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) {
   1617 	static cvar_t	*cv;
   1618 #ifndef BSPC
   1619 	static cvar_t	*cv2;
   1620 #endif
   1621 	const patchCollide_t	*pc;
   1622 	facet_t			*facet;
   1623 	winding_t		*w;
   1624 	int				i, j, k, n;
   1625 	int				curplanenum, planenum, curinward, inward;
   1626 	float			plane[4];
   1627 	vec3_t mins = {-15, -15, -28}, maxs = {15, 15, 28};
   1628 	//vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0};
   1629 	vec3_t v1, v2;
   1630 
   1631 #ifndef BSPC
   1632 	if ( !cv2 )
   1633 	{
   1634 		cv2 = Cvar_Get( "r_debugSurface", "0", 0 );
   1635 	}
   1636 
   1637 	if (cv2->integer != 1)
   1638 	{
   1639 		BotDrawDebugPolygons(drawPoly, cv2->integer);
   1640 		return;
   1641 	}
   1642 #endif
   1643 
   1644 	if ( !debugPatchCollide ) {
   1645 		return;
   1646 	}
   1647 
   1648 #ifndef BSPC
   1649 	if ( !cv ) {
   1650 		cv = Cvar_Get( "cm_debugSize", "2", 0 );
   1651 	}
   1652 #endif
   1653 	pc = debugPatchCollide;
   1654 
   1655 	for ( i = 0, facet = pc->facets ; i < pc->numFacets ; i++, facet++ ) {
   1656 
   1657 		for ( k = 0 ; k < facet->numBorders + 1; k++ ) {
   1658 			//
   1659 			if (k < facet->numBorders) {
   1660 				planenum = facet->borderPlanes[k];
   1661 				inward = facet->borderInward[k];
   1662 			}
   1663 			else {
   1664 				planenum = facet->surfacePlane;
   1665 				inward = qfalse;
   1666 				//continue;
   1667 			}
   1668 
   1669 			Vector4Copy( pc->planes[ planenum ].plane, plane );
   1670 
   1671 			//planenum = facet->surfacePlane;
   1672 			if ( inward ) {
   1673 				VectorSubtract( vec3_origin, plane, plane );
   1674 				plane[3] = -plane[3];
   1675 			}
   1676 
   1677 			plane[3] += cv->value;
   1678 			//*
   1679 			for (n = 0; n < 3; n++)
   1680 			{
   1681 				if (plane[n] > 0) v1[n] = maxs[n];
   1682 				else v1[n] = mins[n];
   1683 			} //end for
   1684 			VectorNegate(plane, v2);
   1685 			plane[3] += fabs(DotProduct(v1, v2));
   1686 			//*/
   1687 
   1688 			w = BaseWindingForPlane( plane,  plane[3] );
   1689 			for ( j = 0 ; j < facet->numBorders + 1 && w; j++ ) {
   1690 				//
   1691 				if (j < facet->numBorders) {
   1692 					curplanenum = facet->borderPlanes[j];
   1693 					curinward = facet->borderInward[j];
   1694 				}
   1695 				else {
   1696 					curplanenum = facet->surfacePlane;
   1697 					curinward = qfalse;
   1698 					//continue;
   1699 				}
   1700 				//
   1701 				if (curplanenum == planenum) continue;
   1702 
   1703 				Vector4Copy( pc->planes[ curplanenum ].plane, plane );
   1704 				if ( !curinward ) {
   1705 					VectorSubtract( vec3_origin, plane, plane );
   1706 					plane[3] = -plane[3];
   1707 				}
   1708 		//			if ( !facet->borderNoAdjust[j] ) {
   1709 					plane[3] -= cv->value;
   1710 		//			}
   1711 				for (n = 0; n < 3; n++)
   1712 				{
   1713 					if (plane[n] > 0) v1[n] = maxs[n];
   1714 					else v1[n] = mins[n];
   1715 				} //end for
   1716 				VectorNegate(plane, v2);
   1717 				plane[3] -= fabs(DotProduct(v1, v2));
   1718 
   1719 				ChopWindingInPlace( &w, plane, plane[3], 0.1f );
   1720 			}
   1721 			if ( w ) {
   1722 				if ( facet == debugFacet ) {
   1723 					drawPoly( 4, w->numpoints, w->p[0] );
   1724 					//Com_Printf("blue facet has %d border planes\n", facet->numBorders);
   1725 				} else {
   1726 					drawPoly( 1, w->numpoints, w->p[0] );
   1727 				}
   1728 				FreeWinding( w );
   1729 			}
   1730 			else
   1731 				Com_Printf("winding chopped away by border planes\n");
   1732 		}
   1733 	}
   1734 
   1735 	// draw the debug block
   1736 	{
   1737 		vec3_t			v[3];
   1738 
   1739 		VectorCopy( debugBlockPoints[0], v[0] );
   1740 		VectorCopy( debugBlockPoints[1], v[1] );
   1741 		VectorCopy( debugBlockPoints[2], v[2] );
   1742 		drawPoly( 2, 3, v[0] );
   1743 
   1744 		VectorCopy( debugBlockPoints[2], v[0] );
   1745 		VectorCopy( debugBlockPoints[3], v[1] );
   1746 		VectorCopy( debugBlockPoints[0], v[2] );
   1747 		drawPoly( 2, 3, v[0] );
   1748 	}
   1749 
   1750 #if 0
   1751 	vec3_t			v[4];
   1752 
   1753 	v[0][0] = pc->bounds[1][0];
   1754 	v[0][1] = pc->bounds[1][1];
   1755 	v[0][2] = pc->bounds[1][2];
   1756 
   1757 	v[1][0] = pc->bounds[1][0];
   1758 	v[1][1] = pc->bounds[0][1];
   1759 	v[1][2] = pc->bounds[1][2];
   1760 
   1761 	v[2][0] = pc->bounds[0][0];
   1762 	v[2][1] = pc->bounds[0][1];
   1763 	v[2][2] = pc->bounds[1][2];
   1764 
   1765 	v[3][0] = pc->bounds[0][0];
   1766 	v[3][1] = pc->bounds[1][1];
   1767 	v[3][2] = pc->bounds[1][2];
   1768 
   1769 	drawPoly( 4, v[0] );
   1770 #endif
   1771 }