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