UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
polylib.cpp
Go to the documentation of this file.
1 
7 /*
8 Copyright (C) 1997-2001 Id Software, Inc.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25 */
26 
27 #include "polylib.h"
28 #include "shared.h"
29 
30 
31 #define BOGUS_RANGE 8192
32 
38 winding_t* AllocWinding (int points)
39 {
40  return (winding_t*)Mem_Alloc(sizeof(vec3_t) * points + sizeof(int));
41 }
42 
47 {
48  if (*(unsigned* )w == 0xdeaddead)
49  Sys_Error("FreeWinding: freed a freed winding");
50  *(unsigned* )w = 0xdeaddead;
51 
52  Mem_Free(w);
53 }
54 
56 {
57  int nump = 0;
58  vec3_t v1, v2;
60 
61  for (int i = 0; i < w->numpoints; i++) {
62  const int j = (i + 1) % w->numpoints;
63  const int k = (i + w->numpoints - 1) % w->numpoints;
64  VectorSubtract(w->p[j], w->p[i], v1);
65  VectorSubtract(w->p[i], w->p[k], v2);
66  VectorNormalize(v1);
67  VectorNormalize(v2);
68  if (DotProduct(v1, v2) < 0.999) {
69  VectorCopy(w->p[i], p[nump]);
70  nump++;
71  }
72  }
73 
74  if (nump == w->numpoints)
75  return;
76 
77  w->numpoints = nump;
78  memcpy(w->p, p, nump * sizeof(p[0]));
79 }
80 
82 {
83  int i;
84  vec3_t d1, d2, cross;
85  vec_t total;
86 
87  total = 0;
88  for (i = 2; i < w->numpoints; i++) {
89  VectorSubtract(w->p[i - 1], w->p[0], d1);
90  VectorSubtract(w->p[i], w->p[0], d2);
91  CrossProduct(d1, d2, cross);
92  total += VectorLength(cross);
93  }
94  return total * 0.5f;
95 }
96 
97 void WindingBounds (const winding_t* w, vec3_t mins, vec3_t maxs)
98 {
99  ClearBounds(mins, maxs);
100 
101  for (int i = 0; i < w->numpoints; i++) {
102  AddPointToBounds(w->p[i], mins, maxs);
103  }
104 }
105 
106 void WindingCenter (const winding_t* w, vec3_t center)
107 {
108  VectorCopy(vec3_origin, center);
109  for (int i = 0; i < w->numpoints; i++)
110  VectorAdd(w->p[i], center, center);
111 
112  vec_t scale = 1.0 / w->numpoints;
113  VectorScale(center, scale, center);
114 }
115 
116 winding_t* BaseWindingForPlane (const vec3_t normal, const vec_t dist)
117 {
118  vec_t max, v;
119  vec3_t org, vright, vup;
120  winding_t* w;
121 
122  /* find the major axis */
123  max = -BOGUS_RANGE;
124  int x = -1;
125  for (int i = 0; i < 3; i++) {
126  v = fabs(normal[i]);
127  if (v > max) {
128  x = i;
129  max = v;
130  }
131  }
132  if (x == -1)
133  Sys_Error("BaseWindingForPlane: no axis found");
134 
135  VectorCopy(vec3_origin, vup);
136  /* axis */
137  switch (x) {
138  case 0:
139  case 1:
140  vup[2] = 1;
141  break;
142  case 2:
143  vup[0] = 1;
144  break;
145  }
146 
147  v = DotProduct(vup, normal);
148  VectorMA(vup, -v, normal, vup);
149  VectorNormalize(vup);
150 
151  VectorScale(normal, dist, org);
152 
153  CrossProduct(vup, normal, vright);
154 
155  VectorScale(vup, 8192, vup);
156  VectorScale(vright, 8192, vright);
157 
158  /* project a really big axis aligned box onto the plane */
159  w = AllocWinding(4);
160  if (!w)
161  return nullptr;
162 
163  VectorSubtract(org, vright, w->p[0]);
164  VectorAdd(w->p[0], vup, w->p[0]);
165 
166  VectorAdd(org, vright, w->p[1]);
167  VectorAdd(w->p[1], vup, w->p[1]);
168 
169  VectorAdd(org, vright, w->p[2]);
170  VectorSubtract(w->p[2], vup, w->p[2]);
171 
172  VectorSubtract(org, vright, w->p[3]);
173  VectorSubtract(w->p[3], vup, w->p[3]);
174 
175  w->numpoints = 4;
176 
177  return w;
178 }
179 
186 {
188  const ptrdiff_t size = (ptrdiff_t)((winding_t*)0)->p[w->numpoints];
189  memcpy(c, w, size);
190  return c;
191 }
192 
194 {
196 
197  for (int i = 0; i < w->numpoints; i++) {
198  VectorCopy(w->p[w->numpoints - 1 - i], c->p[i]);
199  }
200  c->numpoints = w->numpoints;
201  return c;
202 }
203 
204 void ClipWindingEpsilon (const winding_t* in, const vec3_t normal, const vec_t dist,
205  const vec_t epsilon, winding_t** front, winding_t** back)
206 {
207  vec_t dists[MAX_POINTS_ON_WINDING + 4];
208  int sides[MAX_POINTS_ON_WINDING + 4];
209  int counts[3];
210  int i;
211  winding_t* f, *b;
212 
213  VectorClear(counts);
214 
215  /* determine sides for each point */
216  for (i = 0; i < in->numpoints; i++) {
217  const vec_t dot = DotProduct(in->p[i], normal) - dist;
218  dists[i] = dot;
219  if (dot > epsilon)
220  sides[i] = SIDE_FRONT;
221  else if (dot < -epsilon)
222  sides[i] = SIDE_BACK;
223  else
224  sides[i] = SIDE_ON;
225  counts[sides[i]]++;
226  }
227  sides[i] = sides[0];
228  dists[i] = dists[0];
229 
230  if (!counts[0]) {
231  *back = CopyWinding(in);
232  *front = nullptr;
233  return;
234  }
235  if (!counts[1]) {
236  *front = CopyWinding(in);
237  *back = nullptr;
238  return;
239  }
240 
241  /* can't use counts[0] + 2 because of floating point grouping errors */
242  int maxpts = in->numpoints + 4;
243 
244  *front = f = AllocWinding(maxpts);
245  *back = b = AllocWinding(maxpts);
246 
247  for (i = 0; i < in->numpoints; i++) {
248  const vec_t* p1 = in->p[i];
249  const vec_t* p2;
250  vec_t dot;
251  vec3_t mid;
252 
253  if (sides[i] == SIDE_ON) {
254  VectorCopy(p1, f->p[f->numpoints]);
255  f->numpoints++;
256  VectorCopy(p1, b->p[b->numpoints]);
257  b->numpoints++;
258  continue;
259  }
260 
261  if (sides[i] == SIDE_FRONT) {
262  VectorCopy(p1, f->p[f->numpoints]);
263  f->numpoints++;
264  }
265  if (sides[i] == SIDE_BACK) {
266  VectorCopy(p1, b->p[b->numpoints]);
267  b->numpoints++;
268  }
269 
270  if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
271  continue;
272 
273  /* generate a split point */
274  p2 = in->p[(i + 1) % in->numpoints];
275 
276  dot = dists[i] / (dists[i] - dists[i + 1]);
277  /* avoid round off error when possible */
278  for (int j = 0; j < 3; j++) {
279  if (normal[j] == 1)
280  mid[j] = dist;
281  else if (normal[j] == -1)
282  mid[j] = -dist;
283  else
284  mid[j] = p1[j] + dot * (p2[j] - p1[j]);
285  }
286 
287  VectorCopy(mid, f->p[f->numpoints]);
288  f->numpoints++;
289  VectorCopy(mid, b->p[b->numpoints]);
290  b->numpoints++;
291  }
292 
293  if (f->numpoints > maxpts || b->numpoints > maxpts)
294  Sys_Error("ClipWinding: points exceeded estimate");
296  Sys_Error("ClipWinding: MAX_POINTS_ON_WINDING");
297 }
298 
299 void ChopWindingInPlace (winding_t** inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
300 {
302  vec_t dists[MAX_POINTS_ON_WINDING + 4];
303  int sides[MAX_POINTS_ON_WINDING + 4];
304  int counts[3];
305  int i;
306 
307  winding_t* in = *inout;
308  VectorClear(counts);
309 
310  /* determine sides for each point */
311  for (i = 0; i < in->numpoints; i++) {
312  const vec_t dot = DotProduct(in->p[i], normal) - dist;
313  dists[i] = dot;
314  if (dot > epsilon)
315  sides[i] = SIDE_FRONT;
316  else if (dot < -epsilon)
317  sides[i] = SIDE_BACK;
318  else {
319  sides[i] = SIDE_ON;
320  }
321  counts[sides[i]]++;
322  }
323  sides[i] = sides[0];
324  dists[i] = dists[0];
325 
326  if (!counts[0]) {
327  FreeWinding(in);
328  *inout = nullptr;
329  return;
330  }
331  if (!counts[1])
332  return; /* inout stays the same */
333 
334  /* cant use counts[0] + 2 because of fp grouping errors */
335  int maxpts = in->numpoints + 4;
336 
337  winding_t* f = AllocWinding(maxpts);
338 
339  for (i = 0; i < in->numpoints; i++) {
340  const vec_t* p1 = in->p[i];
341  const vec_t* p2;
342  vec_t dot;
343 
344  if (sides[i] == SIDE_ON) {
345  VectorCopy(p1, f->p[f->numpoints]);
346  f->numpoints++;
347  continue;
348  }
349 
350  if (sides[i] == SIDE_FRONT) {
351  VectorCopy(p1, f->p[f->numpoints]);
352  f->numpoints++;
353  }
354 
355  if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
356  continue;
357 
358  /* generate a split point */
359  p2 = in->p[(i + 1) % in->numpoints];
360 
361  dot = dists[i] / (dists[i] - dists[i + 1]);
362  /* avoid round off error when possible */
363  vec3_t mid;
364  for (int j = 0; j < 3; j++) {
365  if (normal[j] == 1)
366  mid[j] = dist;
367  else if (normal[j] == -1)
368  mid[j] = -dist;
369  else
370  mid[j] = p1[j] + dot * (p2[j] - p1[j]);
371  }
372 
373  VectorCopy(mid, f->p[f->numpoints]);
374  f->numpoints++;
375  }
376 
377  if (f->numpoints > maxpts)
378  Sys_Error("ClipWinding: points exceeded estimate");
380  Sys_Error("ClipWinding: MAX_POINTS_ON_WINDING");
381 
382  FreeWinding(in);
383  *inout = f;
384 }
385 
386 
392 {
393  winding_t* f, *b;
394 
395  ClipWindingEpsilon(in, normal, dist, ON_EPSILON, &f, &b);
396  FreeWinding(in);
397  if (b)
398  FreeWinding(b);
399  return f;
400 }
401 
402 #define EDGE_LENGTH 0.2
403 
408 {
409  int edges = 0;
410  for (int i = 0; i < w->numpoints; i++) {
411  const int j = ((i == w->numpoints - 1) ? 0 : i) + 1;
412  vec3_t delta;
413  VectorSubtract(w->p[j], w->p[i], delta);
414  vec_t len = VectorLength(delta);
415  if (len > EDGE_LENGTH) {
416  if (++edges == 3)
417  return false;
418  }
419  }
420  return true;
421 }
422 
427 bool WindingIsHuge (const winding_t* w)
428 {
429  for (int i = 0; i < w->numpoints; i++) {
430  for (int j = 0; j < 3; j++)
431  if (w->p[i][j] < -MAX_WORLD_WIDTH || w->p[i][j] > MAX_WORLD_WIDTH)
432  return true;
433  }
434  return false;
435 }
436 
437 #define SNAP_EPSILON 0.01
438 
443 static void SnapWeldVector (const vec3_t a, const vec3_t b, vec3_t out)
444 {
445  /* dummy check */
446  if (a == nullptr || b == nullptr || out == nullptr)
447  return;
448 
449  /* do each element */
450  for (int i = 0; i < 3; i++) {
451  /* round to integer */
452  const double ai = rint(a[i]);
453  const double bi = rint(a[i]);
454 
455  /* prefer exact integer */
456  if (ai == a[i])
457  out[i] = a[i];
458  else if (bi == b[i])
459  out[i] = b[i];
460 
461  /* use nearest */
462  else if (fabs(ai - a[i]) < fabs(bi - b[i]))
463  out[i] = a[i];
464  else
465  out[i] = b[i];
466 
467  /* snap */
468  vec_t outi = rint(out[i]);
469  if (fabs(outi - out[i]) <= SNAP_EPSILON)
470  out[i] = outi;
471  }
472 }
473 
479 {
480  /* dummy check */
481  if (!w)
482  return false;
483 
484  bool valid = true;
485 
486  /* check all verts */
487  for (int i = 0; i < w->numpoints; i++) {
488  /* get second point index */
489  const int j = (i + 1) % w->numpoints;
490  vec3_t vec;
491 
492  /* don't remove points if winding is a triangle */
493  if (w->numpoints == 3)
494  return valid;
495 
496  /* degenerate edge? */
497  VectorSubtract(w->p[i], w->p[j], vec);
498  float dist = VectorLength(vec);
499  if (dist < ON_EPSILON) {
500  valid = false;
501 
502  /* create an average point (ydnar 2002-01-26: using nearest-integer weld preference) */
503  SnapWeldVector(w->p[i], w->p[j], vec);
504  VectorCopy(vec, w->p[i]);
505 
506  /* move the remaining verts */
507  for (int k = i + 2; k < w->numpoints; k++)
508  VectorCopy(w->p[k], w->p[k - 1]);
509 
510  w->numpoints--;
511  }
512  }
513 
514  /* one last check and return */
515  if (w->numpoints < 3)
516  valid = false;
517  return valid;
518 }
winding_t * ChopWinding(winding_t *in, vec3_t normal, vec_t dist)
Definition: polylib.cpp:391
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition: mathlib.cpp:434
#define VectorCopy(src, dest)
Definition: vector.h:51
#define SIDE_BACK
Definition: defines.h:188
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
winding_t * CopyWinding(const winding_t *w)
Copy a winding with all its points allocated.
Definition: polylib.cpp:185
void WindingBounds(const winding_t *w, vec3_t mins, vec3_t maxs)
Definition: polylib.cpp:97
void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector)
Sets vector_out (vc) to vevtor1 (va) + scale * vector2 (vb)
Definition: mathlib.cpp:261
static const vec3_t scale
const vec3_t vec3_origin
Definition: mathlib.cpp:35
float vec_t
Definition: ufotypes.h:37
bool FixWinding(winding_t *w)
removes degenerate edges from a winding
Definition: polylib.cpp:478
#define MAX_POINTS_ON_WINDING
Definition: polylib.h:36
void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross)
binary operation on vectors in a three-dimensional space
Definition: mathlib.cpp:820
void ChopWindingInPlace(winding_t **inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
Definition: polylib.cpp:299
#define VectorScale(in, scale, out)
Definition: vector.h:79
void RemoveColinearPoints(winding_t *w)
Definition: polylib.cpp:55
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
bool WindingIsHuge(const winding_t *w)
Returns true if the winding still has one of the points from basewinding for plane.
Definition: polylib.cpp:427
GLsizei size
Definition: r_gl.h:152
void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs)
If the point is outside the box defined by mins and maxs, expand the box to accommodate it...
Definition: mathlib.cpp:1042
winding_t * AllocWinding(int points)
Allocate a new winding (polygon)
Definition: polylib.cpp:38
void ClipWindingEpsilon(const winding_t *in, const vec3_t normal, const vec_t dist, const vec_t epsilon, winding_t **front, winding_t **back)
Definition: polylib.cpp:204
void WindingCenter(const winding_t *w, vec3_t center)
Definition: polylib.cpp:106
#define Mem_Alloc(size)
Definition: mem.h:40
for storing the vertices of the side of a brush or other polygon
Definition: polylib.h:30
bool WindingIsTiny(winding_t *w)
Returns true if the winding would be crunched out of existance by the vertex snapping.
Definition: polylib.cpp:407
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
winding_t * ReverseWinding(const winding_t *w)
Definition: polylib.cpp:193
#define SIDE_ON
Definition: defines.h:187
#define VectorAdd(a, b, dest)
Definition: vector.h:47
#define SNAP_EPSILON
Definition: polylib.cpp:437
vec_t WindingArea(const winding_t *w)
Definition: polylib.cpp:81
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
vec3_t p[4]
Definition: polylib.h:32
#define BOGUS_RANGE
Definition: polylib.cpp:31
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition: mathlib.cpp:745
#define Mem_Free(ptr)
Definition: mem.h:35
winding_t * BaseWindingForPlane(const vec3_t normal, const vec_t dist)
Definition: polylib.cpp:116
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition: defines.h:288
static void SnapWeldVector(const vec3_t a, const vec3_t b, vec3_t out)
welds two vec3_t's into a third, taking into account nearest-to-integer instead of averaging ...
Definition: polylib.cpp:443
#define EDGE_LENGTH
Definition: polylib.cpp:402
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
void ClearBounds(vec3_t mins, vec3_t maxs)
Sets mins and maxs to their starting points before using AddPointToBounds.
Definition: mathlib.cpp:1032
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
void FreeWinding(winding_t *w)
Definition: polylib.cpp:46
int numpoints
Definition: polylib.h:31
#define ON_EPSILON
Definition: defines.h:374
#define SIDE_FRONT
Definition: defines.h:186