1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
8
9 RTCW MP 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 RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW MP 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 RTCW MP 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
30 // this is only used for visualization tools in cm_ debug functions
31
32
33 #include "cm_local.h"
34
35
36 // counters are only bumped when running single threaded,
37 // because they are an awful coherence problem
38 int c_active_windings;
39 int c_peak_windings;
40 int c_winding_allocs;
41 int c_winding_points;
42
43 #define BOGUS_RANGE 8192
44
pw(winding_t * w)45 void pw( winding_t *w ) {
46 int i;
47 for ( i = 0 ; i < w->numpoints ; i++ )
48 printf( "(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2] );
49 }
50
51
52 /*
53 =============
54 AllocWinding
55 =============
56 */
AllocWinding(int points)57 winding_t *AllocWinding( int points ) {
58 winding_t *w;
59 int s;
60
61 c_winding_allocs++;
62 c_winding_points += points;
63 c_active_windings++;
64 if ( c_active_windings > c_peak_windings ) {
65 c_peak_windings = c_active_windings;
66 }
67
68 s = sizeof( vec_t ) * 3 * points + sizeof( int );
69 w = Z_Malloc( s );
70 memset( w, 0, s );
71 return w;
72 }
73
FreeWinding(winding_t * w)74 void FreeWinding( winding_t *w ) {
75 if ( *(unsigned *)w == 0xdeaddead ) {
76 Com_Error( ERR_FATAL, "FreeWinding: freed a freed winding" );
77 }
78 *(unsigned *)w = 0xdeaddead;
79
80 c_active_windings--;
81 Z_Free( w );
82 }
83
84 /*
85 ============
86 RemoveColinearPoints
87 ============
88 */
89 int c_removed;
90
RemoveColinearPoints(winding_t * w)91 void RemoveColinearPoints( winding_t *w ) {
92 int i, j, k;
93 vec3_t v1, v2;
94 int nump;
95 vec3_t p[MAX_POINTS_ON_WINDING];
96
97 nump = 0;
98 for ( i = 0 ; i < w->numpoints ; i++ )
99 {
100 j = ( i + 1 ) % w->numpoints;
101 k = ( i + w->numpoints - 1 ) % w->numpoints;
102 VectorSubtract( w->p[j], w->p[i], v1 );
103 VectorSubtract( w->p[i], w->p[k], v2 );
104 VectorNormalize2( v1,v1 );
105 VectorNormalize2( v2,v2 );
106 if ( DotProduct( v1, v2 ) < 0.999 ) {
107 VectorCopy( w->p[i], p[nump] );
108 nump++;
109 }
110 }
111
112 if ( nump == w->numpoints ) {
113 return;
114 }
115
116 c_removed += w->numpoints - nump;
117 w->numpoints = nump;
118 memcpy( w->p, p, nump * sizeof( p[0] ) );
119 }
120
121 /*
122 ============
123 WindingPlane
124 ============
125 */
WindingPlane(winding_t * w,vec3_t normal,vec_t * dist)126 void WindingPlane( winding_t *w, vec3_t normal, vec_t *dist ) {
127 vec3_t v1, v2;
128
129 VectorSubtract( w->p[1], w->p[0], v1 );
130 VectorSubtract( w->p[2], w->p[0], v2 );
131 CrossProduct( v2, v1, normal );
132 VectorNormalize2( normal, normal );
133 *dist = DotProduct( w->p[0], normal );
134
135 }
136
137 /*
138 =============
139 WindingArea
140 =============
141 */
WindingArea(winding_t * w)142 vec_t WindingArea( winding_t *w ) {
143 int i;
144 vec3_t d1, d2, cross;
145 vec_t total;
146
147 total = 0;
148 for ( i = 2 ; i < w->numpoints ; i++ )
149 {
150 VectorSubtract( w->p[i - 1], w->p[0], d1 );
151 VectorSubtract( w->p[i], w->p[0], d2 );
152 CrossProduct( d1, d2, cross );
153 total += 0.5 * VectorLength( cross );
154 }
155 return total;
156 }
157
WindingBounds(winding_t * w,vec3_t mins,vec3_t maxs)158 void WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs ) {
159 vec_t v;
160 int i,j;
161
162 mins[0] = mins[1] = mins[2] = 99999;
163 maxs[0] = maxs[1] = maxs[2] = -99999;
164
165 for ( i = 0 ; i < w->numpoints ; i++ )
166 {
167 for ( j = 0 ; j < 3 ; j++ )
168 {
169 v = w->p[i][j];
170 if ( v < mins[j] ) {
171 mins[j] = v;
172 }
173 if ( v > maxs[j] ) {
174 maxs[j] = v;
175 }
176 }
177 }
178 }
179
180 /*
181 =============
182 WindingCenter
183 =============
184 */
WindingCenter(winding_t * w,vec3_t center)185 void WindingCenter( winding_t *w, vec3_t center ) {
186 int i;
187 float scale;
188
189 VectorCopy( vec3_origin, center );
190 for ( i = 0 ; i < w->numpoints ; i++ )
191 VectorAdd( w->p[i], center, center );
192
193 scale = 1.0 / w->numpoints;
194 VectorScale( center, scale, center );
195 }
196
197 /*
198 =================
199 BaseWindingForPlane
200 =================
201 */
BaseWindingForPlane(vec3_t normal,vec_t dist)202 winding_t *BaseWindingForPlane( vec3_t normal, vec_t dist ) {
203 int i, x;
204 vec_t max, v;
205 vec3_t org, vright, vup;
206 winding_t *w;
207
208 // find the major axis
209
210 max = -BOGUS_RANGE;
211 x = -1;
212 for ( i = 0 ; i < 3; i++ )
213 {
214 v = fabs( normal[i] );
215 if ( v > max ) {
216 x = i;
217 max = v;
218 }
219 }
220 if ( x == -1 ) {
221 Com_Error( ERR_DROP, "BaseWindingForPlane: no axis found" );
222 }
223
224 VectorCopy( vec3_origin, vup );
225 switch ( x )
226 {
227 case 0:
228 case 1:
229 vup[2] = 1;
230 break;
231 case 2:
232 vup[0] = 1;
233 break;
234 }
235
236 v = DotProduct( vup, normal );
237 VectorMA( vup, -v, normal, vup );
238 VectorNormalize2( vup, vup );
239
240 VectorScale( normal, dist, org );
241
242 CrossProduct( vup, normal, vright );
243
244 VectorScale( vup, 8192, vup );
245 VectorScale( vright, 8192, vright );
246
247 // project a really big axis aligned box onto the plane
248 w = AllocWinding( 4 );
249
250 VectorSubtract( org, vright, w->p[0] );
251 VectorAdd( w->p[0], vup, w->p[0] );
252
253 VectorAdd( org, vright, w->p[1] );
254 VectorAdd( w->p[1], vup, w->p[1] );
255
256 VectorAdd( org, vright, w->p[2] );
257 VectorSubtract( w->p[2], vup, w->p[2] );
258
259 VectorSubtract( org, vright, w->p[3] );
260 VectorSubtract( w->p[3], vup, w->p[3] );
261
262 w->numpoints = 4;
263
264 return w;
265 }
266
267 /*
268 ==================
269 CopyWinding
270 ==================
271 */
CopyWinding(winding_t * w)272 winding_t *CopyWinding( winding_t *w ) {
273 intptr_t size;
274 winding_t *c;
275
276 c = AllocWinding( w->numpoints );
277 size = (intptr_t)&(w->p[w->numpoints]) - (intptr_t)w;
278 Com_Memcpy (c, w, size);
279 return c;
280 }
281
282 /*
283 ==================
284 ReverseWinding
285 ==================
286 */
ReverseWinding(winding_t * w)287 winding_t *ReverseWinding( winding_t *w ) {
288 int i;
289 winding_t *c;
290
291 c = AllocWinding( w->numpoints );
292 for ( i = 0 ; i < w->numpoints ; i++ )
293 {
294 VectorCopy( w->p[w->numpoints - 1 - i], c->p[i] );
295 }
296 c->numpoints = w->numpoints;
297 return c;
298 }
299
300
301 /*
302 =============
303 ClipWindingEpsilon
304 =============
305 */
ClipWindingEpsilon(winding_t * in,vec3_t normal,vec_t dist,vec_t epsilon,winding_t ** front,winding_t ** back)306 void ClipWindingEpsilon( winding_t *in, vec3_t normal, vec_t dist,
307 vec_t epsilon, winding_t **front, winding_t **back ) {
308 vec_t dists[MAX_POINTS_ON_WINDING + 4] = { 0 };
309 int sides[MAX_POINTS_ON_WINDING + 4] = { 0 };
310 int counts[3];
311 static vec_t dot; // VC 4.2 optimizer bug if not static
312 int i, j;
313 vec_t *p1, *p2;
314 vec3_t mid;
315 winding_t *f, *b;
316 int maxpts;
317
318 counts[0] = counts[1] = counts[2] = 0;
319
320 // determine sides for each point
321 for ( i = 0 ; i < in->numpoints ; i++ )
322 {
323 dot = DotProduct( in->p[i], normal );
324 dot -= dist;
325 dists[i] = dot;
326 if ( dot > epsilon ) {
327 sides[i] = SIDE_FRONT;
328 } else if ( dot < -epsilon ) {
329 sides[i] = SIDE_BACK;
330 } else
331 {
332 sides[i] = SIDE_ON;
333 }
334 counts[sides[i]]++;
335 }
336 sides[i] = sides[0];
337 dists[i] = dists[0];
338
339 *front = *back = NULL;
340
341 if ( !counts[0] ) {
342 *back = CopyWinding( in );
343 return;
344 }
345 if ( !counts[1] ) {
346 *front = CopyWinding( in );
347 return;
348 }
349
350 maxpts = in->numpoints + 4; // cant use counts[0]+2 because
351 // of fp grouping errors
352
353 *front = f = AllocWinding( maxpts );
354 *back = b = AllocWinding( maxpts );
355
356 for ( i = 0 ; i < in->numpoints ; i++ )
357 {
358 p1 = in->p[i];
359
360 if ( sides[i] == SIDE_ON ) {
361 VectorCopy( p1, f->p[f->numpoints] );
362 f->numpoints++;
363 VectorCopy( p1, b->p[b->numpoints] );
364 b->numpoints++;
365 continue;
366 }
367
368 if ( sides[i] == SIDE_FRONT ) {
369 VectorCopy( p1, f->p[f->numpoints] );
370 f->numpoints++;
371 }
372 if ( sides[i] == SIDE_BACK ) {
373 VectorCopy( p1, b->p[b->numpoints] );
374 b->numpoints++;
375 }
376
377 if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
378 continue;
379 }
380
381 // generate a split point
382 p2 = in->p[( i + 1 ) % in->numpoints];
383
384 dot = dists[i] / ( dists[i] - dists[i + 1] );
385 for ( j = 0 ; j < 3 ; j++ )
386 { // avoid round off error when possible
387 if ( normal[j] == 1 ) {
388 mid[j] = dist;
389 } else if ( normal[j] == -1 ) {
390 mid[j] = -dist;
391 } else {
392 mid[j] = p1[j] + dot * ( p2[j] - p1[j] );
393 }
394 }
395
396 VectorCopy( mid, f->p[f->numpoints] );
397 f->numpoints++;
398 VectorCopy( mid, b->p[b->numpoints] );
399 b->numpoints++;
400 }
401
402 if ( f->numpoints > maxpts || b->numpoints > maxpts ) {
403 Com_Error( ERR_DROP, "ClipWinding: points exceeded estimate" );
404 }
405 if ( f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING ) {
406 Com_Error( ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING" );
407 }
408 }
409
410
411 /*
412 =============
413 ChopWindingInPlace
414 =============
415 */
ChopWindingInPlace(winding_t ** inout,vec3_t normal,vec_t dist,vec_t epsilon)416 void ChopWindingInPlace( winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon ) {
417 winding_t *in;
418 vec_t dists[MAX_POINTS_ON_WINDING + 4] = { 0 };
419 int sides[MAX_POINTS_ON_WINDING + 4] = { 0 };
420 int counts[3];
421 static vec_t dot; // VC 4.2 optimizer bug if not static
422 int i, j;
423 vec_t *p1, *p2;
424 vec3_t mid;
425 winding_t *f;
426 int maxpts;
427
428 in = *inout;
429 counts[0] = counts[1] = counts[2] = 0;
430
431 // determine sides for each point
432 for ( i = 0 ; i < in->numpoints ; i++ )
433 {
434 dot = DotProduct( in->p[i], normal );
435 dot -= dist;
436 dists[i] = dot;
437 if ( dot > epsilon ) {
438 sides[i] = SIDE_FRONT;
439 } else if ( dot < -epsilon ) {
440 sides[i] = SIDE_BACK;
441 } else
442 {
443 sides[i] = SIDE_ON;
444 }
445 counts[sides[i]]++;
446 }
447 sides[i] = sides[0];
448 dists[i] = dists[0];
449
450 if ( !counts[0] ) {
451 FreeWinding( in );
452 *inout = NULL;
453 return;
454 }
455 if ( !counts[1] ) {
456 return; // inout stays the same
457
458 }
459 maxpts = in->numpoints + 4; // cant use counts[0]+2 because
460 // of fp grouping errors
461
462 f = AllocWinding( maxpts );
463
464 for ( i = 0 ; i < in->numpoints ; i++ )
465 {
466 p1 = in->p[i];
467
468 if ( sides[i] == SIDE_ON ) {
469 VectorCopy( p1, f->p[f->numpoints] );
470 f->numpoints++;
471 continue;
472 }
473
474 if ( sides[i] == SIDE_FRONT ) {
475 VectorCopy( p1, f->p[f->numpoints] );
476 f->numpoints++;
477 }
478
479 if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
480 continue;
481 }
482
483 // generate a split point
484 p2 = in->p[( i + 1 ) % in->numpoints];
485
486 dot = dists[i] / ( dists[i] - dists[i + 1] );
487 for ( j = 0 ; j < 3 ; j++ )
488 { // avoid round off error when possible
489 if ( normal[j] == 1 ) {
490 mid[j] = dist;
491 } else if ( normal[j] == -1 ) {
492 mid[j] = -dist;
493 } else {
494 mid[j] = p1[j] + dot * ( p2[j] - p1[j] );
495 }
496 }
497
498 VectorCopy( mid, f->p[f->numpoints] );
499 f->numpoints++;
500 }
501
502 if ( f->numpoints > maxpts ) {
503 Com_Error( ERR_DROP, "ClipWinding: points exceeded estimate" );
504 }
505 if ( f->numpoints > MAX_POINTS_ON_WINDING ) {
506 Com_Error( ERR_DROP, "ClipWinding: MAX_POINTS_ON_WINDING" );
507 }
508
509 FreeWinding( in );
510 *inout = f;
511 }
512
513
514 /*
515 =================
516 ChopWinding
517
518 Returns the fragment of in that is on the front side
519 of the cliping plane. The original is freed.
520 =================
521 */
ChopWinding(winding_t * in,vec3_t normal,vec_t dist)522 winding_t *ChopWinding( winding_t *in, vec3_t normal, vec_t dist ) {
523 winding_t *f, *b;
524
525 ClipWindingEpsilon( in, normal, dist, ON_EPSILON, &f, &b );
526 FreeWinding( in );
527 if ( b ) {
528 FreeWinding( b );
529 }
530 return f;
531 }
532
533
534 /*
535 =================
536 CheckWinding
537
538 =================
539 */
CheckWinding(winding_t * w)540 void CheckWinding( winding_t *w ) {
541 int i, j;
542 vec_t *p1, *p2;
543 vec_t d, edgedist;
544 vec3_t dir, edgenormal, facenormal;
545 vec_t area;
546 vec_t facedist;
547
548 if ( w->numpoints < 3 ) {
549 Com_Error( ERR_DROP, "CheckWinding: %i points",w->numpoints );
550 }
551
552 area = WindingArea( w );
553 if ( area < 1 ) {
554 Com_Error( ERR_DROP, "CheckWinding: %f area", area );
555 }
556
557 WindingPlane( w, facenormal, &facedist );
558
559 for ( i = 0 ; i < w->numpoints ; i++ )
560 {
561 p1 = w->p[i];
562
563 for ( j = 0 ; j < 3 ; j++ )
564 if ( p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE ) {
565 Com_Error( ERR_DROP, "CheckFace: BUGUS_RANGE: %f",p1[j] );
566 }
567
568 j = i + 1 == w->numpoints ? 0 : i + 1;
569
570 // check the point is on the face plane
571 d = DotProduct( p1, facenormal ) - facedist;
572 if ( d < -ON_EPSILON || d > ON_EPSILON ) {
573 Com_Error( ERR_DROP, "CheckWinding: point off plane" );
574 }
575
576 // check the edge isnt degenerate
577 p2 = w->p[j];
578 VectorSubtract( p2, p1, dir );
579
580 if ( VectorLength( dir ) < ON_EPSILON ) {
581 Com_Error( ERR_DROP, "CheckWinding: degenerate edge" );
582 }
583
584 CrossProduct( facenormal, dir, edgenormal );
585 VectorNormalize2( edgenormal, edgenormal );
586 edgedist = DotProduct( p1, edgenormal );
587 edgedist += ON_EPSILON;
588
589 // all other points must be on front side
590 for ( j = 0 ; j < w->numpoints ; j++ )
591 {
592 if ( j == i ) {
593 continue;
594 }
595 d = DotProduct( w->p[j], edgenormal );
596 if ( d > edgedist ) {
597 Com_Error( ERR_DROP, "CheckWinding: non-convex" );
598 }
599 }
600 }
601 }
602
603
604 /*
605 ============
606 WindingOnPlaneSide
607 ============
608 */
WindingOnPlaneSide(winding_t * w,vec3_t normal,vec_t dist)609 int WindingOnPlaneSide( winding_t *w, vec3_t normal, vec_t dist ) {
610 qboolean front, back;
611 int i;
612 vec_t d;
613
614 front = qfalse;
615 back = qfalse;
616 for ( i = 0 ; i < w->numpoints ; i++ )
617 {
618 d = DotProduct( w->p[i], normal ) - dist;
619 if ( d < -ON_EPSILON ) {
620 if ( front ) {
621 return SIDE_CROSS;
622 }
623 back = qtrue;
624 continue;
625 }
626 if ( d > ON_EPSILON ) {
627 if ( back ) {
628 return SIDE_CROSS;
629 }
630 front = qtrue;
631 continue;
632 }
633 }
634
635 if ( back ) {
636 return SIDE_BACK;
637 }
638 if ( front ) {
639 return SIDE_FRONT;
640 }
641 return SIDE_ON;
642 }
643
644
645 /*
646 =================
647 AddWindingToConvexHull
648
649 Both w and *hull are on the same plane
650 =================
651 */
652 #define MAX_HULL_POINTS 128
AddWindingToConvexHull(winding_t * w,winding_t ** hull,vec3_t normal)653 void AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
654 int i, j, k;
655 float *p, *copy;
656 vec3_t dir;
657 float d;
658 int numHullPoints, numNew;
659 vec3_t hullPoints[MAX_HULL_POINTS];
660 vec3_t newHullPoints[MAX_HULL_POINTS];
661 vec3_t hullDirs[MAX_HULL_POINTS];
662 qboolean hullSide[MAX_HULL_POINTS];
663 qboolean outside;
664
665 if ( !*hull ) {
666 *hull = CopyWinding( w );
667 return;
668 }
669
670 numHullPoints = ( *hull )->numpoints;
671 memcpy( hullPoints, ( *hull )->p, numHullPoints * sizeof( vec3_t ) );
672
673 for ( i = 0 ; i < w->numpoints ; i++ ) {
674 p = w->p[i];
675
676 // calculate hull side vectors
677 for ( j = 0 ; j < numHullPoints ; j++ ) {
678 k = ( j + 1 ) % numHullPoints;
679
680 VectorSubtract( hullPoints[k], hullPoints[j], dir );
681 VectorNormalize2( dir, dir );
682 CrossProduct( normal, dir, hullDirs[j] );
683 }
684
685 outside = qfalse;
686 for ( j = 0 ; j < numHullPoints ; j++ ) {
687 VectorSubtract( p, hullPoints[j], dir );
688 d = DotProduct( dir, hullDirs[j] );
689 if ( d >= ON_EPSILON ) {
690 outside = qtrue;
691 }
692 if ( d >= -ON_EPSILON ) {
693 hullSide[j] = qtrue;
694 } else {
695 hullSide[j] = qfalse;
696 }
697 }
698
699 // if the point is effectively inside, do nothing
700 if ( !outside ) {
701 continue;
702 }
703
704 // find the back side to front side transition
705 for ( j = 0 ; j < numHullPoints ; j++ ) {
706 if ( !hullSide[ j % numHullPoints ] && hullSide[ ( j + 1 ) % numHullPoints ] ) {
707 break;
708 }
709 }
710 if ( j == numHullPoints ) {
711 continue;
712 }
713
714 // insert the point here
715 VectorCopy( p, newHullPoints[0] );
716 numNew = 1;
717
718 // copy over all points that aren't double fronts
719 j = ( j + 1 ) % numHullPoints;
720 for ( k = 0 ; k < numHullPoints ; k++ ) {
721 if ( hullSide[ ( j + k ) % numHullPoints ] && hullSide[ ( j + k + 1 ) % numHullPoints ] ) {
722 continue;
723 }
724 copy = hullPoints[ ( j + k + 1 ) % numHullPoints ];
725 VectorCopy( copy, newHullPoints[numNew] );
726 numNew++;
727 }
728
729 numHullPoints = numNew;
730 memcpy( hullPoints, newHullPoints, numHullPoints * sizeof( vec3_t ) );
731 }
732
733 FreeWinding( *hull );
734 w = AllocWinding( numHullPoints );
735 w->numpoints = numHullPoints;
736 *hull = w;
737 memcpy( w->p, hullPoints, numHullPoints * sizeof( vec3_t ) );
738 }
739
740
741