00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
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
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
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
00300 p2 = in->p[(i + 1) % in->numpoints];
00301
00302 dot = dists[i] / (dists[i]-dists[i + 1]);
00303
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
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;
00365
00366
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
00390 p2 = in->p[(i + 1) % in->numpoints];
00391
00392 dot = dists[i] / (dists[i] - dists[i + 1]);
00393
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 }