Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

Winding.cpp (16776B)


      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 
     24 #include "stdafx.h"
     25 #include <assert.h>
     26 #include "qe3.h"
     27 #include "winding.h"
     28 
     29 #define	BOGUS_RANGE	18000
     30 
     31 /*
     32 =============
     33 Plane_Equal
     34 =============
     35 */
     36 #define	NORMAL_EPSILON	0.0001
     37 #define	DIST_EPSILON	0.02
     38 
     39 int Plane_Equal(plane_t *a, plane_t *b, int flip)
     40 {
     41 	vec3_t normal;
     42 	float dist;
     43 
     44 	if (flip) {
     45 		normal[0] = - b->normal[0];
     46 		normal[1] = - b->normal[1];
     47 		normal[2] = - b->normal[2];
     48 		dist = - b->dist;
     49 	}
     50 	else {
     51 		normal[0] = b->normal[0];
     52 		normal[1] = b->normal[1];
     53 		normal[2] = b->normal[2];
     54 		dist = b->dist;
     55 	}
     56 	if (
     57 	   fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
     58 	&& fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
     59 	&& fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
     60 	&& fabs(a->dist - dist) < DIST_EPSILON )
     61 		return true;
     62 	return false;
     63 }
     64 
     65 /*
     66 ============
     67 Plane_FromPoints
     68 ============
     69 */
     70 int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane)
     71 {
     72 	vec3_t v1, v2;
     73 
     74 	VectorSubtract(p2, p1, v1);
     75 	VectorSubtract(p3, p1, v2);
     76 	//CrossProduct(v2, v1, plane->normal);
     77 	CrossProduct(v1, v2, plane->normal);
     78 	if (VectorNormalize(plane->normal) < 0.1) return false;
     79 	plane->dist = DotProduct(p1, plane->normal);
     80 	return true;
     81 }
     82 
     83 /*
     84 =================
     85 Point_Equal
     86 =================
     87 */
     88 int Point_Equal(vec3_t p1, vec3_t p2, float epsilon)
     89 {
     90 	int i;
     91 
     92 	for (i = 0; i < 3; i++)
     93 	{
     94 		if (fabs(p1[i] - p2[i]) > epsilon) return false;
     95 	}
     96 	return true;
     97 }
     98 
     99 
    100 /*
    101 =================
    102 Winding_BaseForPlane
    103 =================
    104 */
    105 winding_t *Winding_BaseForPlane (plane_t *p)
    106 {
    107 	int		i, x;
    108 	vec_t	max, v;
    109 	vec3_t	org, vright, vup;
    110 	winding_t	*w;
    111 	
    112 	// find the major axis
    113 
    114 	max = -BOGUS_RANGE;
    115 	x = -1;
    116 	for (i=0 ; i<3; i++)
    117 	{
    118 		v = fabs(p->normal[i]);
    119 		if (v > max)
    120 		{
    121 			x = i;
    122 			max = v;
    123 		}
    124 	}
    125 	if (x==-1)
    126 		Error ("Winding_BaseForPlane: no axis found");
    127 		
    128 	VectorCopy (vec3_origin, vup);	
    129 	switch (x)
    130 	{
    131 	case 0:
    132 	case 1:
    133 		vup[2] = 1;
    134 		break;		
    135 	case 2:
    136 		vup[0] = 1;
    137 		break;		
    138 	}
    139 
    140 
    141 	v = DotProduct (vup, p->normal);
    142 	VectorMA (vup, -v, p->normal, vup);
    143 	VectorNormalize (vup);
    144 		
    145 	VectorScale (p->normal, p->dist, org);
    146 	
    147 	CrossProduct (vup, p->normal, vright);
    148 	
    149 	VectorScale (vup, BOGUS_RANGE, vup);
    150 	VectorScale (vright, BOGUS_RANGE, vright);
    151 
    152 	// project a really big	axis aligned box onto the plane
    153 	w = Winding_Alloc (4);
    154 	
    155 	VectorSubtract (org, vright, w->points[0]);
    156 	VectorAdd (w->points[0], vup, w->points[0]);
    157 	
    158 	VectorAdd (org, vright, w->points[1]);
    159 	VectorAdd (w->points[1], vup, w->points[1]);
    160 	
    161 	VectorAdd (org, vright, w->points[2]);
    162 	VectorSubtract (w->points[2], vup, w->points[2]);
    163 	
    164 	VectorSubtract (org, vright, w->points[3]);
    165 	VectorSubtract (w->points[3], vup, w->points[3]);
    166 	
    167 	w->numpoints = 4;
    168 	
    169 	return w;	
    170 }
    171 
    172 /*
    173 ==================
    174 Winding_Alloc
    175 ==================
    176 */
    177 winding_t *Winding_Alloc (int points)
    178 {
    179 	winding_t	*w;
    180 	int			size;
    181 	
    182 	if (points > MAX_POINTS_ON_WINDING)
    183 		Error ("Winding_Alloc: %i points", points);
    184 	
    185 	size = (int)((winding_t *)0)->points[points];
    186 	w = (winding_t*) malloc (size);
    187 	memset (w, 0, size);
    188 	w->maxpoints = points;
    189 	
    190 	return w;
    191 }
    192 
    193 
    194 void Winding_Free (winding_t *w)
    195 {
    196 	free(w);
    197 }
    198 
    199 
    200 /*
    201 ==================
    202 Winding_Clone
    203 ==================
    204 */
    205 winding_t *Winding_Clone(winding_t *w)
    206 {
    207 	int			size;
    208 	winding_t	*c;
    209 	
    210 	size = (int)((winding_t *)0)->points[w->numpoints];
    211 	c = (winding_t*)qmalloc (size);
    212 	memcpy (c, w, size);
    213 	return c;
    214 }
    215 
    216 /*
    217 ==================
    218 ReverseWinding
    219 ==================
    220 */
    221 winding_t *Winding_Reverse(winding_t *w)
    222 {
    223 	int			i;
    224 	winding_t	*c;
    225 
    226 	c = Winding_Alloc(w->numpoints);
    227 	for (i = 0; i < w->numpoints; i++)
    228 	{
    229 		VectorCopy (w->points[w->numpoints-1-i], c->points[i]);
    230 	}
    231 	c->numpoints = w->numpoints;
    232 	return c;
    233 }
    234 
    235 
    236 /*
    237 ==============
    238 Winding_RemovePoint
    239 ==============
    240 */
    241 void Winding_RemovePoint(winding_t *w, int point)
    242 {
    243 	if (point < 0 || point >= w->numpoints)
    244 		Error("Winding_RemovePoint: point out of range");
    245 
    246 	if (point < w->numpoints-1)
    247 	{
    248 		memmove(&w->points[point], &w->points[point+1], (int)((winding_t *)0)->points[w->numpoints - point - 1]);
    249 	}
    250 	w->numpoints--;
    251 }
    252 
    253 /*
    254 =============
    255 Winding_InsertPoint
    256 =============
    257 */
    258 winding_t *Winding_InsertPoint(winding_t *w, vec3_t point, int spot)
    259 {
    260 	int i, j;
    261 	winding_t *neww;
    262 
    263 	if (spot > w->numpoints)
    264 	{
    265 		Error("Winding_InsertPoint: spot > w->numpoints");
    266 	} //end if
    267 	if (spot < 0)
    268 	{
    269 		Error("Winding_InsertPoint: spot < 0");
    270 	} //end if
    271 	neww = Winding_Alloc(w->numpoints + 1);
    272 	neww->numpoints = w->numpoints + 1;
    273 	for (i = 0, j = 0; i < neww->numpoints; i++)
    274 	{
    275 		if (i == spot)
    276 		{
    277 			VectorCopy(point, neww->points[i]);
    278 		}
    279 		else
    280 		{
    281 			VectorCopy(w->points[j], neww->points[i]);
    282 			j++;
    283 		}
    284 	}
    285 	return neww;
    286 }
    287 
    288 /*
    289 ==============
    290 Winding_IsTiny
    291 ==============
    292 */
    293 #define	EDGE_LENGTH	0.2
    294 
    295 int Winding_IsTiny (winding_t *w)
    296 {
    297 	int		i, j;
    298 	vec_t	len;
    299 	vec3_t	delta;
    300 	int		edges;
    301 
    302 	edges = 0;
    303 	for (i=0 ; i<w->numpoints ; i++)
    304 	{
    305 		j = i == w->numpoints - 1 ? 0 : i+1;
    306 		VectorSubtract (w->points[j], w->points[i], delta);
    307 		len = VectorLength (delta);
    308 		if (len > EDGE_LENGTH)
    309 		{
    310 			if (++edges == 3)
    311 				return false;
    312 		}
    313 	}
    314 	return true;
    315 }
    316 
    317 /*
    318 ==============
    319 Winding_IsHuge
    320 ==============
    321 */
    322 int Winding_IsHuge(winding_t *w)
    323 {
    324 	int		i, j;
    325 
    326 	for (i=0 ; i<w->numpoints ; i++)
    327 	{
    328 		for (j=0 ; j<3 ; j++)
    329 			if (w->points[i][j] < -BOGUS_RANGE+1 || w->points[i][j] > BOGUS_RANGE-1)
    330 				return true;
    331 	}
    332 	return false;
    333 }
    334 
    335 /*
    336 =============
    337 Winding_PlanesConcave
    338 =============
    339 */
    340 #define WCONVEX_EPSILON		0.2
    341 
    342 int Winding_PlanesConcave(winding_t *w1, winding_t *w2,
    343 							 vec3_t normal1, vec3_t normal2,
    344 							 float dist1, float dist2)
    345 {
    346 	int i;
    347 
    348 	if (!w1 || !w2) return false;
    349 
    350 	// check if one of the points of winding 1 is at the back of the plane of winding 2
    351 	for (i = 0; i < w1->numpoints; i++)
    352 	{
    353 		if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return true;
    354 	}
    355 	// check if one of the points of winding 2 is at the back of the plane of winding 1
    356 	for (i = 0; i < w2->numpoints; i++)
    357 	{
    358 		if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return true;
    359 	}
    360 
    361 	return false;
    362 }
    363 
    364 /*
    365 ==================
    366 Winding_Clip
    367 
    368 Clips the winding to the plane, returning the new winding on the positive side
    369 Frees the input winding.
    370 If keepon is true, an exactly on-plane winding will be saved, otherwise
    371 it will be clipped away.
    372 ==================
    373 */
    374 winding_t *Winding_Clip (winding_t *in, plane_t *split, qboolean keepon)
    375 {
    376 	vec_t	dists[MAX_POINTS_ON_WINDING];
    377 	int		sides[MAX_POINTS_ON_WINDING];
    378 	int		counts[3];
    379 	vec_t	dot;
    380 	int		i, j;
    381 	vec_t	*p1, *p2;
    382 	vec3_t	mid;
    383 	winding_t	*neww;
    384 	int		maxpts;
    385 	
    386 	counts[0] = counts[1] = counts[2] = 0;
    387 
    388 	// determine sides for each point
    389 	for (i=0 ; i<in->numpoints ; i++)
    390 	{
    391 		dot = DotProduct (in->points[i], split->normal);
    392 		dot -= split->dist;
    393 		dists[i] = dot;
    394 		if (dot > ON_EPSILON)
    395 			sides[i] = SIDE_FRONT;
    396 		else if (dot < -ON_EPSILON)
    397 			sides[i] = SIDE_BACK;
    398 		else
    399 		{
    400 			sides[i] = SIDE_ON;
    401 		}
    402 		counts[sides[i]]++;
    403 	}
    404 	sides[i] = sides[0];
    405 	dists[i] = dists[0];
    406 	
    407 	if (keepon && !counts[0] && !counts[1])
    408 		return in;
    409 		
    410 	if (!counts[0])
    411 	{
    412 		Winding_Free (in);
    413 		return NULL;
    414 	}
    415 	if (!counts[1])
    416 		return in;
    417 	
    418 	maxpts = in->numpoints+4;	// can't use counts[0]+2 because
    419 								// of fp grouping errors
    420 	neww = Winding_Alloc (maxpts);
    421 		
    422 	for (i=0 ; i<in->numpoints ; i++)
    423 	{
    424 		p1 = in->points[i];
    425 		
    426 		if (sides[i] == SIDE_ON)
    427 		{
    428 			VectorCopy (p1, neww->points[neww->numpoints]);
    429 			neww->numpoints++;
    430 			continue;
    431 		}
    432 	
    433 		if (sides[i] == SIDE_FRONT)
    434 		{
    435 			VectorCopy (p1, neww->points[neww->numpoints]);
    436 			neww->numpoints++;
    437 		}
    438 		
    439 		if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
    440 			continue;
    441 			
    442 		// generate a split point
    443 		p2 = in->points[(i+1)%in->numpoints];
    444 		
    445 		dot = dists[i] / (dists[i]-dists[i+1]);
    446 		for (j=0 ; j<3 ; j++)
    447 		{	// avoid round off error when possible
    448 			if (split->normal[j] == 1)
    449 				mid[j] = split->dist;
    450 			else if (split->normal[j] == -1)
    451 				mid[j] = -split->dist;
    452 			else
    453 				mid[j] = p1[j] + dot*(p2[j]-p1[j]);
    454 		}
    455 			
    456 		VectorCopy (mid, neww->points[neww->numpoints]);
    457 		neww->numpoints++;
    458 	}
    459 	
    460 	if (neww->numpoints > maxpts)
    461 		Error ("Winding_Clip: points exceeded estimate");
    462 		
    463 	// free the original winding
    464 	Winding_Free (in);
    465 	
    466 	return neww;
    467 }
    468 
    469 /*
    470 =============
    471 Winding_SplitEpsilon
    472 
    473   split the input winding with the plane
    474   the input winding stays untouched
    475 =============
    476 */
    477 void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist, 
    478 				vec_t epsilon, winding_t **front, winding_t **back)
    479 {
    480 	vec_t	dists[MAX_POINTS_ON_WINDING+4];
    481 	int		sides[MAX_POINTS_ON_WINDING+4];
    482 	int		counts[3];
    483 	vec_t	dot;
    484 	int		i, j;
    485 	vec_t	*p1, *p2;
    486 	vec3_t	mid;
    487 	winding_t	*f, *b;
    488 	int		maxpts;
    489 	
    490 	counts[0] = counts[1] = counts[2] = 0;
    491 
    492 	// determine sides for each point
    493 	for (i = 0; i < in->numpoints; i++)
    494 	{
    495 		dot = DotProduct (in->points[i], normal);
    496 		dot -= dist;
    497 		dists[i] = dot;
    498 		if (dot > epsilon)
    499 			sides[i] = SIDE_FRONT;
    500 		else if (dot < -epsilon)
    501 			sides[i] = SIDE_BACK;
    502 		else
    503 		{
    504 			sides[i] = SIDE_ON;
    505 		}
    506 		counts[sides[i]]++;
    507 	}
    508 	sides[i] = sides[0];
    509 	dists[i] = dists[0];
    510 	
    511 	*front = *back = NULL;
    512 
    513 	if (!counts[0])
    514 	{
    515 		*back = Winding_Clone(in);
    516 		return;
    517 	}
    518 	if (!counts[1])
    519 	{
    520 		*front = Winding_Clone(in);
    521 		return;
    522 	}
    523 
    524 	maxpts = in->numpoints+4;	// cant use counts[0]+2 because
    525 								// of fp grouping errors
    526 
    527 	*front = f = Winding_Alloc (maxpts);
    528 	*back = b = Winding_Alloc (maxpts);
    529 		
    530 	for (i = 0; i < in->numpoints; i++)
    531 	{
    532 		p1 = in->points[i];
    533 		
    534 		if (sides[i] == SIDE_ON)
    535 		{
    536 			VectorCopy (p1, f->points[f->numpoints]);
    537 			f->numpoints++;
    538 			VectorCopy (p1, b->points[b->numpoints]);
    539 			b->numpoints++;
    540 			continue;
    541 		}
    542 	
    543 		if (sides[i] == SIDE_FRONT)
    544 		{
    545 			VectorCopy (p1, f->points[f->numpoints]);
    546 			f->numpoints++;
    547 		}
    548 		if (sides[i] == SIDE_BACK)
    549 		{
    550 			VectorCopy (p1, b->points[b->numpoints]);
    551 			b->numpoints++;
    552 		}
    553 
    554 		if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
    555 			continue;
    556 			
    557 		// generate a split point
    558 		p2 = in->points[(i+1)%in->numpoints];
    559 		
    560 		dot = dists[i] / (dists[i]-dists[i+1]);
    561 		for (j = 0; j < 3; j++)
    562 		{
    563 			// avoid round off error when possible
    564 			if (normal[j] == 1)
    565 				mid[j] = dist;
    566 			else if (normal[j] == -1)
    567 				mid[j] = -dist;
    568 			else
    569 				mid[j] = p1[j] + dot*(p2[j]-p1[j]);
    570 		}
    571 			
    572 		VectorCopy (mid, f->points[f->numpoints]);
    573 		f->numpoints++;
    574 		VectorCopy (mid, b->points[b->numpoints]);
    575 		b->numpoints++;
    576 	}
    577 	
    578 	if (f->numpoints > maxpts || b->numpoints > maxpts)
    579 		Error ("Winding_Clip: points exceeded estimate");
    580 	if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
    581 		Error ("Winding_Clip: MAX_POINTS_ON_WINDING");
    582 }
    583 
    584 /*
    585 =============
    586 Winding_TryMerge
    587 
    588 If two windings share a common edge and the edges that meet at the
    589 common points are both inside the other polygons, merge them
    590 
    591 Returns NULL if the windings couldn't be merged, or the new winding.
    592 The originals will NOT be freed.
    593 
    594 if keep is true no points are ever removed
    595 =============
    596 */
    597 #define	CONTINUOUS_EPSILON	0.005
    598 
    599 winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep)
    600 {
    601 	vec_t		*p1, *p2, *p3, *p4, *back;
    602 	winding_t	*newf;
    603 	int			i, j, k, l;
    604 	vec3_t		normal, delta;
    605 	vec_t		dot;
    606 	qboolean	keep1, keep2;
    607 	
    608 
    609 	//
    610 	// find a common edge
    611 	//	
    612 	p1 = p2 = NULL;	// stop compiler warning
    613 	j = 0;			// 
    614 	
    615 	for (i = 0; i < f1->numpoints; i++)
    616 	{
    617 		p1 = f1->points[i];
    618 		p2 = f1->points[(i+1) % f1->numpoints];
    619 		for (j = 0; j < f2->numpoints; j++)
    620 		{
    621 			p3 = f2->points[j];
    622 			p4 = f2->points[(j+1) % f2->numpoints];
    623 			for (k = 0; k < 3; k++)
    624 			{
    625 				if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
    626 					break;
    627 				if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
    628 					break;
    629 			} //end for
    630 			if (k==3)
    631 				break;
    632 		} //end for
    633 		if (j < f2->numpoints)
    634 			break;
    635 	} //end for
    636 	
    637 	if (i == f1->numpoints)
    638 		return NULL;			// no matching edges
    639 
    640 	//
    641 	// check slope of connected lines
    642 	// if the slopes are colinear, the point can be removed
    643 	//
    644 	back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
    645 	VectorSubtract (p1, back, delta);
    646 	CrossProduct (planenormal, delta, normal);
    647 	VectorNormalize (normal);
    648 	
    649 	back = f2->points[(j+2)%f2->numpoints];
    650 	VectorSubtract (back, p1, delta);
    651 	dot = DotProduct (delta, normal);
    652 	if (dot > CONTINUOUS_EPSILON)
    653 		return NULL;			// not a convex polygon
    654 	keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
    655 	
    656 	back = f1->points[(i+2)%f1->numpoints];
    657 	VectorSubtract (back, p2, delta);
    658 	CrossProduct (planenormal, delta, normal);
    659 	VectorNormalize (normal);
    660 
    661 	back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
    662 	VectorSubtract (back, p2, delta);
    663 	dot = DotProduct (delta, normal);
    664 	if (dot > CONTINUOUS_EPSILON)
    665 		return NULL;			// not a convex polygon
    666 	keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
    667 
    668 	//
    669 	// build the new polygon
    670 	//
    671 	newf = Winding_Alloc (f1->numpoints + f2->numpoints);
    672 	
    673 	// copy first polygon
    674 	for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
    675 	{
    676 		if (!keep && k==(i+1)%f1->numpoints && !keep2)
    677 			continue;
    678 		
    679 		VectorCopy (f1->points[k], newf->points[newf->numpoints]);
    680 		newf->numpoints++;
    681 	}
    682 	
    683 	// copy second polygon
    684 	for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
    685 	{
    686 		if (!keep && l==(j+1)%f2->numpoints && !keep1)
    687 			continue;
    688 		VectorCopy (f2->points[l], newf->points[newf->numpoints]);
    689 		newf->numpoints++;
    690 	}
    691 
    692 	return newf;
    693 }
    694 
    695 /*
    696 ============
    697 Winding_Plane
    698 ============
    699 */
    700 void Winding_Plane (winding_t *w, vec3_t normal, double *dist)
    701 {
    702 	vec3_t v1, v2;
    703 	int i;
    704 
    705 	//find two vectors each longer than 0.5 units
    706 	for (i = 0; i < w->numpoints; i++)
    707 	{
    708 		VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1);
    709 		VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2);
    710 		if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
    711 	}
    712 	CrossProduct(v2, v1, normal);
    713 	VectorNormalize(normal);
    714 	*dist = DotProduct(w->points[0], normal);
    715 }
    716 
    717 /*
    718 =============
    719 Winding_Area
    720 =============
    721 */
    722 float Winding_Area (winding_t *w)
    723 {
    724 	int		i;
    725 	vec3_t	d1, d2, cross;
    726 	float	total;
    727 
    728 	total = 0;
    729 	for (i=2 ; i<w->numpoints ; i++)
    730 	{
    731 		VectorSubtract (w->points[i-1], w->points[0], d1);
    732 		VectorSubtract (w->points[i], w->points[0], d2);
    733 		CrossProduct (d1, d2, cross);
    734 		total += 0.5 * VectorLength ( cross );
    735 	}
    736 	return total;
    737 }
    738 
    739 /*
    740 =============
    741 Winding_Bounds
    742 =============
    743 */
    744 void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs)
    745 {
    746 	vec_t	v;
    747 	int		i,j;
    748 
    749 	mins[0] = mins[1] = mins[2] = 99999;
    750 	maxs[0] = maxs[1] = maxs[2] = -99999;
    751 
    752 	for (i=0 ; i<w->numpoints ; i++)
    753 	{
    754 		for (j=0 ; j<3 ; j++)
    755 		{
    756 			v = w->points[i][j];
    757 			if (v < mins[j])
    758 				mins[j] = v;
    759 			if (v > maxs[j])
    760 				maxs[j] = v;
    761 		}
    762 	}
    763 }
    764 
    765 
    766 /*
    767 =================
    768 Winding_PointInside
    769 =================
    770 */
    771 int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon)
    772 {
    773 	int i;
    774 	vec3_t dir, normal, pointvec;
    775 
    776 	for (i = 0; i < w->numpoints; i++)
    777 	{
    778 		VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir);
    779 		VectorSubtract(point, w->points[i], pointvec);
    780 		//
    781 		CrossProduct(dir, plane->normal, normal);
    782 		//
    783 		if (DotProduct(pointvec, normal) < -epsilon) return false;
    784 	}
    785 	return true;
    786 }
    787 
    788 /*
    789 =================
    790 Winding_VectorIntersect
    791 =================
    792 */
    793 int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon)
    794 {
    795 	float front, back, frac;
    796 	vec3_t mid;
    797 
    798 	front = DotProduct(p1, plane->normal) - plane->dist;
    799 	back = DotProduct(p2, plane->normal) - plane->dist;
    800 	//if both points at the same side of the plane
    801 	if (front < -epsilon && back < -epsilon) return false;
    802 	if (front > epsilon && back > epsilon) return false;
    803 	//get point of intersection with winding plane
    804 	if (fabs(front-back) < 0.001)
    805 	{
    806 		VectorCopy(p2, mid);
    807 	}
    808 	else
    809 	{
    810 		frac = front/(front-back);
    811 		mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
    812 		mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
    813 		mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
    814 	}
    815 	return Winding_PointInside(w, plane, mid, epsilon);
    816 }
    817