polylib.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 1997-2001 Id Software, Inc.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "shared.h"
00028 #include "polylib.h"
00029 
00030 static int c_active_windings;
00031 static int c_peak_windings;
00032 
00033 #define BOGUS_RANGE 8192
00034 
00040 winding_t *AllocWinding (int points)
00041 {
00042     if (threadstate.numthreads == 1) {
00043         c_active_windings++;
00044         c_peak_windings = c_active_windings > c_peak_windings ? c_active_windings : c_peak_windings;
00045     }
00046 
00047     return Mem_Alloc(sizeof(vec3_t) * points + sizeof(int));
00048 }
00049 
00053 void FreeWinding (winding_t *w)
00054 {
00055     if (*(unsigned *)w == 0xdeaddead)
00056         Sys_Error("FreeWinding: freed a freed winding");
00057     *(unsigned *)w = 0xdeaddead;
00058 
00059     if (threadstate.numthreads == 1)
00060         c_active_windings--;
00061     Mem_Free(w);
00062 }
00063 
00064 void RemoveColinearPoints (winding_t *w)
00065 {
00066     int i, nump = 0;
00067     vec3_t v1, v2;
00068     vec3_t p[MAX_POINTS_ON_WINDING];
00069 
00070     for (i = 0; i < w->numpoints; i++) {
00071         const int j = (i + 1) % w->numpoints;
00072         const int k = (i + w->numpoints - 1) % w->numpoints;
00073         VectorSubtract(w->p[j], w->p[i], v1);
00074         VectorSubtract(w->p[i], w->p[k], v2);
00075         VectorNormalize(v1);
00076         VectorNormalize(v2);
00077         if (DotProduct(v1, v2) < 0.999) {
00078             VectorCopy(w->p[i], p[nump]);
00079             nump++;
00080         }
00081     }
00082 
00083     if (nump == w->numpoints)
00084         return;
00085 
00086     w->numpoints = nump;
00087     memcpy(w->p, p, nump * sizeof(p[0]));
00088 }
00089 
00090 vec_t WindingArea (const winding_t *w)
00091 {
00092     int i;
00093     vec3_t d1, d2, cross;
00094     vec_t total;
00095 
00096     total = 0;
00097     for (i = 2; i < w->numpoints; i++) {
00098         VectorSubtract(w->p[i - 1], w->p[0], d1);
00099         VectorSubtract(w->p[i], w->p[0], d2);
00100         CrossProduct(d1, d2, cross);
00101         total += VectorLength(cross);
00102     }
00103     return total * 0.5f;
00104 }
00105 
00106 void WindingBounds (const winding_t *w, vec3_t mins, vec3_t maxs)
00107 {
00108     int i, j;
00109 
00110     mins[0] = mins[1] = mins[2] = 99999;
00111     maxs[0] = maxs[1] = maxs[2] = -99999;
00112 
00113     for (i = 0; i < w->numpoints; i++) {
00114         for (j = 0; j < 3; j++) {
00115             const vec_t v = w->p[i][j];
00116             if (v < mins[j])
00117                 mins[j] = v;
00118             if (v > maxs[j])
00119                 maxs[j] = v;
00120         }
00121     }
00122 }
00123 
00124 void WindingCenter (const winding_t *w, vec3_t center)
00125 {
00126     int i;
00127     vec_t scale;
00128 
00129     VectorCopy(vec3_origin, center);
00130     for (i = 0; i < w->numpoints; i++)
00131         VectorAdd(w->p[i], center, center);
00132 
00133     scale = 1.0 / w->numpoints;
00134     VectorScale(center, scale, center);
00135 }
00136 
00137 winding_t *BaseWindingForPlane (const vec3_t normal, const vec_t dist)
00138 {
00139     int i, x;
00140     vec_t max, v;
00141     vec3_t org, vright, vup;
00142     winding_t *w;
00143 
00144     /* find the major axis */
00145     max = -BOGUS_RANGE;
00146     x = -1;
00147     for (i = 0; i < 3; i++) {
00148         v = fabs(normal[i]);
00149         if (v > max) {
00150             x = i;
00151             max = v;
00152         }
00153     }
00154     if (x == -1)
00155         Sys_Error("BaseWindingForPlane: no axis found");
00156 
00157     VectorCopy(vec3_origin, vup);
00158     /* axis */
00159     switch (x) {
00160     case 0:
00161     case 1:
00162         vup[2] = 1;
00163         break;
00164     case 2:
00165         vup[0] = 1;
00166         break;
00167     }
00168 
00169     v = DotProduct(vup, normal);
00170     VectorMA(vup, -v, normal, vup);
00171     VectorNormalize(vup);
00172 
00173     VectorScale(normal, dist, org);
00174 
00175     CrossProduct(vup, normal, vright);
00176 
00177     VectorScale(vup, 8192, vup);
00178     VectorScale(vright, 8192, vright);
00179 
00180     /* project a really big axis aligned box onto the plane */
00181     w = AllocWinding(4);
00182     if (!w)
00183         return NULL;
00184 
00185     VectorSubtract(org, vright, w->p[0]);
00186     VectorAdd(w->p[0], vup, w->p[0]);
00187 
00188     VectorAdd(org, vright, w->p[1]);
00189     VectorAdd(w->p[1], vup, w->p[1]);
00190 
00191     VectorAdd(org, vright, w->p[2]);
00192     VectorSubtract(w->p[2], vup, w->p[2]);
00193 
00194     VectorSubtract(org, vright, w->p[3]);
00195     VectorSubtract(w->p[3], vup, w->p[3]);
00196 
00197     w->numpoints = 4;
00198 
00199     return w;
00200 }
00201 
00207 winding_t *CopyWinding (const winding_t *w)
00208 {
00209     winding_t *c = AllocWinding(w->numpoints);
00210     const ptrdiff_t size = (ptrdiff_t)((winding_t *)0)->p[w->numpoints];
00211     memcpy(c, w, size);
00212     return c;
00213 }
00214 
00215 winding_t *ReverseWinding (const winding_t *w)
00216 {
00217     int i;
00218     winding_t *c = AllocWinding(w->numpoints);
00219 
00220     for (i = 0; i < w->numpoints; i++) {
00221         VectorCopy(w->p[w->numpoints - 1 - i], c->p[i]);
00222     }
00223     c->numpoints = w->numpoints;
00224     return c;
00225 }
00226 
00227 void ClipWindingEpsilon (const winding_t *in, const vec3_t normal, const vec_t dist,
00228         const vec_t epsilon, winding_t **front, winding_t **back)
00229 {
00230     vec_t dists[MAX_POINTS_ON_WINDING + 4];
00231     int sides[MAX_POINTS_ON_WINDING + 4];
00232     int counts[3];
00233     vec_t dot;
00234     int i, j;
00235     winding_t *f, *b;
00236     int maxpts;
00237 
00238     VectorClear(counts);
00239 
00240     /* determine sides for each point */
00241     for (i = 0; i < in->numpoints; i++) {
00242         dot = DotProduct(in->p[i], normal);
00243         dot -= dist;
00244         dists[i] = dot;
00245         if (dot > epsilon)
00246             sides[i] = SIDE_FRONT;
00247         else if (dot < -epsilon)
00248             sides[i] = SIDE_BACK;
00249         else {
00250             sides[i] = SIDE_ON;
00251         }
00252         counts[sides[i]]++;
00253     }
00254     sides[i] = sides[0];
00255     dists[i] = dists[0];
00256 
00257     if (!counts[0]) {
00258         *back = CopyWinding(in);
00259         *front = NULL;
00260         return;
00261     }
00262     if (!counts[1]) {
00263         *front = CopyWinding(in);
00264         *back = NULL;
00265         return;
00266     }
00267 
00268     /* can't use counts[0] + 2 because of floating point grouping errors */
00269     maxpts = in->numpoints + 4;
00270 
00271     *front = f = AllocWinding(maxpts);
00272     *back = b = AllocWinding(maxpts);
00273 
00274     for (i = 0; i < in->numpoints; i++) {
00275         const vec_t *p1 = in->p[i];
00276         const vec_t *p2;
00277         vec3_t mid;
00278 
00279         if (sides[i] == SIDE_ON) {
00280             VectorCopy(p1, f->p[f->numpoints]);
00281             f->numpoints++;
00282             VectorCopy(p1, b->p[b->numpoints]);
00283             b->numpoints++;
00284             continue;
00285         }
00286 
00287         if (sides[i] == SIDE_FRONT) {
00288             VectorCopy(p1, f->p[f->numpoints]);
00289             f->numpoints++;
00290         }
00291         if (sides[i] == SIDE_BACK) {
00292             VectorCopy(p1, b->p[b->numpoints]);
00293             b->numpoints++;
00294         }
00295 
00296         if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
00297             continue;
00298 
00299         /* generate a split point */
00300         p2 = in->p[(i + 1) % in->numpoints];
00301 
00302         dot = dists[i] / (dists[i]-dists[i + 1]);
00303         /* avoid round off error when possible */
00304         for (j = 0; j < 3; j++) {
00305             if (normal[j] == 1)
00306                 mid[j] = dist;
00307             else if (normal[j] == -1)
00308                 mid[j] = -dist;
00309             else
00310                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00311         }
00312 
00313         VectorCopy(mid, f->p[f->numpoints]);
00314         f->numpoints++;
00315         VectorCopy(mid, b->p[b->numpoints]);
00316         b->numpoints++;
00317     }
00318 
00319     if (f->numpoints > maxpts || b->numpoints > maxpts)
00320         Sys_Error("ClipWinding: points exceeded estimate");
00321     if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
00322         Sys_Error("ClipWinding: MAX_POINTS_ON_WINDING");
00323 }
00324 
00325 void ChopWindingInPlace (winding_t **inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
00326 {
00327     winding_t *in;
00329     vec_t dists[MAX_POINTS_ON_WINDING + 4];
00330     int sides[MAX_POINTS_ON_WINDING + 4];
00331     int counts[3];
00332     vec_t dot;
00333     int i, j;
00334     vec3_t mid;
00335     winding_t *f;
00336     int maxpts;
00337 
00338     in = *inout;
00339     VectorClear(counts);
00340 
00341     /* determine sides for each point */
00342     for (i = 0; i < in->numpoints; i++) {
00343         dot = DotProduct(in->p[i], normal);
00344         dot -= dist;
00345         dists[i] = dot;
00346         if (dot > epsilon)
00347             sides[i] = SIDE_FRONT;
00348         else if (dot < -epsilon)
00349             sides[i] = SIDE_BACK;
00350         else {
00351             sides[i] = SIDE_ON;
00352         }
00353         counts[sides[i]]++;
00354     }
00355     sides[i] = sides[0];
00356     dists[i] = dists[0];
00357 
00358     if (!counts[0]) {
00359         FreeWinding(in);
00360         *inout = NULL;
00361         return;
00362     }
00363     if (!counts[1])
00364         return;     /* inout stays the same */
00365 
00366     /* cant use counts[0] + 2 because of fp grouping errors */
00367     maxpts = in->numpoints + 4;
00368 
00369     f = AllocWinding(maxpts);
00370 
00371     for (i = 0; i < in->numpoints; i++) {
00372         const vec_t *p1 = in->p[i];
00373         const vec_t *p2;
00374 
00375         if (sides[i] == SIDE_ON) {
00376             VectorCopy(p1, f->p[f->numpoints]);
00377             f->numpoints++;
00378             continue;
00379         }
00380 
00381         if (sides[i] == SIDE_FRONT) {
00382             VectorCopy(p1, f->p[f->numpoints]);
00383             f->numpoints++;
00384         }
00385 
00386         if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
00387             continue;
00388 
00389         /* generate a split point */
00390         p2 = in->p[(i + 1) % in->numpoints];
00391 
00392         dot = dists[i] / (dists[i] - dists[i + 1]);
00393         /* avoid round off error when possible */
00394         for (j = 0; j < 3; j++) {
00395             if (normal[j] == 1)
00396                 mid[j] = dist;
00397             else if (normal[j] == -1)
00398                 mid[j] = -dist;
00399             else
00400                 mid[j] = p1[j] + dot * (p2[j] - p1[j]);
00401         }
00402 
00403         VectorCopy(mid, f->p[f->numpoints]);
00404         f->numpoints++;
00405     }
00406 
00407     if (f->numpoints > maxpts)
00408         Sys_Error("ClipWinding: points exceeded estimate");
00409     if (f->numpoints > MAX_POINTS_ON_WINDING)
00410         Sys_Error("ClipWinding: MAX_POINTS_ON_WINDING");
00411 
00412     FreeWinding(in);
00413     *inout = f;
00414 }
00415 
00416 
00421 winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist)
00422 {
00423     winding_t *f, *b;
00424 
00425     ClipWindingEpsilon(in, normal, dist, ON_EPSILON, &f, &b);
00426     FreeWinding(in);
00427     if (b)
00428         FreeWinding(b);
00429     return f;
00430 }

Generated by  doxygen 1.6.2