UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
csg.cpp
Go to the documentation of this file.
1 
28 /*
29 Copyright (C) 1997-2001 Id Software, Inc.
30 
31 This program is free software; you can redistribute it and/or
32 modify it under the terms of the GNU General Public License
33 as published by the Free Software Foundation; either version 2
34 of the License, or (at your option) any later version.
35 
36 This program is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
39 
40 See the GNU General Public License for more details.
41 
42 You should have received a copy of the GNU General Public License
43 along with this program; if not, write to the Free Software
44 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
45 
46 */
47 
48 #include "bsp.h"
49 
56 {
57  /* a - b = out (list) */
58  bspbrush_t* front, *back, *out;
59  bspbrush_t* in;
60 
61  in = a;
62  out = nullptr;
63  for (int i = 0; i < b->numsides && in; i++) {
64  SplitBrush(in, b->sides[i].planenum, &front, &back);
65  if (in != a)
66  FreeBrush(in);
67  if (front) { /* add to list */
68  front->next = out;
69  out = front;
70  }
71  in = back;
72  }
73  if (in)
74  FreeBrush(in);
75  else { /* didn't really intersect */
76  FreeBrushList(out);
77  return a;
78  }
79  return out;
80 }
81 
87 {
88  int i;
89 
90  /* check bounding boxes */
91  for (i = 0; i < 3; i++)
92  if (a->brBox.mins[i] >= b->brBox.maxs[i] || a->brBox.maxs[i] <= b->brBox.mins[i])
93  return true; /* bounding boxes don't overlap */
94 
95  /* check for opposing planes */
96  for (i = 0; i < a->numsides; i++) {
97  for (int j = 0; j < b->numsides; j++) {
98  if (a->sides[i].planenum == (b->sides[j].planenum ^ 1))
99  return true; /* opposite planes, so not touching */
100  }
101  }
102 
103  return false; /* might intersect */
104 }
105 
106 static uint16_t minplanenums[2];
107 static uint16_t maxplanenums[2];
108 
113 static bspbrush_t* ClipBrushToBox (bspbrush_t* brush, const AABB& clipBox)
114 {
115  bspbrush_t* front, *back;
116 
117  for (int j = 0; j < 2; j++) {
118  if (brush->brBox.maxs[j] > clipBox.maxs[j]) {
119  SplitBrush(brush, maxplanenums[j], &front, &back);
120  FreeBrush(brush);
121  if (front)
122  FreeBrush(front);
123  brush = back;
124  if (!brush)
125  return nullptr;
126  }
127  if (brush->brBox.mins[j] < clipBox.mins[j]) {
128  SplitBrush(brush, minplanenums[j], &front, &back);
129  FreeBrush(brush);
130  if (back)
131  FreeBrush(back);
132  brush = front;
133  if (!brush)
134  return nullptr;
135  }
136  }
137 
138  /* remove any colinear faces */
139  for (int i = 0; i < brush->numsides; i++) {
140  side_t* side = &brush->sides[i];
141  const int p = side->planenum & ~1;
142  if (p == maxplanenums[0] || p == maxplanenums[1]
143  || p == minplanenums[0] || p == minplanenums[1]) {
144  side->texinfo = TEXINFO_NODE;
145  side->visible = false;
146  }
147  }
148  return brush;
149 }
150 
158 static bool IsInLevel (const int contents, const int level)
159 {
160  /* special levels */
161  switch (level) {
162  case LEVEL_LIGHTCLIP:
163  if (contents & CONTENTS_LIGHTCLIP)
164  return true;
165  else
166  return false;
167  case LEVEL_WEAPONCLIP:
168  if (contents & CONTENTS_WEAPONCLIP)
169  return true;
170  else
171  return false;
172  case LEVEL_ACTORCLIP:
173  if (contents & CONTENTS_ACTORCLIP)
174  return true;
175  else
176  return false;
177  }
178 
179  /* If the brush is any kind of clip, we are not looking for it after here. */
180  if (contents & MASK_CLIP)
181  return false;
182 
183  /* standard levels */
184  if (level == -1)
185  return true;
186  else if (level) {
187  if (((contents >> 8) & 0xFF) == level)
188  return true;
189  else
190  return false;
191  } else {
192  if (contents & 0xFF00)
193  return false;
194  else
195  return true;
196  }
197 }
198 
200 {
201  bspbrush_t* walk, *next;
202 
203  /* add to end of list */
204  for (walk = list; walk; walk = next) {
205  next = walk->next;
206  walk->next = nullptr;
207  tail->next = walk;
208  tail = walk;
209  }
210 
211  return tail;
212 }
213 
220 static bspbrush_t* CullList (bspbrush_t* list, bspbrush_t* skip)
221 {
222  bspbrush_t* newlist;
223  bspbrush_t* next;
224 
225  newlist = nullptr;
226 
227  for (; list; list = next) {
228  next = list->next;
229  if (list == skip) {
230  FreeBrush(list);
231  continue;
232  }
233  list->next = newlist;
234  newlist = list;
235  }
236  return newlist;
237 }
238 
242 static inline bool BrushGE (bspbrush_t* b1, bspbrush_t* b2)
243 {
244  /* detail brushes never bite structural brushes */
247  return false;
249  return true;
250  return false;
251 }
252 
264 int MapBrushesBounds (const int startbrush, const int endbrush, const int level, const AABB& clipBox, AABB& bBox)
265 {
266  int i, num;
267 
268  bBox.setNegativeVolume();
269  num = 0;
270 
271  for (i = startbrush; i < endbrush; i++) {
272  const mapbrush_t* b = &mapbrushes[i];
273 
274  /* don't use finished brushes again */
275  if (b->finished)
276  continue;
277 
278  if (!IsInLevel(b->contentFlags, level))
279  continue;
280 
281  /* check the bounds */
282  if (!clipBox.contains(b->mbBox))
283  continue;
284 
285  num++;
286  bBox.add(b->mbBox);
287  }
288 
289  return num;
290 }
291 
292 bspbrush_t* MakeBspBrushList (int startbrush, int endbrush, int level, const AABB& clip)
293 {
294  bspbrush_t* brushlist, *newbrush;
295  int i, j, vis;
296  int numsides;
297 
298  Verb_Printf(VERB_DUMP, "MakeBspBrushList: bounds (%f %f %f) (%f %f %f)\n",
299  clip.mins[0], clip.mins[1], clip.mins[2], clip.maxs[0], clip.maxs[1], clip.maxs[2]);
300 
301  for (i = 0; i < 2; i++) {
302  float dist;
303  vec3_t normal = {0, 0, 0};
304  normal[i] = 1;
305  dist = clip.maxs[i];
306  maxplanenums[i] = FindOrCreateFloatPlane(normal, dist);
307  dist = clip.mins[i];
308  minplanenums[i] = FindOrCreateFloatPlane(normal, dist);
309  }
310 
311  brushlist = nullptr;
312 
313  for (i = startbrush; i < endbrush; i++) {
314  mapbrush_t* mb = &mapbrushes[i];
315 
316  if (!IsInLevel(mb->contentFlags, level)){
317  Verb_Printf(VERB_DUMP, "Rejected brush %i: wrong level.\n", i);
318  continue;
319  }
320 
321  if (mb->finished){
322  Verb_Printf(VERB_DUMP, "Rejected brush %i: already finished.\n", i);
323  continue;
324  }
325 
326  numsides = mb->numsides;
327  if (!numsides) {
328  Verb_Printf(VERB_DUMP, "Rejected brush %i: no sides.\n", i);
329  continue;
330  }
331 
332  /* make sure the brush has at least one face showing */
333  vis = 0;
334  for (j = 0; j < numsides; j++)
335  if (mb->original_sides[j].visible && mb->original_sides[j].winding)
336  vis++;
337 
338  /* if the brush is outside the clip area, skip it */
339  if (!clip.contains(mb->mbBox))
340  continue;
341 
342  mb->finished = true;
343 
344  /* make a copy of the brush */
345  newbrush = AllocBrush(mb->numsides);
346  newbrush->original = mb;
347  newbrush->numsides = mb->numsides;
348  memcpy(newbrush->sides, mb->original_sides, numsides * sizeof(side_t));
349  for (j = 0; j < numsides; j++) {
350  side_t* side = &newbrush->sides[j];
351  if (side->winding)
352  side->winding = CopyWinding(side->winding);
353  if (side->surfaceFlags & SURF_HINT)
354  side->visible = true; /* hints are always visible */
355  }
356  newbrush->brBox.set(mb->mbBox);
357 
358  /* carve off anything outside the clip box */
359  newbrush = ClipBrushToBox(newbrush, clip);
360  if (!newbrush) {
361  Verb_Printf(VERB_DUMP, "Rejected brush %i: cannot clip to box.\n", i);
362  continue;
363  }
364 
365  newbrush->next = brushlist;
366  brushlist = newbrush;
367  Verb_Printf(VERB_DUMP, "Added brush %i.\n", i);
368  }
369 
370  return brushlist;
371 }
372 
377 {
378  bspbrush_t* b1, *b2, *next;
379  bspbrush_t* tail;
380  bspbrush_t* keep;
381  bspbrush_t* sub, *sub2;
382  int c1, c2;
383  const int originalBrushes = CountBrushList(head);
384  int keepBrushes;
385 
386  Verb_Printf(VERB_EXTRA, "---- ChopBrushes ----\n");
387 
388  keep = nullptr;
389 
390 newlist:
391  /* find tail */
392  if (!head)
393  return nullptr;
394 
395  for (tail = head; tail->next; tail = tail->next);
396 
397  for (b1 = head; b1; b1 = next) {
398  next = b1->next;
399  for (b2 = b1->next; b2; b2 = b2->next) {
400  if (BrushesDisjoint(b1, b2))
401  continue;
402 
403  sub = sub2 = nullptr;
404  c1 = c2 = 999999;
405 
406  if (BrushGE(b2, b1)) {
407  sub = SubtractBrush(b1, b2);
408  if (sub == b1)
409  continue; /* didn't really intersect */
410  if (!sub) { /* b1 is swallowed by b2 */
411  head = CullList(b1, b1);
412  goto newlist;
413  }
414  c1 = CountBrushList(sub);
415  }
416 
417  if (BrushGE(b1, b2)) {
418  sub2 = SubtractBrush(b2, b1);
419  if (sub2 == b2)
420  continue; /* didn't really intersect */
421  if (!sub2) { /* b2 is swallowed by b1 */
422  FreeBrushList(sub);
423  head = CullList(b1, b2);
424  goto newlist;
425  }
426  c2 = CountBrushList(sub2);
427  }
428 
429  if (!sub && !sub2)
430  continue; /* neither one can bite */
431 
432  /* only accept if it didn't fragment */
433  /* (commenting this out allows full fragmentation) */
434  if (c1 > 1 && c2 > 1) {
435  if (sub2)
436  FreeBrushList(sub2);
437  if (sub)
438  FreeBrushList(sub);
439  continue;
440  }
441 
442  if (c1 < c2) {
443  if (sub2)
444  FreeBrushList(sub2);
445  tail = AddBrushListToTail(sub, tail);
446  head = CullList(b1, b1);
447  goto newlist;
448  } else {
449  if (sub)
450  FreeBrushList(sub);
451  tail = AddBrushListToTail(sub2, tail);
452  head = CullList(b1, b2);
453  goto newlist;
454  }
455  }
456 
457  /* b1 is no longer intersecting anything, so keep it */
458  if (!b2) {
459  b1->next = keep;
460  keep = b1;
461  }
462  }
463 
464  keepBrushes = CountBrushList(keep);
465  if (keepBrushes != originalBrushes) {
466  Verb_Printf(VERB_EXTRA, "original brushes: %i\n", originalBrushes);
467  Verb_Printf(VERB_EXTRA, "output brushes: %i\n", keepBrushes);
468  }
469  return keep;
470 }
static bspbrush_t * AddBrushListToTail(bspbrush_t *list, bspbrush_t *tail)
Definition: csg.cpp:199
#define CONTENTS_WEAPONCLIP
Definition: defines.h:249
void setNegativeVolume()
Sets mins and maxs to their starting points before using addPoint.
Definition: aabb.h:98
int texinfo
Definition: map.h:62
winding_t * CopyWinding(const winding_t *w)
Copy a winding with all its points allocated.
Definition: polylib.cpp:185
uint16_t FindOrCreateFloatPlane(vec3_t normal, vec_t dist)
Definition: map.cpp:194
#define CONTENTS_SOLID
Definition: defines.h:223
static bspbrush_t * SubtractBrush(bspbrush_t *a, const bspbrush_t *b)
Definition: csg.cpp:55
Definition: aabb.h:42
static bool IsInLevel(const int contents, const int level)
checks if the level# matches the contentsmask. The level# is mapped to the appropriate levelflags...
Definition: csg.cpp:158
static bspbrush_t * ClipBrushToBox(bspbrush_t *brush, const AABB &clipBox)
Any planes shared with the box edge will be set to no texinfo.
Definition: csg.cpp:113
#define LEVEL_ACTORCLIP
Definition: defines.h:352
void FreeBrushList(bspbrush_t *brushes)
Definition: bspbrush.cpp:193
winding_t * winding
Definition: map.h:63
static bool BrushesDisjoint(bspbrush_t *a, bspbrush_t *b)
Definition: csg.cpp:86
int numsides
Definition: map.h:83
void set(const AABB &other)
Copies the values from the given aabb.
Definition: aabb.h:60
AABB brBox
Definition: bspbrush.h:37
vec3_t maxs
Definition: aabb.h:258
bspbrush_t * ChopBrushes(bspbrush_t *head)
Carves any intersecting solid brushes into the minimum number of non-intersecting brushes...
Definition: csg.cpp:376
AABB mbBox
Definition: map.h:81
#define CONTENTS_DETAIL
Definition: defines.h:251
static uint16_t maxplanenums[2]
Definition: csg.cpp:107
mapbrush_t mapbrushes[MAX_MAP_BRUSHES]
Definition: map.cpp:34
bspbrush_t * AllocBrush(int numsides)
Definition: bspbrush.cpp:166
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition: aabb.cpp:57
bool contains(const vec3_t point) const
Definition: aabb.h:200
static bool BrushGE(bspbrush_t *b1, bspbrush_t *b2)
Returns true if b1 is allowed to bite b2.
Definition: csg.cpp:242
void FreeBrush(bspbrush_t *brushes)
Definition: bspbrush.cpp:179
uint16_t planenum
Definition: map.h:61
struct side_s * original_sides
Definition: map.h:84
bool visible
Definition: map.h:67
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
Definition: map.h:60
struct bspbrush_s * next
Definition: bspbrush.h:36
int numsides
Definition: bspbrush.h:41
int MapBrushesBounds(const int startbrush, const int endbrush, const int level, const AABB &clipBox, AABB &bBox)
sets mins and maxs to the smallest sizes that can contain all brushes from startbrush to endbrush tha...
Definition: csg.cpp:264
side_t sides[STANDARD_NUMBER_OF_BRUSHSIDES]
Definition: bspbrush.h:42
int CountBrushList(bspbrush_t *brushes)
Returns the amount of brushes in the given brushlist.
Definition: bspbrush.cpp:152
void SplitBrush(const bspbrush_t *brush, uint16_t planenum, bspbrush_t **front, bspbrush_t **back)
Generates two new brushes, leaving the original unchanged.
Definition: bspbrush.cpp:544
#define CONTENTS_ACTORCLIP
Definition: defines.h:243
QGL_EXTERN GLint i
Definition: r_gl.h:113
struct mapbrush_s * original
Definition: bspbrush.h:40
#define MASK_CLIP
Definition: defines.h:278
Definition: map.h:75
bool finished
Definition: map.h:94
static bspbrush_t * CullList(bspbrush_t *list, bspbrush_t *skip)
Builds a new list that doesn't hold the given brush.
Definition: csg.cpp:220
bspbrush_t * MakeBspBrushList(int startbrush, int endbrush, int level, const AABB &clip)
Definition: csg.cpp:292
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define LEVEL_LIGHTCLIP
Definition: defines.h:349
vec3_t mins
Definition: aabb.h:257
#define SURF_HINT
Definition: defines.h:261
uint32_t surfaceFlags
Definition: map.h:66
#define LEVEL_WEAPONCLIP
Definition: defines.h:351
#define CONTENTS_LIGHTCLIP
Definition: defines.h:246
#define TEXINFO_NODE
Definition: defines.h:48
static uint16_t minplanenums[2]
Definition: csg.cpp:106
uint32_t contentFlags
Definition: map.h:79
level_locals_t level
Definition: g_main.cpp:38