DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Winding.cpp (35033B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition 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 Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition 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 Doom 3 BFG Edition 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 #pragma hdrstop
     30 #include "../precompiled.h"
     31 
     32 //===============================================================
     33 //
     34 //	idWinding
     35 //
     36 //===============================================================
     37 
     38 /*
     39 =============
     40 idWinding::ReAllocate
     41 =============
     42 */
     43 bool idWinding::ReAllocate( int n, bool keep ) {
     44 	idVec5 *oldP;
     45 
     46 	oldP = p;
     47 	n = (n+3) & ~3;	// align up to multiple of four
     48 	p = new (TAG_IDLIB_WINDING) idVec5[n];
     49 	if ( oldP ) {
     50 		if ( keep ) {
     51 			memcpy( p, oldP, numPoints * sizeof(p[0]) );
     52 		}
     53 		delete[] oldP;
     54 	}
     55 	allocedSize = n;
     56 
     57 	return true;
     58 }
     59 
     60 /*
     61 =============
     62 idWinding::BaseForPlane
     63 =============
     64 */
     65 void idWinding::BaseForPlane( const idVec3 &normal, const float dist ) {
     66 	idVec3 org, vright, vup;
     67 
     68 	org = normal * dist;
     69 
     70 	normal.NormalVectors( vup, vright );
     71 	vup *= MAX_WORLD_SIZE;
     72 	vright *= MAX_WORLD_SIZE;
     73 
     74 	EnsureAlloced( 4 );
     75 	numPoints = 4;
     76 	p[0].ToVec3() = org - vright + vup;
     77 	p[0].s = p[0].t = 0.0f;
     78 	p[1].ToVec3() = org + vright + vup;
     79 	p[1].s = p[1].t = 0.0f;
     80 	p[2].ToVec3() = org + vright - vup;
     81 	p[2].s = p[2].t = 0.0f;
     82 	p[3].ToVec3() = org - vright - vup;
     83 	p[3].s = p[3].t = 0.0f;
     84 }
     85 
     86 /*
     87 =============
     88 idWinding::Split
     89 =============
     90 */
     91 int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **front, idWinding **back ) const {
     92 	float *			dists;
     93 	byte *			sides;
     94 	int				counts[3];
     95 	float			dot;
     96 	int				i, j;
     97 	const idVec5 *	p1, *p2;
     98 	idVec5			mid;
     99 	idWinding *		f, *b;
    100 	int				maxpts;
    101 
    102 	assert( this );
    103 
    104 	dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
    105 	sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );
    106 
    107 	counts[0] = counts[1] = counts[2] = 0;
    108 
    109 	// determine sides for each point
    110 	for ( i = 0; i < numPoints; i++ ) {
    111 		dists[i] = dot = plane.Distance( p[i].ToVec3() );
    112 		if ( dot > epsilon ) {
    113 			sides[i] = SIDE_FRONT;
    114 		} else if ( dot < -epsilon ) {
    115 			sides[i] = SIDE_BACK;
    116 		} else {
    117 			sides[i] = SIDE_ON;
    118 		}
    119 		counts[sides[i]]++;
    120 	}
    121 	sides[i] = sides[0];
    122 	dists[i] = dists[0];
    123 	
    124 	*front = *back = NULL;
    125 
    126 	// if coplanar, put on the front side if the normals match
    127 	if ( !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
    128 		idPlane windingPlane;
    129 
    130 		GetPlane( windingPlane );
    131 		if ( windingPlane.Normal() * plane.Normal() > 0.0f ) {
    132 			*front = Copy();
    133 			return SIDE_FRONT;
    134 		} else {
    135 			*back = Copy();
    136 			return SIDE_BACK;
    137 		}
    138 	}
    139 	// if nothing at the front of the clipping plane
    140 	if ( !counts[SIDE_FRONT] ) {
    141 		*back = Copy();
    142 		return SIDE_BACK;
    143 	}
    144 	// if nothing at the back of the clipping plane
    145 	if ( !counts[SIDE_BACK] ) {
    146 		*front = Copy();
    147 		return SIDE_FRONT;
    148 	}
    149 
    150 	maxpts = numPoints+4;	// cant use counts[0]+2 because of fp grouping errors
    151 
    152 	*front = f = new (TAG_IDLIB_WINDING) idWinding(maxpts);
    153 	*back = b = new (TAG_IDLIB_WINDING) idWinding(maxpts);
    154 		
    155 	for (i = 0; i < numPoints; i++) {
    156 		p1 = &p[i];
    157 		
    158 		if ( sides[i] == SIDE_ON ) {
    159 			f->p[f->numPoints] = *p1;
    160 			f->numPoints++;
    161 			b->p[b->numPoints] = *p1;
    162 			b->numPoints++;
    163 			continue;
    164 		}
    165 	
    166 		if ( sides[i] == SIDE_FRONT ) {
    167 			f->p[f->numPoints] = *p1;
    168 			f->numPoints++;
    169 		}
    170 
    171 		if ( sides[i] == SIDE_BACK ) {
    172 			b->p[b->numPoints] = *p1;
    173 			b->numPoints++;
    174 		}
    175 
    176 		if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
    177 			continue;
    178 		}
    179 			
    180 		// generate a split point
    181 		p2 = &p[(i+1)%numPoints];
    182 		
    183 		// always calculate the split going from the same side
    184 		// or minor epsilon issues can happen
    185 		if ( sides[i] == SIDE_FRONT ) {
    186 			dot = dists[i] / ( dists[i] - dists[i+1] );
    187 			for ( j = 0; j < 3; j++ ) {
    188 				// avoid round off error when possible
    189 				if ( plane.Normal()[j] == 1.0f ) {
    190 					mid[j] = plane.Dist();
    191 				} else if ( plane.Normal()[j] == -1.0f ) {
    192 					mid[j] = -plane.Dist();
    193 				} else {
    194 					mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
    195 				}
    196 			}
    197 			mid.s = p1->s + dot * ( p2->s - p1->s );
    198 			mid.t = p1->t + dot * ( p2->t - p1->t );
    199 		} else {
    200 			dot = dists[i+1] / ( dists[i+1] - dists[i] );
    201 			for ( j = 0; j < 3; j++ ) {	
    202 				// avoid round off error when possible
    203 				if ( plane.Normal()[j] == 1.0f ) {
    204 					mid[j] = plane.Dist();
    205 				} else if ( plane.Normal()[j] == -1.0f ) {
    206 					mid[j] = -plane.Dist();
    207 				} else {
    208 					mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] );
    209 				}
    210 			}
    211 			mid.s = p2->s + dot * ( p1->s - p2->s );
    212 			mid.t = p2->t + dot * ( p1->t - p2->t );
    213 		}
    214 
    215 		f->p[f->numPoints] = mid;
    216 		f->numPoints++;
    217 		b->p[b->numPoints] = mid;
    218 		b->numPoints++;
    219 	}
    220 	
    221 	if ( f->numPoints > maxpts || b->numPoints > maxpts ) {
    222 		idLib::common->FatalError( "idWinding::Split: points exceeded estimate." );
    223 	}
    224 
    225 	return SIDE_CROSS;
    226 }
    227 
    228 /*
    229 =============
    230 idWinding::Clip
    231 =============
    232 */
    233 idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const bool keepOn ) {
    234 	float *		dists;
    235 	byte *		sides;
    236 	idVec5 *	newPoints;
    237 	int			newNumPoints;
    238 	int			counts[3];
    239 	float		dot;
    240 	int			i, j;
    241 	idVec5 *	p1, *p2;
    242 	idVec5		mid;
    243 	int			maxpts;
    244 
    245 	assert( this );
    246 
    247 	dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
    248 	sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );
    249 
    250 	counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
    251 
    252 	// determine sides for each point
    253 	for ( i = 0; i < numPoints; i++ ) {
    254 		dists[i] = dot = plane.Distance( p[i].ToVec3() );
    255 		if ( dot > epsilon ) {
    256 			sides[i] = SIDE_FRONT;
    257 		} else if ( dot < -epsilon ) {
    258 			sides[i] = SIDE_BACK;
    259 		} else {
    260 			sides[i] = SIDE_ON;
    261 		}
    262 		counts[sides[i]]++;
    263 	}
    264 	sides[i] = sides[0];
    265 	dists[i] = dists[0];
    266 
    267 	// if the winding is on the plane and we should keep it
    268 	if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
    269 		return this;
    270 	}
    271 	// if nothing at the front of the clipping plane
    272 	if ( !counts[SIDE_FRONT] ) {
    273 		delete this;
    274 		return NULL;
    275 	}
    276 	// if nothing at the back of the clipping plane
    277 	if ( !counts[SIDE_BACK] ) {
    278 		return this;
    279 	}
    280 
    281 	maxpts = numPoints + 4;		// cant use counts[0]+2 because of fp grouping errors
    282 
    283 	newPoints = (idVec5 *) _alloca16( maxpts * sizeof( idVec5 ) );
    284 	newNumPoints = 0;
    285 		
    286 	for ( i = 0; i < numPoints; i++ ) {
    287 		p1 = &p[i];
    288 
    289 		if ( newNumPoints+1 > maxpts ) {
    290 			return this;		// can't split -- fall back to original
    291 		}
    292 
    293 		if ( sides[i] == SIDE_ON ) {
    294 			newPoints[newNumPoints] = *p1;
    295 			newNumPoints++;
    296 			continue;
    297 		}
    298 
    299 		if ( sides[i] == SIDE_FRONT ) {
    300 			newPoints[newNumPoints] = *p1;
    301 			newNumPoints++;
    302 		}
    303 
    304 		if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
    305 			continue;
    306 		}
    307 
    308 		if ( newNumPoints+1 > maxpts ) {
    309 			return this;		// can't split -- fall back to original
    310 		}
    311 
    312 		// generate a split point
    313 		p2 = &p[(i+1)%numPoints];
    314 
    315 		dot = dists[i] / (dists[i] - dists[i+1]);
    316 		for ( j = 0; j < 3; j++ ) {
    317 			// avoid round off error when possible
    318 			if ( plane.Normal()[j] == 1.0f ) {
    319 				mid[j] = plane.Dist();
    320 			} else if ( plane.Normal()[j] == -1.0f ) {
    321 				mid[j] = -plane.Dist();
    322 			} else {
    323 				mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
    324 			}
    325 		}
    326 		mid.s = p1->s + dot * ( p2->s - p1->s );
    327 		mid.t = p1->t + dot * ( p2->t - p1->t );
    328 
    329 		newPoints[newNumPoints] = mid;
    330 		newNumPoints++;
    331 	}
    332 	
    333 	if ( !EnsureAlloced( newNumPoints, false ) ) {
    334 		return this;
    335 	}
    336 
    337 	numPoints = newNumPoints;
    338 	memcpy( p, newPoints, newNumPoints * sizeof(idVec5) );
    339 
    340 	return this;
    341 }
    342 
    343 /*
    344 =============
    345 idWinding::ClipInPlace
    346 =============
    347 */
    348 bool idWinding::ClipInPlace( const idPlane &plane, const float epsilon, const bool keepOn ) {
    349 	float*		dists;
    350 	byte *		sides;
    351 	idVec5 *	newPoints;
    352 	int			newNumPoints;
    353 	int			counts[3];
    354 	float		dot;
    355 	int			i, j;
    356 	idVec5 *	p1, *p2;
    357 	idVec5		mid;
    358 	int			maxpts;
    359 
    360 	assert( this );
    361 
    362 	dists = (float *) _alloca( (numPoints+4) * sizeof( float ) );
    363 	sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) );
    364 
    365 	counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
    366 
    367 	// determine sides for each point
    368 	for ( i = 0; i < numPoints; i++ ) {
    369 		dists[i] = dot = plane.Distance( p[i].ToVec3() );
    370 		if ( dot > epsilon ) {
    371 			sides[i] = SIDE_FRONT;
    372 		} else if ( dot < -epsilon ) {
    373 			sides[i] = SIDE_BACK;
    374 		} else {
    375 			sides[i] = SIDE_ON;
    376 		}
    377 		counts[sides[i]]++;
    378 	}
    379 	sides[i] = sides[0];
    380 	dists[i] = dists[0];
    381 	
    382 	// if the winding is on the plane and we should keep it
    383 	if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
    384 		return true;
    385 	}
    386 	// if nothing at the front of the clipping plane
    387 	if ( !counts[SIDE_FRONT] ) {
    388 		numPoints = 0;
    389 		return false;
    390 	}
    391 	// if nothing at the back of the clipping plane
    392 	if ( !counts[SIDE_BACK] ) {
    393 		return true;
    394 	}
    395 
    396 	maxpts = numPoints + 4;		// cant use counts[0]+2 because of fp grouping errors
    397 
    398 	newPoints = (idVec5 *) _alloca16( maxpts * sizeof( idVec5 ) );
    399 	newNumPoints = 0;
    400 
    401 	for ( i = 0; i < numPoints; i++ ) {
    402 		p1 = &p[i];
    403 
    404 		if ( newNumPoints+1 > maxpts ) {
    405 			return true;		// can't split -- fall back to original
    406 		}
    407 		
    408 		if ( sides[i] == SIDE_ON ) {
    409 			newPoints[newNumPoints] = *p1;
    410 			newNumPoints++;
    411 			continue;
    412 		}
    413 	
    414 		if ( sides[i] == SIDE_FRONT ) {
    415 			newPoints[newNumPoints] = *p1;
    416 			newNumPoints++;
    417 		}
    418 
    419 		if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
    420 			continue;
    421 		}
    422 			
    423 		if ( newNumPoints+1 > maxpts ) {
    424 			return true;		// can't split -- fall back to original
    425 		}
    426 
    427 		// generate a split point
    428 		p2 = &p[(i+1)%numPoints];
    429 		
    430 		dot = dists[i] / (dists[i] - dists[i+1]);
    431 		for ( j = 0; j < 3; j++ ) {
    432 			// avoid round off error when possible
    433 			if ( plane.Normal()[j] == 1.0f ) {
    434 				mid[j] = plane.Dist();
    435 			} else if ( plane.Normal()[j] == -1.0f ) {
    436 				mid[j] = -plane.Dist();
    437 			} else {
    438 				mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
    439 			}
    440 		}
    441 		mid.s = p1->s + dot * ( p2->s - p1->s );
    442 		mid.t = p1->t + dot * ( p2->t - p1->t );
    443 			
    444 		newPoints[newNumPoints] = mid;
    445 		newNumPoints++;
    446 	}
    447 
    448 	if ( !EnsureAlloced( newNumPoints, false ) ) {
    449 		return true;
    450 	}
    451 
    452 	numPoints = newNumPoints;
    453 	memcpy( p, newPoints, newNumPoints * sizeof(idVec5) );
    454 
    455 	return true;
    456 }
    457 
    458 /*
    459 =============
    460 idWinding::Copy
    461 =============
    462 */
    463 idWinding *idWinding::Copy() const {
    464 	idWinding *w;
    465 
    466 	w = new (TAG_IDLIB_WINDING) idWinding( numPoints );
    467 	w->numPoints = numPoints;
    468 	memcpy( w->p, p, numPoints * sizeof(p[0]) );
    469 	return w;
    470 }
    471 
    472 /*
    473 =============
    474 idWinding::Reverse
    475 =============
    476 */
    477 idWinding *idWinding::Reverse() const {
    478 	idWinding *w;
    479 	int i;
    480 
    481 	w = new (TAG_IDLIB_WINDING) idWinding( numPoints );
    482 	w->numPoints = numPoints;
    483 	for ( i = 0; i < numPoints; i++ ) {
    484 		w->p[ numPoints - i - 1 ] = p[i];
    485 	}
    486 	return w;
    487 }
    488 
    489 /*
    490 =============
    491 idWinding::ReverseSelf
    492 =============
    493 */
    494 void idWinding::ReverseSelf() {
    495 	idVec5 v;
    496 	int i;
    497 
    498 	for ( i = 0; i < (numPoints>>1); i++ ) {
    499 		v = p[i];
    500 		p[i] = p[numPoints - i - 1];
    501 		p[numPoints - i - 1] = v;
    502 	}
    503 }
    504 
    505 /*
    506 =============
    507 idWinding::Check
    508 =============
    509 */
    510 bool idWinding::Check( bool print ) const {
    511 	int				i, j;
    512 	float			d, edgedist;
    513 	idVec3			dir, edgenormal;
    514 	float			area;
    515 	idPlane			plane;
    516 
    517 	if ( numPoints < 3 ) {
    518 		if ( print ) {
    519 			idLib::common->Printf( "idWinding::Check: only %i points.", numPoints );
    520 		}
    521 		return false;
    522 	}
    523 	
    524 	area = GetArea();
    525 	if ( area < 1.0f ) {
    526 		if ( print ) {
    527 			idLib::common->Printf( "idWinding::Check: tiny area: %f", area );
    528 		}
    529 		return false;
    530 	}
    531 
    532 	GetPlane( plane );
    533 	
    534 	for ( i = 0; i < numPoints; i++ ) {
    535 		const idVec3 &p1 = p[i].ToVec3();
    536 
    537 		// check if the winding is huge
    538 		for ( j = 0; j < 3; j++ ) {
    539 			if ( p1[j] >= MAX_WORLD_COORD || p1[j] <= MIN_WORLD_COORD ) {
    540 				if ( print ) {
    541 					idLib::common->Printf( "idWinding::Check: point %d outside world %c-axis: %f", i, 'X'+j, p1[j] );
    542 				}
    543 				return false;
    544 			}
    545 		}
    546 
    547 		j = i + 1 == numPoints ? 0 : i + 1;
    548 		
    549 		// check if the point is on the face plane
    550 		d = p1 * plane.Normal() + plane[3];
    551 		if ( d < -ON_EPSILON || d > ON_EPSILON ) {
    552 			if ( print ) {
    553 				idLib::common->Printf( "idWinding::Check: point %d off plane.", i );
    554 			}
    555 			return false;
    556 		}
    557 	
    558 		// check if the edge isn't degenerate
    559 		const idVec3 &p2 = p[j].ToVec3();
    560 		dir = p2 - p1;
    561 		
    562 		if ( dir.Length() < ON_EPSILON) {
    563 			if ( print ) {
    564 				idLib::common->Printf( "idWinding::Check: edge %d is degenerate.", i );
    565 			}
    566 			return false;
    567 		}
    568 
    569 		// check if the winding is convex
    570 		edgenormal = plane.Normal().Cross( dir );
    571 		edgenormal.Normalize();
    572 		edgedist = p1 * edgenormal;
    573 		edgedist += ON_EPSILON;
    574 		
    575 		// all other points must be on front side
    576 		for ( j = 0; j < numPoints; j++ ) {
    577 			if ( j == i ) {
    578 				continue;
    579 			}
    580 			d = p[j].ToVec3() * edgenormal;
    581 			if ( d > edgedist ) {
    582 				if ( print ) {
    583 					idLib::common->Printf( "idWinding::Check: non-convex." );
    584 				}
    585 				return false;
    586 			}
    587 		}
    588 	}
    589 	return true;
    590 }
    591 
    592 /*
    593 =============
    594 idWinding::GetArea
    595 =============
    596 */
    597 float idWinding::GetArea() const {
    598 	int i;
    599 	idVec3 d1, d2, cross;
    600 	float total;
    601 
    602 	total = 0.0f;
    603 	for ( i = 2; i < numPoints; i++ ) {
    604 		d1 = p[i-1].ToVec3() - p[0].ToVec3();
    605 		d2 = p[i].ToVec3() - p[0].ToVec3();
    606 		cross = d1.Cross( d2 );
    607 		total += cross.Length();
    608 	}
    609 	return total * 0.5f;
    610 }
    611 
    612 /*
    613 =============
    614 idWinding::GetRadius
    615 =============
    616 */
    617 float idWinding::GetRadius( const idVec3 &center ) const {
    618 	int i;
    619 	float radius, r;
    620 	idVec3 dir;
    621 
    622 	radius = 0.0f;
    623 	for ( i = 0; i < numPoints; i++ ) {
    624 		dir = p[i].ToVec3() - center;
    625 		r = dir * dir;
    626 		if ( r > radius ) {
    627 			radius = r;
    628 		}
    629 	}
    630 	return idMath::Sqrt( radius );
    631 }
    632 
    633 /*
    634 =============
    635 idWinding::GetCenter
    636 =============
    637 */
    638 idVec3 idWinding::GetCenter() const {
    639 	int i;
    640 	idVec3 center;
    641 
    642 	center.Zero();
    643 	for ( i = 0; i < numPoints; i++ ) {
    644 		center += p[i].ToVec3();
    645 	}
    646 	center *= ( 1.0f / numPoints );
    647 	return center;
    648 }
    649 
    650 /*
    651 =============
    652 idWinding::GetPlane
    653 =============
    654 */
    655 void idWinding::GetPlane( idVec3 &normal, float &dist ) const {
    656 	idVec3 v1, v2, center;
    657 
    658 	if ( numPoints < 3 ) {
    659 		normal.Zero();
    660 		dist = 0.0f;
    661 		return;
    662 	}
    663 
    664 	center = GetCenter();
    665 	v1 = p[0].ToVec3() - center;
    666 	v2 = p[1].ToVec3() - center;
    667 	normal = v2.Cross( v1 );
    668 	normal.Normalize();
    669 	dist = p[0].ToVec3() * normal;
    670 }
    671 
    672 /*
    673 =============
    674 idWinding::GetPlane
    675 =============
    676 */
    677 void idWinding::GetPlane( idPlane &plane ) const {
    678 	idVec3 v1, v2;
    679 	idVec3 center;
    680 
    681 	if ( numPoints < 3 ) {
    682 		plane.Zero();
    683 		return;
    684 	}
    685 
    686 	center = GetCenter();
    687 	v1 = p[0].ToVec3() - center;
    688 	v2 = p[1].ToVec3() - center;
    689 	plane.SetNormal( v2.Cross( v1 ) );
    690 	plane.Normalize();
    691 	plane.FitThroughPoint( p[0].ToVec3() );
    692 }
    693 
    694 /*
    695 =============
    696 idWinding::GetBounds
    697 =============
    698 */
    699 void idWinding::GetBounds( idBounds &bounds ) const {
    700 	int i;
    701 
    702 	if ( !numPoints ) {
    703 		bounds.Clear();
    704 		return;
    705 	}
    706 
    707 	bounds[0] = bounds[1] = p[0].ToVec3();
    708 	for ( i = 1; i < numPoints; i++ ) {
    709 		if ( p[i].x < bounds[0].x ) {
    710 			bounds[0].x = p[i].x;
    711 		} else if ( p[i].x > bounds[1].x ) {
    712 			bounds[1].x = p[i].x;
    713 		}
    714 		if ( p[i].y < bounds[0].y ) {
    715 			bounds[0].y = p[i].y;
    716 		} else if ( p[i].y > bounds[1].y ) {
    717 			bounds[1].y = p[i].y;
    718 		}
    719 		if ( p[i].z < bounds[0].z ) {
    720 			bounds[0].z = p[i].z;
    721 		} else if ( p[i].z > bounds[1].z ) {
    722 			bounds[1].z = p[i].z;
    723 		}
    724 	}
    725 }
    726 
    727 /*
    728 =============
    729 idWinding::RemoveEqualPoints
    730 =============
    731 */
    732 void idWinding::RemoveEqualPoints( const float epsilon ) {
    733 	int i, j;
    734 
    735 	for ( i = 0; i < numPoints; i++ ) {
    736 		if ( (p[i].ToVec3() - p[(i+numPoints-1)%numPoints].ToVec3()).LengthSqr() >= Square( epsilon ) ) {
    737 			continue;
    738 		}
    739 		numPoints--;
    740 		for ( j = i; j < numPoints; j++ ) {
    741 			p[j] = p[j+1];
    742 		}
    743 		i--;
    744 	}
    745 }
    746 
    747 /*
    748 =============
    749 idWinding::RemoveColinearPoints
    750 =============
    751 */
    752 void idWinding::RemoveColinearPoints( const idVec3 &normal, const float epsilon ) {
    753 	int i, j;
    754 	idVec3 edgeNormal;
    755 	float dist;
    756 
    757 	if ( numPoints <= 3 ) {
    758 		return;
    759 	}
    760 
    761 	for ( i = 0; i < numPoints; i++ ) {
    762 
    763 		// create plane through edge orthogonal to winding plane
    764 		edgeNormal = (p[i].ToVec3() - p[(i+numPoints-1)%numPoints].ToVec3()).Cross( normal );
    765 		edgeNormal.Normalize();
    766 		dist = edgeNormal * p[i].ToVec3();
    767 
    768 		if ( idMath::Fabs( edgeNormal * p[(i+1)%numPoints].ToVec3() - dist ) > epsilon ) {
    769 			continue;
    770 		}
    771 
    772 		numPoints--;
    773 		for ( j = i; j < numPoints; j++ ) {
    774 			p[j] = p[j+1];
    775 		}
    776 		i--;
    777 	}
    778 }
    779 
    780 /*
    781 =============
    782 idWinding::AddToConvexHull
    783 
    784   Adds the given winding to the convex hull.
    785   Assumes the current winding already is a convex hull with three or more points.
    786 =============
    787 */
    788 void idWinding::AddToConvexHull( const idWinding *winding, const idVec3 &normal, const float epsilon ) {
    789 	int				i, j, k;
    790 	idVec3			dir;
    791 	float			d;
    792 	int				maxPts;
    793 	idVec3 *		hullDirs;
    794 	bool *			hullSide;
    795 	bool			outside;
    796 	int				numNewHullPoints;
    797 	idVec5 *		newHullPoints;
    798 
    799 	if ( !winding ) {
    800 		return;
    801 	}
    802 
    803 	maxPts = this->numPoints + winding->numPoints;
    804 
    805 	if ( !this->EnsureAlloced( maxPts, true ) ) {
    806 		return;
    807 	}
    808 
    809 	newHullPoints = (idVec5 *) _alloca( maxPts * sizeof( idVec5 ) );
    810 	hullDirs = (idVec3 *) _alloca( maxPts * sizeof( idVec3 ) );
    811 	hullSide = (bool *) _alloca( maxPts * sizeof( bool ) );
    812 
    813 	for ( i = 0; i < winding->numPoints; i++ ) {
    814 		const idVec5 &p1 = winding->p[i];
    815 
    816 		// calculate hull edge vectors
    817 		for ( j = 0; j < this->numPoints; j++ ) {
    818 			dir = this->p[ (j + 1) % this->numPoints ].ToVec3() - this->p[ j ].ToVec3();
    819 			dir.Normalize();
    820 			hullDirs[j] = normal.Cross( dir );
    821 		}
    822 
    823 		// calculate side for each hull edge
    824 		outside = false;
    825 		for ( j = 0; j < this->numPoints; j++ ) {
    826 			dir = p1.ToVec3() - this->p[j].ToVec3();
    827 			d = dir * hullDirs[j];
    828 			if ( d >= epsilon ) {
    829 				outside = true;
    830 			}
    831 			if ( d >= -epsilon ) {
    832 				hullSide[j] = true;
    833 			} else {
    834 				hullSide[j] = false;
    835 			}
    836 		}
    837 
    838 		// if the point is effectively inside, do nothing
    839 		if ( !outside ) {
    840 			continue;
    841 		}
    842 
    843 		// find the back side to front side transition
    844 		for ( j = 0; j < this->numPoints; j++ ) {
    845 			if ( !hullSide[ j ] && hullSide[ (j + 1) % this->numPoints ] ) {
    846 				break;
    847 			}
    848 		}
    849 		if ( j >= this->numPoints ) {
    850 			continue;
    851 		}
    852 
    853 		// insert the point here
    854 		newHullPoints[0] = p1;
    855 		numNewHullPoints = 1;
    856 
    857 		// copy over all points that aren't double fronts
    858 		j = (j+1) % this->numPoints;
    859 		for ( k = 0; k < this->numPoints; k++ ) {
    860 			if ( hullSide[ (j+k) % this->numPoints ] && hullSide[ (j+k+1) % this->numPoints ] ) {
    861 				continue;
    862 			}
    863 			newHullPoints[numNewHullPoints] = this->p[ (j+k+1) % this->numPoints ];
    864 			numNewHullPoints++;
    865 		}
    866 
    867 		this->numPoints = numNewHullPoints;
    868 		memcpy( this->p, newHullPoints, numNewHullPoints * sizeof(idVec5) );
    869 	}
    870 }
    871 
    872 /*
    873 =============
    874 idWinding::AddToConvexHull
    875 
    876   Add a point to the convex hull.
    877   The current winding must be convex but may be degenerate and can have less than three points.
    878 =============
    879 */
    880 void idWinding::AddToConvexHull( const idVec3 &point, const idVec3 &normal, const float epsilon ) {
    881 	int				j, k, numHullPoints;
    882 	idVec3			dir;
    883 	float			d;
    884 	idVec3 *		hullDirs;
    885 	bool *			hullSide;
    886 	idVec5 *		hullPoints;
    887 	bool			outside;
    888 
    889 	switch( numPoints ) {
    890 		case 0: {
    891 			p[0] = point;
    892 			numPoints++;
    893 			return;
    894 		}
    895 		case 1: {
    896 			// don't add the same point second
    897 			if ( p[0].ToVec3().Compare( point, epsilon ) ) {
    898 				return;
    899 			}
    900 			p[1].ToVec3() = point;
    901 			numPoints++;
    902 			return;
    903 		}
    904 		case 2: {
    905 			// don't add a point if it already exists
    906 			if ( p[0].ToVec3().Compare( point, epsilon ) || p[1].ToVec3().Compare( point, epsilon ) ) {
    907 				return;
    908 			}
    909 			// if only two points make sure we have the right ordering according to the normal
    910 			dir = point - p[0].ToVec3();
    911 			dir = dir.Cross( p[1].ToVec3() - p[0].ToVec3() );
    912 			if ( dir[0] == 0.0f && dir[1] == 0.0f && dir[2] == 0.0f ) {
    913 				// points don't make a plane
    914 				return;
    915 			}
    916 			if ( dir * normal > 0.0f ) {
    917 				p[2].ToVec3() = point;
    918 			}
    919 			else {
    920 				p[2] = p[1];
    921 				p[1].ToVec3() = point;
    922 			}
    923 			numPoints++;
    924 			return;
    925 		}
    926 	}
    927 
    928 	hullDirs = (idVec3 *) _alloca( numPoints * sizeof( idVec3 ) );
    929 	hullSide = (bool *) _alloca( numPoints * sizeof( bool ) );
    930 
    931 	// calculate hull edge vectors
    932 	for ( j = 0; j < numPoints; j++ ) {
    933 		dir = p[(j + 1) % numPoints].ToVec3() - p[j].ToVec3();
    934 		hullDirs[j] = normal.Cross( dir );
    935 	}
    936 
    937 	// calculate side for each hull edge
    938 	outside = false;
    939 	for ( j = 0; j < numPoints; j++ ) {
    940 		dir = point - p[j].ToVec3();
    941 		d = dir * hullDirs[j];
    942 		if ( d >= epsilon ) {
    943 			outside = true;
    944 		}
    945 		if ( d >= -epsilon ) {
    946 			hullSide[j] = true;
    947 		} else {
    948 			hullSide[j] = false;
    949 		}
    950 	}
    951 
    952 	// if the point is effectively inside, do nothing
    953 	if ( !outside ) {
    954 		return;
    955 	}
    956 
    957 	// find the back side to front side transition
    958 	for ( j = 0; j < numPoints; j++ ) {
    959 		if ( !hullSide[ j ] && hullSide[ (j + 1) % numPoints ] ) {
    960 			break;
    961 		}
    962 	}
    963 	if ( j >= numPoints ) {
    964 		return;
    965 	}
    966 
    967 	hullPoints = (idVec5 *) _alloca( (numPoints+1) * sizeof( idVec5 ) );
    968 
    969 	// insert the point here
    970 	hullPoints[0] = point;
    971 	numHullPoints = 1;
    972 
    973 	// copy over all points that aren't double fronts
    974 	j = (j+1) % numPoints;
    975 	for ( k = 0; k < numPoints; k++ ) {
    976 		if ( hullSide[ (j+k) % numPoints ] && hullSide[ (j+k+1) % numPoints ] ) {
    977 			continue;
    978 		}
    979 		hullPoints[numHullPoints] = p[ (j+k+1) % numPoints ];
    980 		numHullPoints++;
    981 	}
    982 
    983 	if ( !EnsureAlloced( numHullPoints, false ) ) {
    984 		return;
    985 	}
    986 	numPoints = numHullPoints;
    987 	memcpy( p, hullPoints, numHullPoints * sizeof(idVec5) );
    988 }
    989 
    990 /*
    991 =============
    992 idWinding::TryMerge
    993 =============
    994 */
    995 #define	CONTINUOUS_EPSILON	0.005f
    996 
    997 idWinding *idWinding::TryMerge( const idWinding &w, const idVec3 &planenormal, int keep ) const {
    998 	idVec3			*p1, *p2, *p3, *p4, *back;
    999 	idWinding		*newf;
   1000 	const idWinding	*f1, *f2;
   1001 	int				i, j, k, l;
   1002 	idVec3			normal, delta;
   1003 	float			dot;
   1004 	bool			keep1, keep2;
   1005 
   1006 	f1 = this;
   1007 	f2 = &w;
   1008 	//
   1009 	// find a idLib::common edge
   1010 	//	
   1011 	p1 = p2 = NULL;	// stop compiler warning
   1012 	j = 0;
   1013 	
   1014 	for ( i = 0; i < f1->numPoints; i++ ) {
   1015 		p1 = &f1->p[i].ToVec3();
   1016 		p2 = &f1->p[(i+1) % f1->numPoints].ToVec3();
   1017 		for ( j = 0; j < f2->numPoints; j++ ) {
   1018 			p3 = &f2->p[j].ToVec3();
   1019 			p4 = &f2->p[(j+1) % f2->numPoints].ToVec3();
   1020 			for (k = 0; k < 3; k++ ) {
   1021 				if ( idMath::Fabs((*p1)[k] - (*p4)[k]) > 0.1f ) {
   1022 					break;
   1023 				}
   1024 				if ( idMath::Fabs((*p2)[k] - (*p3)[k]) > 0.1f ) {
   1025 					break;
   1026 				}
   1027 			}
   1028 			if ( k == 3 ) {
   1029 				break;
   1030 			}
   1031 		}
   1032 		if ( j < f2->numPoints ) {
   1033 			break;
   1034 		}
   1035 	}
   1036 	
   1037 	if ( i == f1->numPoints ) {
   1038 		return NULL;			// no matching edges
   1039 	}
   1040 
   1041 	//
   1042 	// check slope of connected lines
   1043 	// if the slopes are colinear, the point can be removed
   1044 	//
   1045 	back = &f1->p[(i+f1->numPoints-1)%f1->numPoints].ToVec3();
   1046 	delta = (*p1) - (*back);
   1047 	normal = planenormal.Cross(delta);
   1048 	normal.Normalize();
   1049 	
   1050 	back = &f2->p[(j+2)%f2->numPoints].ToVec3();
   1051 	delta = (*back) - (*p1);
   1052 	dot = delta * normal;
   1053 	if ( dot > CONTINUOUS_EPSILON ) {
   1054 		return NULL;			// not a convex polygon
   1055 	}
   1056 
   1057 	keep1 = (bool)(dot < -CONTINUOUS_EPSILON);
   1058 	
   1059 	back = &f1->p[(i+2)%f1->numPoints].ToVec3();
   1060 	delta = (*back) - (*p2);
   1061 	normal = planenormal.Cross( delta );
   1062 	normal.Normalize();
   1063 
   1064 	back = &f2->p[(j+f2->numPoints-1)%f2->numPoints].ToVec3();
   1065 	delta = (*back) - (*p2);
   1066 	dot = delta * normal;
   1067 	if ( dot > CONTINUOUS_EPSILON ) {
   1068 		return NULL;			// not a convex polygon
   1069 	}
   1070 
   1071 	keep2 = (bool)(dot < -CONTINUOUS_EPSILON);
   1072 
   1073 	//
   1074 	// build the new polygon
   1075 	//
   1076 	newf = new (TAG_IDLIB_WINDING) idWinding( f1->numPoints + f2->numPoints );
   1077 	
   1078 	// copy first polygon
   1079 	for ( k = (i+1) % f1->numPoints; k != i; k = (k+1) % f1->numPoints ) {
   1080 		if ( !keep && k == (i+1) % f1->numPoints && !keep2 ) {
   1081 			continue;
   1082 		}
   1083 		
   1084 		newf->p[newf->numPoints] = f1->p[k];
   1085 		newf->numPoints++;
   1086 	}
   1087 	
   1088 	// copy second polygon
   1089 	for ( l = (j+1) % f2->numPoints; l != j; l = (l+1) % f2->numPoints ) {
   1090 		if ( !keep && l == (j+1) % f2->numPoints && !keep1 ) {
   1091 			continue;
   1092 		}
   1093 		newf->p[newf->numPoints] = f2->p[l];
   1094 		newf->numPoints++;
   1095 	}
   1096 
   1097 	return newf;
   1098 }
   1099 
   1100 /*
   1101 =============
   1102 idWinding::RemovePoint
   1103 =============
   1104 */
   1105 void idWinding::RemovePoint( int point ) {
   1106 	if ( point < 0 || point >= numPoints ) {
   1107 		idLib::common->FatalError( "idWinding::removePoint: point out of range" );
   1108 	}
   1109 	if ( point < numPoints - 1) {
   1110 		memmove(&p[point], &p[point+1], (numPoints - point - 1) * sizeof(p[0]) );
   1111 	}
   1112 	numPoints--;
   1113 }
   1114 
   1115 /*
   1116 =============
   1117 idWinding::InsertPoint
   1118 =============
   1119 */
   1120 void idWinding::InsertPoint( const idVec5 &point, int spot ) {
   1121 	int i;
   1122 
   1123 	if ( spot > numPoints ) {
   1124 		idLib::common->FatalError( "idWinding::insertPoint: spot > numPoints" );
   1125 	}
   1126 
   1127 	if ( spot < 0 ) {
   1128 		idLib::common->FatalError( "idWinding::insertPoint: spot < 0" );
   1129 	}
   1130 
   1131 	EnsureAlloced( numPoints+1, true );
   1132 	for ( i = numPoints; i > spot; i-- ) {
   1133 		p[i] = p[i-1];
   1134 	}
   1135 	p[spot] = point;
   1136 	numPoints++;
   1137 }
   1138 
   1139 /*
   1140 =============
   1141 idWinding::InsertPointIfOnEdge
   1142 =============
   1143 */
   1144 bool idWinding::InsertPointIfOnEdge( const idVec5 &point, const idPlane &plane, const float epsilon ) {
   1145 	int i;
   1146 	float dist, dot;
   1147 	idVec3 normal;
   1148 
   1149 	// point may not be too far from the winding plane
   1150 	if ( idMath::Fabs( plane.Distance( point.ToVec3() ) ) > epsilon ) {
   1151 		return false;
   1152 	}
   1153 
   1154 	for ( i = 0; i < numPoints; i++ ) {
   1155 
   1156 		// create plane through edge orthogonal to winding plane
   1157 		normal = (p[(i+1)%numPoints].ToVec3() - p[i].ToVec3()).Cross( plane.Normal() );
   1158 		normal.Normalize();
   1159 		dist = normal * p[i].ToVec3();
   1160 
   1161 		if ( idMath::Fabs( normal * point.ToVec3() - dist ) > epsilon ) {
   1162 			continue;
   1163 		}
   1164 
   1165 		normal = plane.Normal().Cross( normal );
   1166 		dot = normal * point.ToVec3();
   1167 
   1168 		dist = dot - normal * p[i].ToVec3();
   1169 
   1170 		if ( dist < epsilon ) {
   1171 			// if the winding already has the point
   1172 			if ( dist > -epsilon ) {
   1173 				return false;
   1174 			}
   1175 			continue;
   1176 		}
   1177 
   1178 		dist = dot - normal * p[(i+1)%numPoints].ToVec3();
   1179 
   1180 		if ( dist > -epsilon ) {
   1181 			// if the winding already has the point
   1182 			if ( dist < epsilon ) {
   1183 				return false;
   1184 			}
   1185 			continue;
   1186 		}
   1187 
   1188 		InsertPoint( point, i+1 );
   1189 		return true;
   1190 	}
   1191 	return false;
   1192 }
   1193 
   1194 /*
   1195 =============
   1196 idWinding::IsTiny
   1197 =============
   1198 */
   1199 #define	EDGE_LENGTH		0.2f
   1200 
   1201 bool idWinding::IsTiny() const {
   1202 	int		i;
   1203 	float	len;
   1204 	idVec3	delta;
   1205 	int		edges;
   1206 
   1207 	edges = 0;
   1208 	for ( i = 0; i < numPoints; i++ ) {
   1209 		delta = p[(i+1)%numPoints].ToVec3() - p[i].ToVec3();
   1210 		len = delta.Length();
   1211 		if ( len > EDGE_LENGTH ) {
   1212 			if ( ++edges == 3 ) {
   1213 				return false;
   1214 			}
   1215 		}
   1216 	}
   1217 	return true;
   1218 }
   1219 
   1220 /*
   1221 =============
   1222 idWinding::IsHuge
   1223 =============
   1224 */
   1225 bool idWinding::IsHuge() const {
   1226 	int i, j;
   1227 
   1228 	for ( i = 0; i < numPoints; i++ ) {
   1229 		for ( j = 0; j < 3; j++ ) {
   1230 			if ( p[i][j] <= MIN_WORLD_COORD || p[i][j] >= MAX_WORLD_COORD ) {
   1231 				return true;
   1232 			}
   1233 		}
   1234 	}
   1235 	return false;
   1236 }
   1237 
   1238 /*
   1239 =============
   1240 idWinding::Print
   1241 =============
   1242 */
   1243 void idWinding::Print() const {
   1244 	int i;
   1245 
   1246 	for ( i = 0; i < numPoints; i++ ) {
   1247 		idLib::common->Printf( "(%5.1f, %5.1f, %5.1f)\n", p[i][0], p[i][1], p[i][2] );
   1248 	}
   1249 }
   1250 
   1251 /*
   1252 =============
   1253 idWinding::PlaneDistance
   1254 =============
   1255 */
   1256 float idWinding::PlaneDistance( const idPlane &plane ) const {
   1257 	int		i;
   1258 	float	d, min, max;
   1259 
   1260 	min = idMath::INFINITY;
   1261 	max = -min;
   1262 	for ( i = 0; i < numPoints; i++ ) {
   1263 		d = plane.Distance( p[i].ToVec3() );
   1264 		if ( d < min ) {
   1265 			min = d;
   1266 			if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
   1267 				return 0.0f;
   1268 			}
   1269 		}
   1270 		if ( d > max ) {
   1271 			max = d;
   1272 			if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
   1273 				return 0.0f;
   1274 			}
   1275 		}
   1276 	}
   1277 	if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
   1278 		return min;
   1279 	}
   1280 	if ( IEEE_FLT_SIGNBITSET( max ) ) {
   1281 		return max;
   1282 	}
   1283 	return 0.0f;
   1284 }
   1285 
   1286 /*
   1287 =============
   1288 idWinding::PlaneSide
   1289 =============
   1290 */
   1291 int idWinding::PlaneSide( const idPlane &plane, const float epsilon ) const {
   1292 	bool	front, back;
   1293 	int		i;
   1294 	float	d;
   1295 
   1296 	front = false;
   1297 	back = false;
   1298 	for ( i = 0; i < numPoints; i++ ) {
   1299 		d = plane.Distance( p[i].ToVec3() );
   1300 		if ( d < -epsilon ) {
   1301 			if ( front ) {
   1302 				return SIDE_CROSS;
   1303 			}
   1304 			back = true;
   1305 			continue;
   1306 		}
   1307 		else if ( d > epsilon ) {
   1308 			if ( back ) {
   1309 				return SIDE_CROSS;
   1310 			}
   1311 			front = true;
   1312 			continue;
   1313 		}
   1314 	}
   1315 
   1316 	if ( back ) {
   1317 		return SIDE_BACK;
   1318 	}
   1319 	if ( front ) {
   1320 		return SIDE_FRONT;
   1321 	}
   1322 	return SIDE_ON;
   1323 }
   1324 
   1325 /*
   1326 =============
   1327 idWinding::PlanesConcave
   1328 =============
   1329 */
   1330 #define WCONVEX_EPSILON		0.2f
   1331 
   1332 bool idWinding::PlanesConcave( const idWinding &w2, const idVec3 &normal1, const idVec3 &normal2, float dist1, float dist2 ) const {
   1333 	int i;
   1334 
   1335 	// check if one of the points of winding 1 is at the back of the plane of winding 2
   1336 	for ( i = 0; i < numPoints; i++ ) {
   1337 		if ( normal2 * p[i].ToVec3() - dist2 > WCONVEX_EPSILON ) {
   1338 			return true;
   1339 		}
   1340 	}
   1341 	// check if one of the points of winding 2 is at the back of the plane of winding 1
   1342 	for ( i = 0; i < w2.numPoints; i++ ) {
   1343 		if ( normal1 * w2.p[i].ToVec3() - dist1 > WCONVEX_EPSILON ) {
   1344 			return true;
   1345 		}
   1346 	}
   1347 
   1348 	return false;
   1349 }
   1350 
   1351 /*
   1352 =============
   1353 idWinding::PointInside
   1354 =============
   1355 */
   1356 bool idWinding::PointInside( const idVec3 &normal, const idVec3 &point, const float epsilon ) const {
   1357 	int i;
   1358 	idVec3 dir, n, pointvec;
   1359 
   1360 	for ( i = 0; i < numPoints; i++ ) {
   1361 		dir = p[(i+1) % numPoints].ToVec3() - p[i].ToVec3();
   1362 		pointvec = point - p[i].ToVec3();
   1363 
   1364 		n = dir.Cross( normal );
   1365 
   1366 		if ( pointvec * n < -epsilon ) {
   1367 			return false;
   1368 		}
   1369 	}
   1370 	return true;
   1371 }
   1372 
   1373 /*
   1374 =============
   1375 idWinding::LineIntersection
   1376 =============
   1377 */
   1378 bool idWinding::LineIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &end, bool backFaceCull ) const {
   1379 	float front, back, frac;
   1380 	idVec3 mid;
   1381 
   1382 	front = windingPlane.Distance( start );
   1383 	back = windingPlane.Distance( end );
   1384 
   1385 	// if both points at the same side of the plane
   1386 	if ( front < 0.0f && back < 0.0f ) {
   1387 		return false;
   1388 	}
   1389 
   1390 	if ( front > 0.0f && back > 0.0f ) {
   1391 		return false;
   1392 	}
   1393 
   1394 	// if back face culled
   1395 	if ( backFaceCull && front < 0.0f ) {
   1396 		return false;
   1397 	}
   1398 
   1399 	// get point of intersection with winding plane
   1400 	if ( idMath::Fabs(front - back) < 0.0001f ) {
   1401 		mid = end;
   1402 	}
   1403 	else {
   1404 		frac = front / (front - back);
   1405 		mid[0] = start[0] + (end[0] - start[0]) * frac;
   1406 		mid[1] = start[1] + (end[1] - start[1]) * frac;
   1407 		mid[2] = start[2] + (end[2] - start[2]) * frac;
   1408 	}
   1409 
   1410 	return PointInside( windingPlane.Normal(), mid, 0.0f );
   1411 }
   1412 
   1413 /*
   1414 =============
   1415 idWinding::RayIntersection
   1416 =============
   1417 */
   1418 bool idWinding::RayIntersection( const idPlane &windingPlane, const idVec3 &start, const idVec3 &dir, float &scale, bool backFaceCull ) const {
   1419 	int i;
   1420 	bool side, lastside = false;
   1421 	idPluecker pl1, pl2;
   1422 
   1423 	scale = 0.0f;
   1424 	pl1.FromRay( start, dir );
   1425 	for ( i = 0; i < numPoints; i++ ) {
   1426 		pl2.FromLine( p[i].ToVec3(), p[(i+1)%numPoints].ToVec3() );
   1427 		side = pl1.PermutedInnerProduct( pl2 ) > 0.0f;
   1428 		if ( i && side != lastside ) {
   1429 			return false;
   1430 		}
   1431 		lastside = side;
   1432 	}
   1433 	if ( !backFaceCull || lastside ) {
   1434 		windingPlane.RayIntersection( start, dir, scale );
   1435 		return true;
   1436 	}
   1437 	return false;
   1438 }
   1439 
   1440 /*
   1441 =================
   1442 idWinding::TriangleArea
   1443 =================
   1444 */
   1445 float idWinding::TriangleArea( const idVec3 &a, const idVec3 &b, const idVec3 &c ) {
   1446 	idVec3	v1, v2;
   1447 	idVec3	cross;
   1448 
   1449 	v1 = b - a;
   1450 	v2 = c - a;
   1451 	cross = v1.Cross( v2 );
   1452 	return 0.5f * cross.Length();
   1453 }
   1454 
   1455 
   1456 //===============================================================
   1457 //
   1458 //	idFixedWinding
   1459 //
   1460 //===============================================================
   1461 
   1462 /*
   1463 =============
   1464 idFixedWinding::ReAllocate
   1465 =============
   1466 */
   1467 bool idFixedWinding::ReAllocate( int n, bool keep ) {
   1468 
   1469 	assert( n <= MAX_POINTS_ON_WINDING );
   1470 
   1471 	if ( n > MAX_POINTS_ON_WINDING ) {
   1472 		idLib::common->Printf("WARNING: idFixedWinding -> MAX_POINTS_ON_WINDING overflowed\n");
   1473 		return false;
   1474 	}
   1475 	return true;
   1476 }
   1477 
   1478 /*
   1479 =============
   1480 idFixedWinding::Split
   1481 =============
   1482 */
   1483 int idFixedWinding::Split( idFixedWinding *back, const idPlane &plane, const float epsilon ) {
   1484 	int		counts[3];
   1485 	float	dists[MAX_POINTS_ON_WINDING+4];
   1486 	byte	sides[MAX_POINTS_ON_WINDING+4];
   1487 	float	dot;
   1488 	int		i, j;
   1489 	idVec5 *p1, *p2;
   1490 	idVec5	mid;
   1491 	idFixedWinding out;
   1492 
   1493 	counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
   1494 
   1495 	// determine sides for each point
   1496 	for ( i = 0; i < numPoints; i++ ) {
   1497 		dists[i] = dot = plane.Distance( p[i].ToVec3() );
   1498 		if ( dot > epsilon ) {
   1499 			sides[i] = SIDE_FRONT;
   1500 		} else if ( dot < -epsilon ) {
   1501 			sides[i] = SIDE_BACK;
   1502 		} else {
   1503 			sides[i] = SIDE_ON;
   1504 		}
   1505 		counts[sides[i]]++;
   1506 	}
   1507 
   1508 	if ( !counts[SIDE_BACK] ) {
   1509 		if ( !counts[SIDE_FRONT] ) {
   1510 			return SIDE_ON;
   1511 		}
   1512 		else {
   1513 			return SIDE_FRONT;
   1514 		}
   1515 	}
   1516 	
   1517 	if ( !counts[SIDE_FRONT] ) {
   1518 		return SIDE_BACK;
   1519 	}
   1520 
   1521 	sides[i] = sides[0];
   1522 	dists[i] = dists[0];
   1523 	
   1524 	out.numPoints = 0;
   1525 	back->numPoints = 0;
   1526 
   1527 	for ( i = 0; i < numPoints; i++ ) {
   1528 		p1 = &p[i];
   1529 
   1530 		if ( !out.EnsureAlloced( out.numPoints+1, true ) ) {
   1531 			return SIDE_FRONT;		// can't split -- fall back to original
   1532 		}
   1533 		if ( !back->EnsureAlloced( back->numPoints+1, true ) ) {
   1534 			return SIDE_FRONT;		// can't split -- fall back to original
   1535 		}
   1536 
   1537 		if ( sides[i] == SIDE_ON ) {
   1538 			out.p[out.numPoints] = *p1;
   1539 			out.numPoints++;
   1540 			back->p[back->numPoints] = *p1;
   1541 			back->numPoints++;
   1542 			continue;
   1543 		}
   1544 	
   1545 		if ( sides[i] == SIDE_FRONT ) {
   1546 			out.p[out.numPoints] = *p1;
   1547 			out.numPoints++;
   1548 		}
   1549 		if ( sides[i] == SIDE_BACK ) {
   1550 			back->p[back->numPoints] = *p1;
   1551 			back->numPoints++;
   1552 		}
   1553 		
   1554 		if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
   1555 			continue;
   1556 		}
   1557 			
   1558 		if ( !out.EnsureAlloced( out.numPoints+1, true ) ) {
   1559 			return SIDE_FRONT;		// can't split -- fall back to original
   1560 		}
   1561 
   1562 		if ( !back->EnsureAlloced( back->numPoints+1, true ) ) {
   1563 			return SIDE_FRONT;		// can't split -- fall back to original
   1564 		}
   1565 
   1566 		// generate a split point
   1567 		j = i + 1;
   1568 		if ( j >= numPoints ) {
   1569 			p2 = &p[0];
   1570 		}
   1571 		else {
   1572 			p2 = &p[j];
   1573 		}
   1574 
   1575 		dot = dists[i] / (dists[i] - dists[i+1]);
   1576 		for ( j = 0; j < 3; j++ ) {
   1577 			// avoid round off error when possible
   1578 			if ( plane.Normal()[j] == 1.0f ) {
   1579 				mid[j] = plane.Dist();
   1580 			} else if ( plane.Normal()[j] == -1.0f ) {
   1581 				mid[j] = -plane.Dist();
   1582 			} else {
   1583 				mid[j] = (*p1)[j] + dot * ( (*p2)[j] - (*p1)[j] );
   1584 			}
   1585 		}
   1586 		mid.s = p1->s + dot * ( p2->s - p1->s );
   1587 		mid.t = p1->t + dot * ( p2->t - p1->t );
   1588 			
   1589 		out.p[out.numPoints] = mid;
   1590 		out.numPoints++;
   1591 		back->p[back->numPoints] = mid;
   1592 		back->numPoints++;
   1593 	}
   1594 	for ( i = 0; i < out.numPoints; i++ ) {
   1595 		p[i] = out.p[i];
   1596 	}
   1597 	numPoints = out.numPoints;
   1598 
   1599 	return SIDE_CROSS;
   1600 }