]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/polylib.c
7d5b8a83c8056a900b3280d28b0a22711af956b0
[xonotic/netradiant.git] / tools / quake3 / common / polylib.c
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 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 GtkRadiant; 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 "cmdlib.h"
24 #include "mathlib.h"
25 #include "inout.h"
26 #include "polylib.h"
27 #include "qfiles.h"
28
29
30 extern int numthreads;
31
32 // counters are only bumped when running single threaded,
33 // because they are an awefull coherence problem
34 int     c_active_windings;
35 int     c_peak_windings;
36 int     c_winding_allocs;
37 int     c_winding_points;
38
39 #define BOGUS_RANGE     WORLD_SIZE
40
41 void pw(winding_t *w)
42 {
43         int             i;
44         for (i=0 ; i<w->numpoints ; i++)
45                 Sys_Printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
46 }
47
48
49 /*
50 =============
51 AllocWinding
52 =============
53 */
54 winding_t       *AllocWinding (int points)
55 {
56         winding_t       *w;
57         int                     s;
58
59   if (points >= MAX_POINTS_ON_WINDING)
60     Error ("AllocWinding failed: MAX_POINTS_ON_WINDING exceeded");
61
62         if (numthreads == 1)
63         {
64                 c_winding_allocs++;
65                 c_winding_points += points;
66                 c_active_windings++;
67                 if (c_active_windings > c_peak_windings)
68                         c_peak_windings = c_active_windings;
69         }
70         s = sizeof(vec_t)*3*points + sizeof(int);
71         w = safe_malloc (s);
72         memset (w, 0, s); 
73         return w;
74 }
75
76 void FreeWinding (winding_t *w)
77 {
78         if (*(unsigned *)w == 0xdeaddead)
79                 Error ("FreeWinding: freed a freed winding");
80         *(unsigned *)w = 0xdeaddead;
81
82         if (numthreads == 1)
83                 c_active_windings--;
84         free (w);
85 }
86
87 /*
88 ============
89 RemoveColinearPoints
90 ============
91 */
92 int     c_removed;
93
94 void    RemoveColinearPoints (winding_t *w)
95 {
96         int             i, j, k;
97         vec3_t  v1, v2;
98         int             nump;
99         vec3_t  p[MAX_POINTS_ON_WINDING];
100
101         nump = 0;
102         for (i=0 ; i<w->numpoints ; i++)
103         {
104                 j = (i+1)%w->numpoints;
105                 k = (i+w->numpoints-1)%w->numpoints;
106                 VectorSubtract (w->p[j], w->p[i], v1);
107                 VectorSubtract (w->p[i], w->p[k], v2);
108                 VectorNormalize(v1,v1);
109                 VectorNormalize(v2,v2);
110                 if (DotProduct(v1, v2) < 0.999)
111                 {
112                         VectorCopy (w->p[i], p[nump]);
113                         nump++;
114                 }
115         }
116
117         if (nump == w->numpoints)
118                 return;
119
120         if (numthreads == 1)
121                 c_removed += w->numpoints - nump;
122         w->numpoints = nump;
123         memcpy (w->p, p, nump*sizeof(p[0]));
124 }
125
126 /*
127 ============
128 WindingPlane
129 ============
130 */
131 void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
132 {
133         vec3_t  v1, v2;
134
135         VectorSubtract (w->p[1], w->p[0], v1);
136         VectorSubtract (w->p[2], w->p[0], v2);
137         CrossProduct (v2, v1, normal);
138         VectorNormalize (normal, normal);
139         *dist = DotProduct (w->p[0], normal);
140
141 }
142
143 /*
144 =============
145 WindingArea
146 =============
147 */
148 vec_t   WindingArea (winding_t *w)
149 {
150         int             i;
151         vec3_t  d1, d2, cross;
152         vec_t   total;
153
154         total = 0;
155         for (i=2 ; i<w->numpoints ; i++)
156         {
157                 VectorSubtract (w->p[i-1], w->p[0], d1);
158                 VectorSubtract (w->p[i], w->p[0], d2);
159                 CrossProduct (d1, d2, cross);
160                 total += 0.5 * VectorLength ( cross );
161         }
162         return total;
163 }
164
165 void    WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
166 {
167         vec_t   v;
168         int             i,j;
169
170         mins[0] = mins[1] = mins[2] = 99999;
171         maxs[0] = maxs[1] = maxs[2] = -99999;
172
173         for (i=0 ; i<w->numpoints ; i++)
174         {
175                 for (j=0 ; j<3 ; j++)
176                 {
177                         v = w->p[i][j];
178                         if (v < mins[j])
179                                 mins[j] = v;
180                         if (v > maxs[j])
181                                 maxs[j] = v;
182                 }
183         }
184 }
185
186 /*
187 =============
188 WindingCenter
189 =============
190 */
191 void    WindingCenter (winding_t *w, vec3_t center)
192 {
193         int             i;
194         float   scale;
195
196         VectorCopy (vec3_origin, center);
197         for (i=0 ; i<w->numpoints ; i++)
198                 VectorAdd (w->p[i], center, center);
199
200         scale = 1.0/w->numpoints;
201         VectorScale (center, scale, center);
202 }
203
204 /*
205 =================
206 BaseWindingForPlane
207 =================
208 */
209 winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
210 {
211         // The goal in this function is to replicate the exact behavior that was in the original
212         // BaseWindingForPlane() function (see below).  The only thing we're going to change is the
213         // accuracy of the operation.  The original code gave a preference for the vup vector to start
214         // out as (0, 0, 1), unless the normal had a dominant Z value, in which case vup started out
215         // as (1, 0, 0).  After that, vup was "bent" [along the plane defined by normal and vup] to
216         // become perpendicular to normal.  After that the vright vector was computed as the cross
217         // product of vup and normal.
218
219         // Once these vectors are calculated, I'm constructing the winding points in exactly the same
220         // way as was done in the original function.  Orientation is the same.
221
222         // Note that the 4 points in the returned winding_t may actually not be necessary (3 might
223         // be enough).  However, I want to minimize the chance of ANY bugs popping up due to any
224         // change in behavior of this function.  Therefore, behavior stays exactly the same, except
225         // for precision of math.  Performance might be better in the new function as well.
226
227         int             x, i;
228         vec_t           max, v;
229         vec3_t          vright, vup, org;
230         winding_t       *w;
231
232         max = -BOGUS_RANGE;
233         x = -1;
234         for (i = 0; i < 3; i++) {
235                 v = fabs(normal[i]);
236                 if (v > max) {
237                         x = i;
238                         max = v;
239                 }
240         }
241         if (x == -1) Error("BaseWindingForPlane: no axis found");
242
243         switch (x) {
244                 case 0: // Fall through to next case.
245                 case 1:
246                         vright[0] = -normal[1];
247                         vright[1] = normal[0];
248                         vright[2] = 0;
249                         break;
250                 case 2:
251                         vright[0] = 0;
252                         vright[1] = -normal[2];
253                         vright[2] = normal[1];
254                         break;
255         }
256         // NOTE: vright is NOT a unit vector at this point.
257         VectorSetLength(vright, MAX_WORLD_COORD * 2, vright);
258         CrossProduct(normal, vright, vup);
259         VectorScale(normal, dist, org);
260
261         w = AllocWinding(4);
262
263         VectorSubtract(org, vright, w->p[0]);
264         VectorAdd(w->p[0], vup, w->p[0]);
265
266         VectorAdd(org, vright, w->p[1]);
267         VectorAdd(w->p[1], vup, w->p[1]);
268
269         VectorAdd(org, vright, w->p[2]);
270         VectorSubtract(w->p[2], vup, w->p[2]);
271
272         VectorSubtract(org, vright, w->p[3]);
273         VectorSubtract(w->p[3], vup, w->p[3]);
274
275         w->numpoints = 4;
276
277         return w;
278 }
279
280 // Old function, not used but here for reference.  Please do not modify it.
281 // (You may remove it at some point.)
282 winding_t *_BaseWindingForPlane_orig_(vec3_t normal, vec_t dist)
283 {
284         int             i, x;
285         vec_t   max, v;
286         vec3_t  org, vright, vup;
287         winding_t       *w;
288         
289 // find the major axis
290
291         max = -BOGUS_RANGE;
292         x = -1;
293         for (i=0 ; i<3; i++)
294         {
295                 v = fabs(normal[i]);
296                 if (v > max)
297                 {
298                         x = i;
299                         max = v;
300                 }
301         }
302         if (x==-1)
303                 Error ("BaseWindingForPlane: no axis found");
304                 
305         VectorCopy (vec3_origin, vup);  
306         switch (x)
307         {
308         case 0:
309         case 1:
310                 vup[2] = 1;
311                 break;          
312         case 2:
313                 vup[0] = 1;
314                 break;          
315         }
316
317         v = DotProduct (vup, normal);
318         VectorMA (vup, -v, normal, vup);
319         VectorNormalize (vup, vup);
320                 
321         VectorScale (normal, dist, org);
322         
323         CrossProduct (vup, normal, vright);
324         
325         // LordHavoc: this has to use *2 because otherwise some created points may
326         // be inside the world (think of a diagonal case), and any brush with such
327         // points should be removed, failure to detect such cases is disasterous
328         VectorScale (vup, MAX_WORLD_COORD*2, vup);
329         VectorScale (vright, MAX_WORLD_COORD*2, vright);
330
331   // project a really big       axis aligned box onto the plane
332         w = AllocWinding (4);
333         
334         VectorSubtract (org, vright, w->p[0]);
335         VectorAdd (w->p[0], vup, w->p[0]);
336         
337         VectorAdd (org, vright, w->p[1]);
338         VectorAdd (w->p[1], vup, w->p[1]);
339         
340         VectorAdd (org, vright, w->p[2]);
341         VectorSubtract (w->p[2], vup, w->p[2]);
342         
343         VectorSubtract (org, vright, w->p[3]);
344         VectorSubtract (w->p[3], vup, w->p[3]);
345         
346         w->numpoints = 4;
347         
348         return w;       
349 }
350
351 /*
352 ==================
353 CopyWinding
354 ==================
355 */
356 winding_t       *CopyWinding (winding_t *w)
357 {
358         size_t                  size;
359         winding_t       *c;
360
361         c = AllocWinding (w->numpoints);
362         size = (size_t)((winding_t *)NULL)->p[w->numpoints];
363         memcpy (c, w, size);
364         return c;
365 }
366
367 /*
368 ==================
369 ReverseWinding
370 ==================
371 */
372 winding_t       *ReverseWinding (winding_t *w)
373 {
374         int                     i;
375         winding_t       *c;
376
377         c = AllocWinding (w->numpoints);
378         for (i=0 ; i<w->numpoints ; i++)
379         {
380                 VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
381         }
382         c->numpoints = w->numpoints;
383         return c;
384 }
385
386
387 /*
388 =============
389 ClipWindingEpsilon
390 =============
391 */
392 void    ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, 
393                                 vec_t epsilon, winding_t **front, winding_t **back)
394 {
395         vec_t   dists[MAX_POINTS_ON_WINDING+4];
396         int             sides[MAX_POINTS_ON_WINDING+4];
397         int             counts[3];
398         static  vec_t   dot;            // VC 4.2 optimizer bug if not static
399         int             i, j;
400         vec_t   *p1, *p2;
401         vec3_t  mid;
402         winding_t       *f, *b;
403         int             maxpts;
404         
405         counts[0] = counts[1] = counts[2] = 0;
406
407 // determine sides for each point
408         for (i=0 ; i<in->numpoints ; i++)
409   {
410
411                 dot = DotProduct (in->p[i], normal);
412                 dot -= dist;
413                 dists[i] = dot;
414                 if (dot > epsilon)
415                         sides[i] = SIDE_FRONT;
416                 else if (dot < -epsilon)
417                         sides[i] = SIDE_BACK;
418                 else
419                 {
420                         sides[i] = SIDE_ON;
421                 }
422                 counts[sides[i]]++;
423         }
424         sides[i] = sides[0];
425         dists[i] = dists[0];
426         
427         *front = *back = NULL;
428
429         if (!counts[0])
430         {
431                 *back = CopyWinding (in);
432                 return;
433         }
434         if (!counts[1])
435         {
436                 *front = CopyWinding (in);
437                 return;
438         }
439
440         maxpts = in->numpoints+4;       // cant use counts[0]+2 because
441                                                                 // of fp grouping errors
442
443         *front = f = AllocWinding (maxpts);
444         *back = b = AllocWinding (maxpts);
445                 
446         for (i=0 ; i<in->numpoints ; i++)
447         {
448                 p1 = in->p[i];
449                 
450                 if (sides[i] == SIDE_ON)
451                 {
452                         VectorCopy (p1, f->p[f->numpoints]);
453                         f->numpoints++;
454                         VectorCopy (p1, b->p[b->numpoints]);
455                         b->numpoints++;
456                         continue;
457                 }
458         
459                 if (sides[i] == SIDE_FRONT)
460                 {
461                         VectorCopy (p1, f->p[f->numpoints]);
462                         f->numpoints++;
463                 }
464                 if (sides[i] == SIDE_BACK)
465                 {
466                         VectorCopy (p1, b->p[b->numpoints]);
467                         b->numpoints++;
468                 }
469
470                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
471                         continue;
472                         
473         // generate a split point
474                 p2 = in->p[(i+1)%in->numpoints];
475                 
476                 dot = dists[i] / (dists[i]-dists[i+1]);
477                 for (j=0 ; j<3 ; j++)
478                 {       // avoid round off error when possible
479                         if (normal[j] == 1)
480                                 mid[j] = dist;
481                         else if (normal[j] == -1)
482                                 mid[j] = -dist;
483                         else
484                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
485                 }
486                         
487                 VectorCopy (mid, f->p[f->numpoints]);
488                 f->numpoints++;
489                 VectorCopy (mid, b->p[b->numpoints]);
490                 b->numpoints++;
491         }
492         
493         if (f->numpoints > maxpts || b->numpoints > maxpts)
494                 Error ("ClipWinding: points exceeded estimate");
495         if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
496                 Error ("ClipWinding: MAX_POINTS_ON_WINDING");
497 }
498
499
500 /*
501 =============
502 ChopWindingInPlace
503 =============
504 */
505 void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
506 {
507         winding_t       *in;
508         vec_t   dists[MAX_POINTS_ON_WINDING+4];
509         int             sides[MAX_POINTS_ON_WINDING+4];
510         int             counts[3];
511         static  vec_t   dot;            // VC 4.2 optimizer bug if not static
512         int             i, j;
513         vec_t   *p1, *p2;
514         vec3_t  mid;
515         winding_t       *f;
516         int             maxpts;
517
518         in = *inout;
519         counts[0] = counts[1] = counts[2] = 0;
520
521 // determine sides for each point
522         for (i=0 ; i<in->numpoints ; i++)
523         {
524                 dot = DotProduct (in->p[i], normal);
525                 dot -= dist;
526                 dists[i] = dot;
527                 if (dot > epsilon)
528                         sides[i] = SIDE_FRONT;
529                 else if (dot < -epsilon)
530                         sides[i] = SIDE_BACK;
531                 else
532                 {
533                         sides[i] = SIDE_ON;
534                 }
535                 counts[sides[i]]++;
536         }
537         sides[i] = sides[0];
538         dists[i] = dists[0];
539         
540         if (!counts[0])
541         {
542                 FreeWinding (in);
543                 *inout = NULL;
544                 return;
545         }
546         if (!counts[1])
547                 return;         // inout stays the same
548
549         maxpts = in->numpoints+4;       // cant use counts[0]+2 because
550                                                                 // of fp grouping errors
551
552         f = AllocWinding (maxpts);
553                 
554         for (i=0 ; i<in->numpoints ; i++)
555         {
556                 p1 = in->p[i];
557                 
558                 if (sides[i] == SIDE_ON)
559                 {
560                         VectorCopy (p1, f->p[f->numpoints]);
561                         f->numpoints++;
562                         continue;
563                 }
564         
565                 if (sides[i] == SIDE_FRONT)
566                 {
567                         VectorCopy (p1, f->p[f->numpoints]);
568                         f->numpoints++;
569                 }
570
571                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
572                         continue;
573                         
574         // generate a split point
575                 p2 = in->p[(i+1)%in->numpoints];
576                 
577                 dot = dists[i] / (dists[i]-dists[i+1]);
578                 for (j=0 ; j<3 ; j++)
579                 {       // avoid round off error when possible
580                         if (normal[j] == 1)
581                                 mid[j] = dist;
582                         else if (normal[j] == -1)
583                                 mid[j] = -dist;
584                         else
585                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
586                 }
587                         
588                 VectorCopy (mid, f->p[f->numpoints]);
589                 f->numpoints++;
590         }
591         
592         if (f->numpoints > maxpts)
593                 Error ("ClipWinding: points exceeded estimate");
594         if (f->numpoints > MAX_POINTS_ON_WINDING)
595                 Error ("ClipWinding: MAX_POINTS_ON_WINDING");
596
597         FreeWinding (in);
598         *inout = f;
599 }
600
601
602 /*
603 =================
604 ChopWinding
605
606 Returns the fragment of in that is on the front side
607 of the cliping plane.  The original is freed.
608 =================
609 */
610 winding_t       *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
611 {
612         winding_t       *f, *b;
613
614         ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
615         FreeWinding (in);
616         if (b)
617                 FreeWinding (b);
618         return f;
619 }
620
621
622 /*
623 =================
624 CheckWinding
625
626 =================
627 */
628 void CheckWinding (winding_t *w)
629 {
630         int             i, j;
631         vec_t   *p1, *p2;
632         vec_t   d, edgedist;
633         vec3_t  dir, edgenormal, facenormal;
634         vec_t   area;
635         vec_t   facedist;
636
637         if (w->numpoints < 3)
638                 Error ("CheckWinding: %i points",w->numpoints);
639         
640         area = WindingArea(w);
641         if (area < 1)
642                 Error ("CheckWinding: %f area", area);
643
644         WindingPlane (w, facenormal, &facedist);
645         
646         for (i=0 ; i<w->numpoints ; i++)
647         {
648                 p1 = w->p[i];
649
650                 for (j=0 ; j<3 ; j++)
651                         if (p1[j] > MAX_WORLD_COORD || p1[j] < MIN_WORLD_COORD)
652                                 Error ("CheckFace: MAX_WORLD_COORD exceeded: %f",p1[j]);
653
654                 j = i+1 == w->numpoints ? 0 : i+1;
655                 
656         // check the point is on the face plane
657                 d = DotProduct (p1, facenormal) - facedist;
658                 if (d < -ON_EPSILON || d > ON_EPSILON)
659                         Error ("CheckWinding: point off plane");
660         
661         // check the edge isnt degenerate
662                 p2 = w->p[j];
663                 VectorSubtract (p2, p1, dir);
664                 
665                 if (VectorLength (dir) < ON_EPSILON)
666                         Error ("CheckWinding: degenerate edge");
667                         
668                 CrossProduct (facenormal, dir, edgenormal);
669                 VectorNormalize (edgenormal, edgenormal);
670                 edgedist = DotProduct (p1, edgenormal);
671                 edgedist += ON_EPSILON;
672                 
673         // all other points must be on front side
674                 for (j=0 ; j<w->numpoints ; j++)
675                 {
676                         if (j == i)
677                                 continue;
678                         d = DotProduct (w->p[j], edgenormal);
679                         if (d > edgedist)
680                                 Error ("CheckWinding: non-convex");
681                 }
682         }
683 }
684
685
686 /*
687 ============
688 WindingOnPlaneSide
689 ============
690 */
691 int             WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
692 {
693         qboolean        front, back;
694         int                     i;
695         vec_t           d;
696
697         front = qfalse;
698         back = qfalse;
699         for (i=0 ; i<w->numpoints ; i++)
700         {
701                 d = DotProduct (w->p[i], normal) - dist;
702                 if (d < -ON_EPSILON)
703                 {
704                         if (front)
705                                 return SIDE_CROSS;
706                         back = qtrue;
707                         continue;
708                 }
709                 if (d > ON_EPSILON)
710                 {
711                         if (back)
712                                 return SIDE_CROSS;
713                         front = qtrue;
714                         continue;
715                 }
716         }
717
718         if (back)
719                 return SIDE_BACK;
720         if (front)
721                 return SIDE_FRONT;
722         return SIDE_ON;
723 }
724
725
726 /*
727 =================
728 AddWindingToConvexHull
729
730 Both w and *hull are on the same plane
731 =================
732 */
733 #define MAX_HULL_POINTS         128
734 void    AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
735         int                     i, j, k;
736         float           *p, *copy;
737         vec3_t          dir;
738         float           d;
739         int                     numHullPoints, numNew;
740         vec3_t          hullPoints[MAX_HULL_POINTS];
741         vec3_t          newHullPoints[MAX_HULL_POINTS];
742         vec3_t          hullDirs[MAX_HULL_POINTS];
743         qboolean        hullSide[MAX_HULL_POINTS];
744         qboolean        outside;
745
746         if ( !*hull ) {
747                 *hull = CopyWinding( w );
748                 return;
749         }
750
751         numHullPoints = (*hull)->numpoints;
752         memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );
753
754         for ( i = 0 ; i < w->numpoints ; i++ ) {
755                 p = w->p[i];
756
757                 // calculate hull side vectors
758                 for ( j = 0 ; j < numHullPoints ; j++ ) {
759                         k = ( j + 1 ) % numHullPoints;
760
761                         VectorSubtract( hullPoints[k], hullPoints[j], dir );
762                         VectorNormalize( dir, dir );
763                         CrossProduct( normal, dir, hullDirs[j] );
764                 }
765
766                 outside = qfalse;
767                 for ( j = 0 ; j < numHullPoints ; j++ ) {
768                         VectorSubtract( p, hullPoints[j], dir );
769                         d = DotProduct( dir, hullDirs[j] );
770                         if ( d >= ON_EPSILON ) {
771                                 outside = qtrue;
772                         }
773                         if ( d >= -ON_EPSILON ) {
774                                 hullSide[j] = qtrue;
775                         } else {
776                                 hullSide[j] = qfalse;
777                         }
778                 }
779
780                 // if the point is effectively inside, do nothing
781                 if ( !outside ) {
782                         continue;
783                 }
784
785                 // find the back side to front side transition
786                 for ( j = 0 ; j < numHullPoints ; j++ ) {
787                         if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
788                                 break;
789                         }
790                 }
791                 if ( j == numHullPoints ) {
792                         continue;
793                 }
794
795                 // insert the point here
796                 VectorCopy( p, newHullPoints[0] );
797                 numNew = 1;
798
799                 // copy over all points that aren't double fronts
800                 j = (j+1)%numHullPoints;
801                 for ( k = 0 ; k < numHullPoints ; k++ ) {
802                         if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
803                                 continue;
804                         }
805                         copy = hullPoints[ (j+k+1) % numHullPoints ];
806                         VectorCopy( copy, newHullPoints[numNew] );
807                         numNew++;
808                 }
809
810                 numHullPoints = numNew;
811                 memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
812         }
813
814         FreeWinding( *hull );
815         w = AllocWinding( numHullPoints );
816         w->numpoints = numHullPoints;
817         *hull = w;
818         memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
819 }
820
821