00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <malloc.h>
00024 #include "l_cmd.h"
00025 #include "l_math.h"
00026 #include "l_poly.h"
00027 #include "l_log.h"
00028 #include "l_mem.h"
00029
00030 #define BOGUS_RANGE 65535
00031
00032 extern int numthreads;
00033
00034
00035
00036 int c_active_windings;
00037 int c_peak_windings;
00038 int c_winding_allocs;
00039 int c_winding_points;
00040 int c_windingmemory;
00041 int c_peak_windingmemory;
00042
00043 char windingerror[1024];
00044
00045 void pw(winding_t *w)
00046 {
00047 int i;
00048 for (i=0 ; i<w->numpoints ; i++)
00049 printf ("(%5.3f, %5.3f, %5.3f)\n",w->p[i][0], w->p[i][1],w->p[i][2]);
00050 }
00051
00052
00053 void ResetWindings(void)
00054 {
00055 c_active_windings = 0;
00056 c_peak_windings = 0;
00057 c_winding_allocs = 0;
00058 c_winding_points = 0;
00059 c_windingmemory = 0;
00060 c_peak_windingmemory = 0;
00061
00062 strcpy(windingerror, "");
00063 }
00064
00065
00066
00067
00068
00069 winding_t *AllocWinding (int points)
00070 {
00071 winding_t *w;
00072 int s;
00073
00074 s = sizeof(vec_t)*3*points + sizeof(int);
00075 w = GetMemory(s);
00076 memset(w, 0, s);
00077
00078 if (numthreads == 1)
00079 {
00080 c_winding_allocs++;
00081 c_winding_points += points;
00082 c_active_windings++;
00083 if (c_active_windings > c_peak_windings)
00084 c_peak_windings = c_active_windings;
00085 c_windingmemory += MemorySize(w);
00086 if (c_windingmemory > c_peak_windingmemory)
00087 c_peak_windingmemory = c_windingmemory;
00088 }
00089 return w;
00090 }
00091
00092 void FreeWinding (winding_t *w)
00093 {
00094 if (*(unsigned *)w == 0xdeaddead)
00095 Error ("FreeWinding: freed a freed winding");
00096
00097 if (numthreads == 1)
00098 {
00099 c_active_windings--;
00100 c_windingmemory -= MemorySize(w);
00101 }
00102
00103 *(unsigned *)w = 0xdeaddead;
00104
00105 FreeMemory(w);
00106 }
00107
00108 int WindingMemory(void)
00109 {
00110 return c_windingmemory;
00111 }
00112
00113 int WindingPeakMemory(void)
00114 {
00115 return c_peak_windingmemory;
00116 }
00117
00118 int ActiveWindings(void)
00119 {
00120 return c_active_windings;
00121 }
00122
00123
00124
00125
00126
00127 int c_removed;
00128
00129 void RemoveColinearPoints (winding_t *w)
00130 {
00131 int i, j, k;
00132 vec3_t v1, v2;
00133 int nump;
00134 vec3_t p[MAX_POINTS_ON_WINDING];
00135
00136 nump = 0;
00137 for (i=0 ; i<w->numpoints ; i++)
00138 {
00139 j = (i+1)%w->numpoints;
00140 k = (i+w->numpoints-1)%w->numpoints;
00141 VectorSubtract (w->p[j], w->p[i], v1);
00142 VectorSubtract (w->p[i], w->p[k], v2);
00143 VectorNormalize(v1);
00144 VectorNormalize(v2);
00145 if (DotProduct(v1, v2) < 0.999)
00146 {
00147 if (nump >= MAX_POINTS_ON_WINDING)
00148 Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
00149 VectorCopy (w->p[i], p[nump]);
00150 nump++;
00151 }
00152 }
00153
00154 if (nump == w->numpoints)
00155 return;
00156
00157 if (numthreads == 1)
00158 c_removed += w->numpoints - nump;
00159 w->numpoints = nump;
00160 memcpy (w->p, p, nump*sizeof(p[0]));
00161 }
00162
00163
00164
00165
00166
00167
00168 void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist)
00169 {
00170 vec3_t v1, v2;
00171 int i;
00172
00173
00174 for (i = 0; i < w->numpoints; i++)
00175 {
00176 VectorSubtract(w->p[(i+1) % w->numpoints], w->p[i], v1);
00177 VectorSubtract(w->p[(i+2) % w->numpoints], w->p[i], v2);
00178 if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
00179 }
00180 CrossProduct(v2, v1, normal);
00181 VectorNormalize(normal);
00182 *dist = DotProduct(w->p[0], normal);
00183 }
00184
00185
00186
00187
00188
00189
00190 vec_t WindingArea (winding_t *w)
00191 {
00192 int i;
00193 vec3_t d1, d2, cross;
00194 vec_t total;
00195
00196 total = 0;
00197 for (i=2 ; i<w->numpoints ; i++)
00198 {
00199 VectorSubtract (w->p[i-1], w->p[0], d1);
00200 VectorSubtract (w->p[i], w->p[0], d2);
00201 CrossProduct (d1, d2, cross);
00202 total += 0.5 * VectorLength ( cross );
00203 }
00204 return total;
00205 }
00206
00207 void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs)
00208 {
00209 vec_t v;
00210 int i,j;
00211
00212 mins[0] = mins[1] = mins[2] = 99999;
00213 maxs[0] = maxs[1] = maxs[2] = -99999;
00214
00215 for (i=0 ; i<w->numpoints ; i++)
00216 {
00217 for (j=0 ; j<3 ; j++)
00218 {
00219 v = w->p[i][j];
00220 if (v < mins[j])
00221 mins[j] = v;
00222 if (v > maxs[j])
00223 maxs[j] = v;
00224 }
00225 }
00226 }
00227
00228
00229
00230
00231
00232
00233 void WindingCenter (winding_t *w, vec3_t center)
00234 {
00235 int i;
00236 float scale;
00237
00238 VectorCopy (vec3_origin, center);
00239 for (i=0 ; i<w->numpoints ; i++)
00240 VectorAdd (w->p[i], center, center);
00241
00242 scale = 1.0/w->numpoints;
00243 VectorScale (center, scale, center);
00244 }
00245
00246
00247
00248
00249
00250
00251 winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
00252 {
00253 int i, x;
00254 vec_t max, v;
00255 vec3_t org, vright, vup;
00256 winding_t *w;
00257
00258
00259
00260 max = -BOGUS_RANGE;
00261 x = -1;
00262 for (i=0 ; i<3; i++)
00263 {
00264 v = fabs(normal[i]);
00265 if (v > max)
00266 {
00267 x = i;
00268 max = v;
00269 }
00270 }
00271 if (x==-1)
00272 Error ("BaseWindingForPlane: no axis found");
00273
00274 VectorCopy (vec3_origin, vup);
00275 switch (x)
00276 {
00277 case 0:
00278 case 1:
00279 vup[2] = 1;
00280 break;
00281 case 2:
00282 vup[0] = 1;
00283 break;
00284 }
00285
00286 v = DotProduct (vup, normal);
00287 VectorMA (vup, -v, normal, vup);
00288 VectorNormalize (vup);
00289
00290 VectorScale (normal, dist, org);
00291
00292 CrossProduct (vup, normal, vright);
00293
00294 VectorScale (vup, BOGUS_RANGE, vup);
00295 VectorScale (vright, BOGUS_RANGE, vright);
00296
00297
00298 w = AllocWinding (4);
00299
00300 VectorSubtract (org, vright, w->p[0]);
00301 VectorAdd (w->p[0], vup, w->p[0]);
00302
00303 VectorAdd (org, vright, w->p[1]);
00304 VectorAdd (w->p[1], vup, w->p[1]);
00305
00306 VectorAdd (org, vright, w->p[2]);
00307 VectorSubtract (w->p[2], vup, w->p[2]);
00308
00309 VectorSubtract (org, vright, w->p[3]);
00310 VectorSubtract (w->p[3], vup, w->p[3]);
00311
00312 w->numpoints = 4;
00313
00314 return w;
00315 }
00316
00317
00318
00319
00320
00321
00322 winding_t *CopyWinding (winding_t *w)
00323 {
00324 int size;
00325 winding_t *c;
00326
00327 c = AllocWinding (w->numpoints);
00328 size = (int)((winding_t *)0)->p[w->numpoints];
00329 memcpy (c, w, size);
00330 return c;
00331 }
00332
00333
00334
00335
00336
00337
00338 winding_t *ReverseWinding (winding_t *w)
00339 {
00340 int i;
00341 winding_t *c;
00342
00343 c = AllocWinding (w->numpoints);
00344 for (i=0 ; i<w->numpoints ; i++)
00345 {
00346 VectorCopy (w->p[w->numpoints-1-i], c->p[i]);
00347 }
00348 c->numpoints = w->numpoints;
00349 return c;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358 void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
00359 vec_t epsilon, winding_t **front, winding_t **back)
00360 {
00361 vec_t dists[MAX_POINTS_ON_WINDING+4];
00362 int sides[MAX_POINTS_ON_WINDING+4];
00363 int counts[3];
00364
00365 vec_t dot;
00366 int i, j;
00367 vec_t *p1, *p2;
00368 vec3_t mid;
00369 winding_t *f, *b;
00370 int maxpts;
00371
00372 counts[0] = counts[1] = counts[2] = 0;
00373
00374
00375 for (i=0 ; i<in->numpoints ; i++)
00376 {
00377 dot = DotProduct (in->p[i], normal);
00378 dot -= dist;
00379 dists[i] = dot;
00380 if (dot > epsilon)
00381 sides[i] = SIDE_FRONT;
00382 else if (dot < -epsilon)
00383 sides[i] = SIDE_BACK;
00384 else
00385 {
00386 sides[i] = SIDE_ON;
00387 }
00388 counts[sides[i]]++;
00389 }
00390 sides[i] = sides[0];
00391 dists[i] = dists[0];
00392
00393 *front = *back = NULL;
00394
00395 if (!counts[0])
00396 {
00397 *back = CopyWinding (in);
00398 return;
00399 }
00400 if (!counts[1])
00401 {
00402 *front = CopyWinding (in);
00403 return;
00404 }
00405
00406 maxpts = in->numpoints+4;
00407
00408
00409 *front = f = AllocWinding (maxpts);
00410 *back = b = AllocWinding (maxpts);
00411
00412 for (i=0 ; i<in->numpoints ; i++)
00413 {
00414 p1 = in->p[i];
00415
00416 if (sides[i] == SIDE_ON)
00417 {
00418 VectorCopy (p1, f->p[f->numpoints]);
00419 f->numpoints++;
00420 VectorCopy (p1, b->p[b->numpoints]);
00421 b->numpoints++;
00422 continue;
00423 }
00424
00425 if (sides[i] == SIDE_FRONT)
00426 {
00427 VectorCopy (p1, f->p[f->numpoints]);
00428 f->numpoints++;
00429 }
00430 if (sides[i] == SIDE_BACK)
00431 {
00432 VectorCopy (p1, b->p[b->numpoints]);
00433 b->numpoints++;
00434 }
00435
00436 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00437 continue;
00438
00439
00440 p2 = in->p[(i+1)%in->numpoints];
00441
00442 dot = dists[i] / (dists[i]-dists[i+1]);
00443 for (j=0 ; j<3 ; j++)
00444 {
00445 if (normal[j] == 1)
00446 mid[j] = dist;
00447 else if (normal[j] == -1)
00448 mid[j] = -dist;
00449 else
00450 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00451 }
00452
00453 VectorCopy (mid, f->p[f->numpoints]);
00454 f->numpoints++;
00455 VectorCopy (mid, b->p[b->numpoints]);
00456 b->numpoints++;
00457 }
00458
00459 if (f->numpoints > maxpts || b->numpoints > maxpts)
00460 Error ("ClipWinding: points exceeded estimate");
00461 if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
00462 Error ("ClipWinding: MAX_POINTS_ON_WINDING");
00463 }
00464
00465
00466
00467
00468
00469
00470
00471 void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon)
00472 {
00473 winding_t *in;
00474 vec_t dists[MAX_POINTS_ON_WINDING+4];
00475 int sides[MAX_POINTS_ON_WINDING+4];
00476 int counts[3];
00477
00478 vec_t dot;
00479 int i, j;
00480 vec_t *p1, *p2;
00481 vec3_t mid;
00482 winding_t *f;
00483 int maxpts;
00484
00485 in = *inout;
00486 counts[0] = counts[1] = counts[2] = 0;
00487
00488
00489 for (i=0 ; i<in->numpoints ; i++)
00490 {
00491 dot = DotProduct (in->p[i], normal);
00492 dot -= dist;
00493 dists[i] = dot;
00494 if (dot > epsilon)
00495 sides[i] = SIDE_FRONT;
00496 else if (dot < -epsilon)
00497 sides[i] = SIDE_BACK;
00498 else
00499 {
00500 sides[i] = SIDE_ON;
00501 }
00502 counts[sides[i]]++;
00503 }
00504 sides[i] = sides[0];
00505 dists[i] = dists[0];
00506
00507 if (!counts[0])
00508 {
00509 FreeWinding (in);
00510 *inout = NULL;
00511 return;
00512 }
00513 if (!counts[1])
00514 return;
00515
00516 maxpts = in->numpoints+4;
00517
00518
00519 f = AllocWinding (maxpts);
00520
00521 for (i=0 ; i<in->numpoints ; i++)
00522 {
00523 p1 = in->p[i];
00524
00525 if (sides[i] == SIDE_ON)
00526 {
00527 VectorCopy (p1, f->p[f->numpoints]);
00528 f->numpoints++;
00529 continue;
00530 }
00531
00532 if (sides[i] == SIDE_FRONT)
00533 {
00534 VectorCopy (p1, f->p[f->numpoints]);
00535 f->numpoints++;
00536 }
00537
00538 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00539 continue;
00540
00541
00542 p2 = in->p[(i+1)%in->numpoints];
00543
00544 dot = dists[i] / (dists[i]-dists[i+1]);
00545 for (j=0 ; j<3 ; j++)
00546 {
00547 if (normal[j] == 1)
00548 mid[j] = dist;
00549 else if (normal[j] == -1)
00550 mid[j] = -dist;
00551 else
00552 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00553 }
00554
00555 VectorCopy (mid, f->p[f->numpoints]);
00556 f->numpoints++;
00557 }
00558
00559 if (f->numpoints > maxpts)
00560 Error ("ClipWinding: points exceeded estimate");
00561 if (f->numpoints > MAX_POINTS_ON_WINDING)
00562 Error ("ClipWinding: MAX_POINTS_ON_WINDING");
00563
00564 FreeWinding (in);
00565 *inout = f;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
00578 {
00579 winding_t *f, *b;
00580
00581 ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b);
00582 FreeWinding (in);
00583 if (b)
00584 FreeWinding (b);
00585 return f;
00586 }
00587
00588
00589
00590
00591
00592
00593
00594
00595 void CheckWinding (winding_t *w)
00596 {
00597 int i, j;
00598 vec_t *p1, *p2;
00599 vec_t d, edgedist;
00600 vec3_t dir, edgenormal, facenormal;
00601 vec_t area;
00602 vec_t facedist;
00603
00604 if (w->numpoints < 3)
00605 Error ("CheckWinding: %i points",w->numpoints);
00606
00607 area = WindingArea(w);
00608 if (area < 1)
00609 Error ("CheckWinding: %f area", area);
00610
00611 WindingPlane (w, facenormal, &facedist);
00612
00613 for (i=0 ; i<w->numpoints ; i++)
00614 {
00615 p1 = w->p[i];
00616
00617 for (j=0 ; j<3 ; j++)
00618 if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
00619 Error ("CheckWinding: BUGUS_RANGE: %f",p1[j]);
00620
00621 j = i+1 == w->numpoints ? 0 : i+1;
00622
00623
00624 d = DotProduct (p1, facenormal) - facedist;
00625 if (d < -ON_EPSILON || d > ON_EPSILON)
00626 Error ("CheckWinding: point off plane");
00627
00628
00629 p2 = w->p[j];
00630 VectorSubtract (p2, p1, dir);
00631
00632 if (VectorLength (dir) < ON_EPSILON)
00633 Error ("CheckWinding: degenerate edge");
00634
00635 CrossProduct (facenormal, dir, edgenormal);
00636 VectorNormalize (edgenormal);
00637 edgedist = DotProduct (p1, edgenormal);
00638 edgedist += ON_EPSILON;
00639
00640
00641 for (j=0 ; j<w->numpoints ; j++)
00642 {
00643 if (j == i)
00644 continue;
00645 d = DotProduct (w->p[j], edgenormal);
00646 if (d > edgedist)
00647 Error ("CheckWinding: non-convex");
00648 }
00649 }
00650 }
00651
00652
00653
00654
00655
00656
00657
00658 int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist)
00659 {
00660 qboolean front, back;
00661 int i;
00662 vec_t d;
00663
00664 front = false;
00665 back = false;
00666 for (i=0 ; i<w->numpoints ; i++)
00667 {
00668 d = DotProduct (w->p[i], normal) - dist;
00669 if (d < -ON_EPSILON)
00670 {
00671 if (front)
00672 return SIDE_CROSS;
00673 back = true;
00674 continue;
00675 }
00676 if (d > ON_EPSILON)
00677 {
00678 if (back)
00679 return SIDE_CROSS;
00680 front = true;
00681 continue;
00682 }
00683 }
00684
00685 if (back)
00686 return SIDE_BACK;
00687 if (front)
00688 return SIDE_FRONT;
00689 return SIDE_ON;
00690 }
00691
00692
00693 #define CONTINUOUS_EPSILON 0.005
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710 winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
00711 {
00712 vec_t *p1, *p2, *p3, *p4, *back;
00713 winding_t *newf;
00714 int i, j, k, l;
00715 vec3_t normal, delta;
00716 vec_t dot;
00717 qboolean keep1, keep2;
00718
00719
00720
00721
00722
00723 p1 = p2 = NULL;
00724 j = 0;
00725
00726 for (i = 0; i < f1->numpoints; i++)
00727 {
00728 p1 = f1->p[i];
00729 p2 = f1->p[(i+1) % f1->numpoints];
00730 for (j = 0; j < f2->numpoints; j++)
00731 {
00732 p3 = f2->p[j];
00733 p4 = f2->p[(j+1) % f2->numpoints];
00734 for (k = 0; k < 3; k++)
00735 {
00736 if (fabs(p1[k] - p4[k]) > 0.1)
00737 break;
00738 if (fabs(p2[k] - p3[k]) > 0.1)
00739 break;
00740 }
00741 if (k==3)
00742 break;
00743 }
00744 if (j < f2->numpoints)
00745 break;
00746 }
00747
00748 if (i == f1->numpoints)
00749 return NULL;
00750
00751
00752
00753
00754
00755 back = f1->p[(i+f1->numpoints-1)%f1->numpoints];
00756 VectorSubtract (p1, back, delta);
00757 CrossProduct (planenormal, delta, normal);
00758 VectorNormalize (normal);
00759
00760 back = f2->p[(j+2)%f2->numpoints];
00761 VectorSubtract (back, p1, delta);
00762 dot = DotProduct (delta, normal);
00763 if (dot > CONTINUOUS_EPSILON)
00764 return NULL;
00765 keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00766
00767 back = f1->p[(i+2)%f1->numpoints];
00768 VectorSubtract (back, p2, delta);
00769 CrossProduct (planenormal, delta, normal);
00770 VectorNormalize (normal);
00771
00772 back = f2->p[(j+f2->numpoints-1)%f2->numpoints];
00773 VectorSubtract (back, p2, delta);
00774 dot = DotProduct (delta, normal);
00775 if (dot > CONTINUOUS_EPSILON)
00776 return NULL;
00777 keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00778
00779
00780
00781
00782 newf = AllocWinding (f1->numpoints + f2->numpoints);
00783
00784
00785 for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
00786 {
00787 if (k==(i+1)%f1->numpoints && !keep2)
00788 continue;
00789
00790 VectorCopy (f1->p[k], newf->p[newf->numpoints]);
00791 newf->numpoints++;
00792 }
00793
00794
00795 for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
00796 {
00797 if (l==(j+1)%f2->numpoints && !keep1)
00798 continue;
00799 VectorCopy (f2->p[l], newf->p[newf->numpoints]);
00800 newf->numpoints++;
00801 }
00802
00803 return newf;
00804 }
00805
00806
00807
00808
00809
00810
00811
00812
00813 winding_t *MergeWindings(winding_t *w1, winding_t *w2, vec3_t planenormal)
00814 {
00815 winding_t *neww;
00816 float dist;
00817 int i, j, n, found, insertafter;
00818 int sides[MAX_POINTS_ON_WINDING+4];
00819 vec3_t newp[MAX_POINTS_ON_WINDING+4];
00820 int numpoints;
00821 vec3_t edgevec, sepnormal, v;
00822
00823 RemoveEqualPoints(w1, 0.2);
00824 numpoints = w1->numpoints;
00825 memcpy(newp, w1->p, w1->numpoints * sizeof(vec3_t));
00826
00827 for (i = 0; i < w2->numpoints; i++)
00828 {
00829 VectorCopy(w2->p[i], v);
00830 for (j = 0; j < numpoints; j++)
00831 {
00832 VectorSubtract(newp[(j+1)%numpoints],
00833 newp[(j)%numpoints], edgevec);
00834 CrossProduct(edgevec, planenormal, sepnormal);
00835 VectorNormalize(sepnormal);
00836 if (VectorLength(sepnormal) < 0.9)
00837 {
00838
00839 for (n = j; n < numpoints-1; n++)
00840 {
00841 VectorCopy(newp[n+1], newp[n]);
00842 sides[n] = sides[n+1];
00843 }
00844 numpoints--;
00845 j--;
00846 Log_Print("MergeWindings: degenerate edge on winding %f %f %f\n", sepnormal[0],
00847 sepnormal[1],
00848 sepnormal[2]);
00849 continue;
00850 }
00851 dist = DotProduct(newp[(j)%numpoints], sepnormal);
00852 if (DotProduct(v, sepnormal) - dist < -0.1) sides[j] = SIDE_BACK;
00853 else sides[j] = SIDE_FRONT;
00854 }
00855
00856 for (j = 0; j < numpoints;)
00857 {
00858 if (sides[j] == SIDE_BACK
00859 && sides[(j+1)%numpoints] == SIDE_BACK)
00860 {
00861
00862 for (n = (j+1)%numpoints; n < numpoints-1; n++)
00863 {
00864 VectorCopy(newp[n+1], newp[n]);
00865 sides[n] = sides[n+1];
00866 }
00867 numpoints--;
00868 }
00869 else
00870 {
00871 j++;
00872 }
00873 }
00874
00875 found = false;
00876 for (j = 0; j < numpoints; j++)
00877 {
00878 if (sides[j] == SIDE_FRONT
00879 && sides[(j+1)%numpoints] == SIDE_BACK)
00880 {
00881 if (found) Log_Print("Warning: MergeWindings: front to back found twice\n");
00882 found = true;
00883 }
00884 }
00885
00886 for (j = 0; j < numpoints; j++)
00887 {
00888 if (sides[j] == SIDE_FRONT
00889 && sides[(j+1)%numpoints] == SIDE_BACK)
00890 {
00891 insertafter = (j+1)%numpoints;
00892
00893 for (n = numpoints-1; n > insertafter; n--)
00894 {
00895 VectorCopy(newp[n], newp[n+1]);
00896 }
00897 numpoints++;
00898 VectorCopy(v, newp[(insertafter+1)%numpoints]);
00899 break;
00900 }
00901 }
00902 }
00903 neww = AllocWinding(numpoints);
00904 neww->numpoints = numpoints;
00905 memcpy(neww->p, newp, numpoints * sizeof(vec3_t));
00906 RemoveColinearPoints(neww);
00907 return neww;
00908 }
00909
00910
00911
00912
00913
00914
00915 char *WindingErrorString(void)
00916 {
00917 return windingerror;
00918 }
00919
00920
00921
00922
00923
00924
00925 int WindingError(winding_t *w)
00926 {
00927 int i, j;
00928 vec_t *p1, *p2;
00929 vec_t d, edgedist;
00930 vec3_t dir, edgenormal, facenormal;
00931 vec_t area;
00932 vec_t facedist;
00933
00934 if (w->numpoints < 3)
00935 {
00936 sprintf(windingerror, "winding %i points", w->numpoints);
00937 return WE_NOTENOUGHPOINTS;
00938 }
00939
00940 area = WindingArea(w);
00941 if (area < 1)
00942 {
00943 sprintf(windingerror, "winding %f area", area);
00944 return WE_SMALLAREA;
00945 }
00946
00947 WindingPlane (w, facenormal, &facedist);
00948
00949 for (i=0 ; i<w->numpoints ; i++)
00950 {
00951 p1 = w->p[i];
00952
00953 for (j=0 ; j<3 ; j++)
00954 {
00955 if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
00956 {
00957 sprintf(windingerror, "winding point %d BUGUS_RANGE \'%f %f %f\'", j, p1[0], p1[1], p1[2]);
00958 return WE_POINTBOGUSRANGE;
00959 }
00960 }
00961
00962 j = i+1 == w->numpoints ? 0 : i+1;
00963
00964
00965 d = DotProduct (p1, facenormal) - facedist;
00966 if (d < -ON_EPSILON || d > ON_EPSILON)
00967 {
00968 sprintf(windingerror, "winding point %d off plane", i);
00969 return WE_POINTOFFPLANE;
00970 }
00971
00972
00973 p2 = w->p[j];
00974 VectorSubtract (p2, p1, dir);
00975
00976 if (VectorLength (dir) < ON_EPSILON)
00977 {
00978 sprintf(windingerror, "winding degenerate edge %d-%d", i, j);
00979 return WE_DEGENERATEEDGE;
00980 }
00981
00982 CrossProduct (facenormal, dir, edgenormal);
00983 VectorNormalize (edgenormal);
00984 edgedist = DotProduct (p1, edgenormal);
00985 edgedist += ON_EPSILON;
00986
00987
00988 for (j=0 ; j<w->numpoints ; j++)
00989 {
00990 if (j == i)
00991 continue;
00992 d = DotProduct (w->p[j], edgenormal);
00993 if (d > edgedist)
00994 {
00995 sprintf(windingerror, "winding non-convex");
00996 return WE_NONCONVEX;
00997 }
00998 }
00999 }
01000 return WE_NONE;
01001 }
01002
01003
01004
01005
01006
01007
01008 void RemoveEqualPoints(winding_t *w, float epsilon)
01009 {
01010 int i, nump;
01011 vec3_t v;
01012 vec3_t p[MAX_POINTS_ON_WINDING];
01013
01014 VectorCopy(w->p[0], p[0]);
01015 nump = 1;
01016 for (i = 1; i < w->numpoints; i++)
01017 {
01018 VectorSubtract(w->p[i], p[nump-1], v);
01019 if (VectorLength(v) > epsilon)
01020 {
01021 if (nump >= MAX_POINTS_ON_WINDING)
01022 Error("RemoveColinearPoints: MAX_POINTS_ON_WINDING");
01023 VectorCopy (w->p[i], p[nump]);
01024 nump++;
01025 }
01026 }
01027
01028 if (nump == w->numpoints)
01029 return;
01030
01031 w->numpoints = nump;
01032 memcpy(w->p, p, nump * sizeof(p[0]));
01033 }
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043 winding_t *AddWindingPoint(winding_t *w, vec3_t point, int spot)
01044 {
01045 int i, j;
01046 winding_t *neww;
01047
01048 if (spot > w->numpoints)
01049 {
01050 Error("AddWindingPoint: num > w->numpoints");
01051 }
01052 if (spot < 0)
01053 {
01054 Error("AddWindingPoint: num < 0");
01055 }
01056 neww = AllocWinding(w->numpoints + 1);
01057 neww->numpoints = w->numpoints + 1;
01058 for (i = 0, j = 0; i < neww->numpoints; i++)
01059 {
01060 if (i == spot)
01061 {
01062 VectorCopy(point, neww->p[i]);
01063 }
01064 else
01065 {
01066 VectorCopy(w->p[j], neww->p[i]);
01067 j++;
01068 }
01069 }
01070 return neww;
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080 #define MELT_ON_EPSILON 0.2
01081
01082 int PointOnWinding(winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot)
01083 {
01084 int i, j;
01085 vec3_t v1, v2;
01086 vec3_t edgenormal, edgevec;
01087 float edgedist, dot;
01088
01089 *spot = 0;
01090
01091 dot = DotProduct(point, normal) - dist;
01092 if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) return false;
01093
01094 for (i = 0; i < w->numpoints; i++)
01095 {
01096 j = (i+1) % w->numpoints;
01097
01098 VectorSubtract(w->p[j], w->p[i], edgevec);
01099 CrossProduct(normal, edgevec, edgenormal);
01100 VectorNormalize(edgenormal);
01101 edgedist = DotProduct(edgenormal, w->p[i]);
01102
01103 dot = DotProduct(point, edgenormal) - edgedist;
01104 if (dot < -MELT_ON_EPSILON || dot > MELT_ON_EPSILON) continue;
01105
01106 VectorSubtract(point, w->p[i], v1);
01107
01108 VectorSubtract(point, w->p[j], v2);
01109
01110
01111 if (VectorNormalize(v1) < 0.5) return false;
01112 if (VectorNormalize(v2) < 0.5) return false;
01113
01114
01115
01116 if (DotProduct(v1, v2) < -0.99)
01117 {
01118 *spot = i + 1;
01119 return true;
01120 }
01121 }
01122 return false;
01123 }
01124
01125
01126
01127
01128
01129
01130 int FindPlaneSeperatingWindings(winding_t *w1, winding_t *w2, vec3_t dir,
01131 vec3_t normal, float *dist)
01132 {
01133 int i, i2, j, j2, n;
01134 int sides1[3], sides2[3];
01135 float dist1, dist2, dot, diff;
01136 vec3_t normal1, normal2;
01137 vec3_t v1, v2;
01138
01139 for (i = 0; i < w1->numpoints; i++)
01140 {
01141 i2 = (i+1) % w1->numpoints;
01142
01143 VectorSubtract(w1->p[i2], w1->p[i], v1);
01144 if (VectorLength(v1) < 0.1)
01145 {
01146
01147 continue;
01148 }
01149 CrossProduct(v1, dir, normal1);
01150 VectorNormalize(normal1);
01151 dist1 = DotProduct(normal1, w1->p[i]);
01152
01153 for (j = 0; j < w2->numpoints; j++)
01154 {
01155 j2 = (j+1) % w2->numpoints;
01156
01157 VectorSubtract(w2->p[j2], w2->p[j], v2);
01158 if (VectorLength(v2) < 0.1)
01159 {
01160
01161 continue;
01162 }
01163 CrossProduct(v2, dir, normal2);
01164 VectorNormalize(normal2);
01165 dist2 = DotProduct(normal2, w2->p[j]);
01166
01167 diff = dist1 - dist2;
01168 if (diff < -0.1 || diff > 0.1)
01169 {
01170 dist2 = -dist2;
01171 VectorNegate(normal2, normal2);
01172 diff = dist1 - dist2;
01173 if (diff < -0.1 || diff > 0.1) continue;
01174 }
01175
01176 for (n = 0; n < 3; n++)
01177 {
01178 diff = normal1[n] - normal2[n];
01179 if (diff < -0.0001 || diff > 0.0001) break;
01180 }
01181 if (n != 3) continue;
01182
01183
01184 sides1[0] = sides1[1] = sides1[2] = 0;
01185 for (n = 0; n < w1->numpoints; n++)
01186 {
01187 dot = DotProduct(w1->p[n], normal1) - dist1;
01188 if (dot > 0.1) sides1[0]++;
01189 else if (dot < -0.1) sides1[1]++;
01190 else sides1[2]++;
01191 }
01192
01193
01194 sides2[0] = sides2[1] = sides2[2] = 0;
01195 for (n = 0; n < w2->numpoints; n++)
01196 {
01197
01198 dot = DotProduct(w2->p[n], normal1) - dist1;
01199 if (dot > 0.1) sides2[0]++;
01200 else if (dot < -0.1) sides2[1]++;
01201 else sides2[2]++;
01202 }
01203
01204 if (sides1[0] && sides1[1])
01205 {
01206 Log_Write("FindPlaneSeperatingWindings: winding1 non-convex\r\n");
01207 continue;
01208 }
01209
01210 if (sides2[0] && sides2[1])
01211 {
01212 Log_Write("FindPlaneSeperatingWindings: winding2 non-convex\r\n");
01213 continue;
01214 }
01215
01216 if ((!sides1[0] && !sides1[1]) || (!sides2[0] && !sides2[1]))
01217 {
01218
01219 continue;
01220 }
01221
01222 if ((!sides1[0] && !sides2[1]) || (!sides1[1] && !sides2[0]))
01223 {
01224 VectorCopy(normal1, normal);
01225 *dist = dist1;
01226 return true;
01227 }
01228 }
01229 }
01230 return false;
01231 }
01232
01233
01234
01235
01236
01237
01238 #define WCONVEX_EPSILON 0.2
01239
01240 int WindingsNonConvex(winding_t *w1, winding_t *w2,
01241 vec3_t normal1, vec3_t normal2,
01242 float dist1, float dist2)
01243 {
01244 int i;
01245
01246 if (!w1 || !w2) return false;
01247
01248
01249 for (i = 0; i < w1->numpoints; i++)
01250 {
01251 if (DotProduct(normal2, w1->p[i]) - dist2 > WCONVEX_EPSILON) return true;
01252 }
01253
01254 for (i = 0; i < w2->numpoints; i++)
01255 {
01256 if (DotProduct(normal1, w2->p[i]) - dist1 > WCONVEX_EPSILON) return true;
01257 }
01258
01259 return false;
01260 }
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342