00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stdafx.h"
00025 #include <assert.h>
00026 #include "qe3.h"
00027 #include "winding.h"
00028
00029 #define BOGUS_RANGE 18000
00030
00031
00032
00033
00034
00035
00036 #define NORMAL_EPSILON 0.0001
00037 #define DIST_EPSILON 0.02
00038
00039 int Plane_Equal(plane_t *a, plane_t *b, int flip)
00040 {
00041 vec3_t normal;
00042 float dist;
00043
00044 if (flip) {
00045 normal[0] = - b->normal[0];
00046 normal[1] = - b->normal[1];
00047 normal[2] = - b->normal[2];
00048 dist = - b->dist;
00049 }
00050 else {
00051 normal[0] = b->normal[0];
00052 normal[1] = b->normal[1];
00053 normal[2] = b->normal[2];
00054 dist = b->dist;
00055 }
00056 if (
00057 fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
00058 && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
00059 && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
00060 && fabs(a->dist - dist) < DIST_EPSILON )
00061 return true;
00062 return false;
00063 }
00064
00065
00066
00067
00068
00069
00070 int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane)
00071 {
00072 vec3_t v1, v2;
00073
00074 VectorSubtract(p2, p1, v1);
00075 VectorSubtract(p3, p1, v2);
00076
00077 CrossProduct(v1, v2, plane->normal);
00078 if (VectorNormalize(plane->normal) < 0.1) return false;
00079 plane->dist = DotProduct(p1, plane->normal);
00080 return true;
00081 }
00082
00083
00084
00085
00086
00087
00088 int Point_Equal(vec3_t p1, vec3_t p2, float epsilon)
00089 {
00090 int i;
00091
00092 for (i = 0; i < 3; i++)
00093 {
00094 if (fabs(p1[i] - p2[i]) > epsilon) return false;
00095 }
00096 return true;
00097 }
00098
00099
00100
00101
00102
00103
00104
00105 winding_t *Winding_BaseForPlane (plane_t *p)
00106 {
00107 int i, x;
00108 vec_t max, v;
00109 vec3_t org, vright, vup;
00110 winding_t *w;
00111
00112
00113
00114 max = -BOGUS_RANGE;
00115 x = -1;
00116 for (i=0 ; i<3; i++)
00117 {
00118 v = fabs(p->normal[i]);
00119 if (v > max)
00120 {
00121 x = i;
00122 max = v;
00123 }
00124 }
00125 if (x==-1)
00126 Error ("Winding_BaseForPlane: no axis found");
00127
00128 VectorCopy (vec3_origin, vup);
00129 switch (x)
00130 {
00131 case 0:
00132 case 1:
00133 vup[2] = 1;
00134 break;
00135 case 2:
00136 vup[0] = 1;
00137 break;
00138 }
00139
00140
00141 v = DotProduct (vup, p->normal);
00142 VectorMA (vup, -v, p->normal, vup);
00143 VectorNormalize (vup);
00144
00145 VectorScale (p->normal, p->dist, org);
00146
00147 CrossProduct (vup, p->normal, vright);
00148
00149 VectorScale (vup, BOGUS_RANGE, vup);
00150 VectorScale (vright, BOGUS_RANGE, vright);
00151
00152
00153 w = Winding_Alloc (4);
00154
00155 VectorSubtract (org, vright, w->points[0]);
00156 VectorAdd (w->points[0], vup, w->points[0]);
00157
00158 VectorAdd (org, vright, w->points[1]);
00159 VectorAdd (w->points[1], vup, w->points[1]);
00160
00161 VectorAdd (org, vright, w->points[2]);
00162 VectorSubtract (w->points[2], vup, w->points[2]);
00163
00164 VectorSubtract (org, vright, w->points[3]);
00165 VectorSubtract (w->points[3], vup, w->points[3]);
00166
00167 w->numpoints = 4;
00168
00169 return w;
00170 }
00171
00172
00173
00174
00175
00176
00177 winding_t *Winding_Alloc (int points)
00178 {
00179 winding_t *w;
00180 int size;
00181
00182 if (points > MAX_POINTS_ON_WINDING)
00183 Error ("Winding_Alloc: %i points", points);
00184
00185 size = (int)((winding_t *)0)->points[points];
00186 w = (winding_t*) malloc (size);
00187 memset (w, 0, size);
00188 w->maxpoints = points;
00189
00190 return w;
00191 }
00192
00193
00194 void Winding_Free (winding_t *w)
00195 {
00196 free(w);
00197 }
00198
00199
00200
00201
00202
00203
00204
00205 winding_t *Winding_Clone(winding_t *w)
00206 {
00207 int size;
00208 winding_t *c;
00209
00210 size = (int)((winding_t *)0)->points[w->numpoints];
00211 c = (winding_t*)qmalloc (size);
00212 memcpy (c, w, size);
00213 return c;
00214 }
00215
00216
00217
00218
00219
00220
00221 winding_t *Winding_Reverse(winding_t *w)
00222 {
00223 int i;
00224 winding_t *c;
00225
00226 c = Winding_Alloc(w->numpoints);
00227 for (i = 0; i < w->numpoints; i++)
00228 {
00229 VectorCopy (w->points[w->numpoints-1-i], c->points[i]);
00230 }
00231 c->numpoints = w->numpoints;
00232 return c;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 void Winding_RemovePoint(winding_t *w, int point)
00242 {
00243 if (point < 0 || point >= w->numpoints)
00244 Error("Winding_RemovePoint: point out of range");
00245
00246 if (point < w->numpoints-1)
00247 {
00248 memmove(&w->points[point], &w->points[point+1], (int)((winding_t *)0)->points[w->numpoints - point - 1]);
00249 }
00250 w->numpoints--;
00251 }
00252
00253
00254
00255
00256
00257
00258 winding_t *Winding_InsertPoint(winding_t *w, vec3_t point, int spot)
00259 {
00260 int i, j;
00261 winding_t *neww;
00262
00263 if (spot > w->numpoints)
00264 {
00265 Error("Winding_InsertPoint: spot > w->numpoints");
00266 }
00267 if (spot < 0)
00268 {
00269 Error("Winding_InsertPoint: spot < 0");
00270 }
00271 neww = Winding_Alloc(w->numpoints + 1);
00272 neww->numpoints = w->numpoints + 1;
00273 for (i = 0, j = 0; i < neww->numpoints; i++)
00274 {
00275 if (i == spot)
00276 {
00277 VectorCopy(point, neww->points[i]);
00278 }
00279 else
00280 {
00281 VectorCopy(w->points[j], neww->points[i]);
00282 j++;
00283 }
00284 }
00285 return neww;
00286 }
00287
00288
00289
00290
00291
00292
00293 #define EDGE_LENGTH 0.2
00294
00295 int Winding_IsTiny (winding_t *w)
00296 {
00297 int i, j;
00298 vec_t len;
00299 vec3_t delta;
00300 int edges;
00301
00302 edges = 0;
00303 for (i=0 ; i<w->numpoints ; i++)
00304 {
00305 j = i == w->numpoints - 1 ? 0 : i+1;
00306 VectorSubtract (w->points[j], w->points[i], delta);
00307 len = VectorLength (delta);
00308 if (len > EDGE_LENGTH)
00309 {
00310 if (++edges == 3)
00311 return false;
00312 }
00313 }
00314 return true;
00315 }
00316
00317
00318
00319
00320
00321
00322 int Winding_IsHuge(winding_t *w)
00323 {
00324 int i, j;
00325
00326 for (i=0 ; i<w->numpoints ; i++)
00327 {
00328 for (j=0 ; j<3 ; j++)
00329 if (w->points[i][j] < -BOGUS_RANGE+1 || w->points[i][j] > BOGUS_RANGE-1)
00330 return true;
00331 }
00332 return false;
00333 }
00334
00335
00336
00337
00338
00339
00340 #define WCONVEX_EPSILON 0.2
00341
00342 int Winding_PlanesConcave(winding_t *w1, winding_t *w2,
00343 vec3_t normal1, vec3_t normal2,
00344 float dist1, float dist2)
00345 {
00346 int i;
00347
00348 if (!w1 || !w2) return false;
00349
00350
00351 for (i = 0; i < w1->numpoints; i++)
00352 {
00353 if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return true;
00354 }
00355
00356 for (i = 0; i < w2->numpoints; i++)
00357 {
00358 if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return true;
00359 }
00360
00361 return false;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 winding_t *Winding_Clip (winding_t *in, plane_t *split, qboolean keepon)
00375 {
00376 vec_t dists[MAX_POINTS_ON_WINDING];
00377 int sides[MAX_POINTS_ON_WINDING];
00378 int counts[3];
00379 vec_t dot;
00380 int i, j;
00381 vec_t *p1, *p2;
00382 vec3_t mid;
00383 winding_t *neww;
00384 int maxpts;
00385
00386 counts[0] = counts[1] = counts[2] = 0;
00387
00388
00389 for (i=0 ; i<in->numpoints ; i++)
00390 {
00391 dot = DotProduct (in->points[i], split->normal);
00392 dot -= split->dist;
00393 dists[i] = dot;
00394 if (dot > ON_EPSILON)
00395 sides[i] = SIDE_FRONT;
00396 else if (dot < -ON_EPSILON)
00397 sides[i] = SIDE_BACK;
00398 else
00399 {
00400 sides[i] = SIDE_ON;
00401 }
00402 counts[sides[i]]++;
00403 }
00404 sides[i] = sides[0];
00405 dists[i] = dists[0];
00406
00407 if (keepon && !counts[0] && !counts[1])
00408 return in;
00409
00410 if (!counts[0])
00411 {
00412 Winding_Free (in);
00413 return NULL;
00414 }
00415 if (!counts[1])
00416 return in;
00417
00418 maxpts = in->numpoints+4;
00419
00420 neww = Winding_Alloc (maxpts);
00421
00422 for (i=0 ; i<in->numpoints ; i++)
00423 {
00424 p1 = in->points[i];
00425
00426 if (sides[i] == SIDE_ON)
00427 {
00428 VectorCopy (p1, neww->points[neww->numpoints]);
00429 neww->numpoints++;
00430 continue;
00431 }
00432
00433 if (sides[i] == SIDE_FRONT)
00434 {
00435 VectorCopy (p1, neww->points[neww->numpoints]);
00436 neww->numpoints++;
00437 }
00438
00439 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00440 continue;
00441
00442
00443 p2 = in->points[(i+1)%in->numpoints];
00444
00445 dot = dists[i] / (dists[i]-dists[i+1]);
00446 for (j=0 ; j<3 ; j++)
00447 {
00448 if (split->normal[j] == 1)
00449 mid[j] = split->dist;
00450 else if (split->normal[j] == -1)
00451 mid[j] = -split->dist;
00452 else
00453 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00454 }
00455
00456 VectorCopy (mid, neww->points[neww->numpoints]);
00457 neww->numpoints++;
00458 }
00459
00460 if (neww->numpoints > maxpts)
00461 Error ("Winding_Clip: points exceeded estimate");
00462
00463
00464 Winding_Free (in);
00465
00466 return neww;
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist,
00478 vec_t epsilon, winding_t **front, winding_t **back)
00479 {
00480 vec_t dists[MAX_POINTS_ON_WINDING+4];
00481 int sides[MAX_POINTS_ON_WINDING+4];
00482 int counts[3];
00483 vec_t dot;
00484 int i, j;
00485 vec_t *p1, *p2;
00486 vec3_t mid;
00487 winding_t *f, *b;
00488 int maxpts;
00489
00490 counts[0] = counts[1] = counts[2] = 0;
00491
00492
00493 for (i = 0; i < in->numpoints; i++)
00494 {
00495 dot = DotProduct (in->points[i], normal);
00496 dot -= dist;
00497 dists[i] = dot;
00498 if (dot > epsilon)
00499 sides[i] = SIDE_FRONT;
00500 else if (dot < -epsilon)
00501 sides[i] = SIDE_BACK;
00502 else
00503 {
00504 sides[i] = SIDE_ON;
00505 }
00506 counts[sides[i]]++;
00507 }
00508 sides[i] = sides[0];
00509 dists[i] = dists[0];
00510
00511 *front = *back = NULL;
00512
00513 if (!counts[0])
00514 {
00515 *back = Winding_Clone(in);
00516 return;
00517 }
00518 if (!counts[1])
00519 {
00520 *front = Winding_Clone(in);
00521 return;
00522 }
00523
00524 maxpts = in->numpoints+4;
00525
00526
00527 *front = f = Winding_Alloc (maxpts);
00528 *back = b = Winding_Alloc (maxpts);
00529
00530 for (i = 0; i < in->numpoints; i++)
00531 {
00532 p1 = in->points[i];
00533
00534 if (sides[i] == SIDE_ON)
00535 {
00536 VectorCopy (p1, f->points[f->numpoints]);
00537 f->numpoints++;
00538 VectorCopy (p1, b->points[b->numpoints]);
00539 b->numpoints++;
00540 continue;
00541 }
00542
00543 if (sides[i] == SIDE_FRONT)
00544 {
00545 VectorCopy (p1, f->points[f->numpoints]);
00546 f->numpoints++;
00547 }
00548 if (sides[i] == SIDE_BACK)
00549 {
00550 VectorCopy (p1, b->points[b->numpoints]);
00551 b->numpoints++;
00552 }
00553
00554 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00555 continue;
00556
00557
00558 p2 = in->points[(i+1)%in->numpoints];
00559
00560 dot = dists[i] / (dists[i]-dists[i+1]);
00561 for (j = 0; j < 3; j++)
00562 {
00563
00564 if (normal[j] == 1)
00565 mid[j] = dist;
00566 else if (normal[j] == -1)
00567 mid[j] = -dist;
00568 else
00569 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00570 }
00571
00572 VectorCopy (mid, f->points[f->numpoints]);
00573 f->numpoints++;
00574 VectorCopy (mid, b->points[b->numpoints]);
00575 b->numpoints++;
00576 }
00577
00578 if (f->numpoints > maxpts || b->numpoints > maxpts)
00579 Error ("Winding_Clip: points exceeded estimate");
00580 if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
00581 Error ("Winding_Clip: MAX_POINTS_ON_WINDING");
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 #define CONTINUOUS_EPSILON 0.005
00598
00599 winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep)
00600 {
00601 vec_t *p1, *p2, *p3, *p4, *back;
00602 winding_t *newf;
00603 int i, j, k, l;
00604 vec3_t normal, delta;
00605 vec_t dot;
00606 qboolean keep1, keep2;
00607
00608
00609
00610
00611
00612 p1 = p2 = NULL;
00613 j = 0;
00614
00615 for (i = 0; i < f1->numpoints; i++)
00616 {
00617 p1 = f1->points[i];
00618 p2 = f1->points[(i+1) % f1->numpoints];
00619 for (j = 0; j < f2->numpoints; j++)
00620 {
00621 p3 = f2->points[j];
00622 p4 = f2->points[(j+1) % f2->numpoints];
00623 for (k = 0; k < 3; k++)
00624 {
00625 if (fabs(p1[k] - p4[k]) > 0.1)
00626 break;
00627 if (fabs(p2[k] - p3[k]) > 0.1)
00628 break;
00629 }
00630 if (k==3)
00631 break;
00632 }
00633 if (j < f2->numpoints)
00634 break;
00635 }
00636
00637 if (i == f1->numpoints)
00638 return NULL;
00639
00640
00641
00642
00643
00644 back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
00645 VectorSubtract (p1, back, delta);
00646 CrossProduct (planenormal, delta, normal);
00647 VectorNormalize (normal);
00648
00649 back = f2->points[(j+2)%f2->numpoints];
00650 VectorSubtract (back, p1, delta);
00651 dot = DotProduct (delta, normal);
00652 if (dot > CONTINUOUS_EPSILON)
00653 return NULL;
00654 keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00655
00656 back = f1->points[(i+2)%f1->numpoints];
00657 VectorSubtract (back, p2, delta);
00658 CrossProduct (planenormal, delta, normal);
00659 VectorNormalize (normal);
00660
00661 back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
00662 VectorSubtract (back, p2, delta);
00663 dot = DotProduct (delta, normal);
00664 if (dot > CONTINUOUS_EPSILON)
00665 return NULL;
00666 keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
00667
00668
00669
00670
00671 newf = Winding_Alloc (f1->numpoints + f2->numpoints);
00672
00673
00674 for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
00675 {
00676 if (!keep && k==(i+1)%f1->numpoints && !keep2)
00677 continue;
00678
00679 VectorCopy (f1->points[k], newf->points[newf->numpoints]);
00680 newf->numpoints++;
00681 }
00682
00683
00684 for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
00685 {
00686 if (!keep && l==(j+1)%f2->numpoints && !keep1)
00687 continue;
00688 VectorCopy (f2->points[l], newf->points[newf->numpoints]);
00689 newf->numpoints++;
00690 }
00691
00692 return newf;
00693 }
00694
00695
00696
00697
00698
00699
00700 void Winding_Plane (winding_t *w, vec3_t normal, double *dist)
00701 {
00702 vec3_t v1, v2;
00703 int i;
00704
00705
00706 for (i = 0; i < w->numpoints; i++)
00707 {
00708 VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1);
00709 VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2);
00710 if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break;
00711 }
00712 CrossProduct(v2, v1, normal);
00713 VectorNormalize(normal);
00714 *dist = DotProduct(w->points[0], normal);
00715 }
00716
00717
00718
00719
00720
00721
00722 float Winding_Area (winding_t *w)
00723 {
00724 int i;
00725 vec3_t d1, d2, cross;
00726 float total;
00727
00728 total = 0;
00729 for (i=2 ; i<w->numpoints ; i++)
00730 {
00731 VectorSubtract (w->points[i-1], w->points[0], d1);
00732 VectorSubtract (w->points[i], w->points[0], d2);
00733 CrossProduct (d1, d2, cross);
00734 total += 0.5 * VectorLength ( cross );
00735 }
00736 return total;
00737 }
00738
00739
00740
00741
00742
00743
00744 void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs)
00745 {
00746 vec_t v;
00747 int i,j;
00748
00749 mins[0] = mins[1] = mins[2] = 99999;
00750 maxs[0] = maxs[1] = maxs[2] = -99999;
00751
00752 for (i=0 ; i<w->numpoints ; i++)
00753 {
00754 for (j=0 ; j<3 ; j++)
00755 {
00756 v = w->points[i][j];
00757 if (v < mins[j])
00758 mins[j] = v;
00759 if (v > maxs[j])
00760 maxs[j] = v;
00761 }
00762 }
00763 }
00764
00765
00766
00767
00768
00769
00770
00771 int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon)
00772 {
00773 int i;
00774 vec3_t dir, normal, pointvec;
00775
00776 for (i = 0; i < w->numpoints; i++)
00777 {
00778 VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir);
00779 VectorSubtract(point, w->points[i], pointvec);
00780
00781 CrossProduct(dir, plane->normal, normal);
00782
00783 if (DotProduct(pointvec, normal) < -epsilon) return false;
00784 }
00785 return true;
00786 }
00787
00788
00789
00790
00791
00792
00793 int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon)
00794 {
00795 float front, back, frac;
00796 vec3_t mid;
00797
00798 front = DotProduct(p1, plane->normal) - plane->dist;
00799 back = DotProduct(p2, plane->normal) - plane->dist;
00800
00801 if (front < -epsilon && back < -epsilon) return false;
00802 if (front > epsilon && back > epsilon) return false;
00803
00804 if (fabs(front-back) < 0.001)
00805 {
00806 VectorCopy(p2, mid);
00807 }
00808 else
00809 {
00810 frac = front/(front-back);
00811 mid[0] = p1[0] + (p2[0] - p1[0]) * frac;
00812 mid[1] = p1[1] + (p2[1] - p1[1]) * frac;
00813 mid[2] = p1[2] + (p2[2] - p1[2]) * frac;
00814 }
00815 return Winding_PointInside(w, plane, mid, epsilon);
00816 }
00817