UFO: Alien Invasion
Loading...
Searching...
No Matches
csg.cpp
Go to the documentation of this file.
1
27
28/*
29Copyright (C) 1997-2001 Id Software, Inc.
30
31This program is free software; you can redistribute it and/or
32modify it under the terms of the GNU General Public License
33as published by the Free Software Foundation; either version 2
34of the License, or (at your option) any later version.
35
36This program is distributed in the hope that it will be useful,
37but WITHOUT ANY WARRANTY; without even the implied warranty of
38MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
39
40See the GNU General Public License for more details.
41
42You should have received a copy of the GNU General Public License
43along with this program; if not, write to the Free Software
44Foundation, 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
106static uint16_t minplanenums[2];
107static uint16_t maxplanenums[2];
108
113static 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
158static 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
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
242static inline bool BrushGE (bspbrush_t* b1, bspbrush_t* b2)
243{
244 /* detail brushes never bite structural brushes */
245 if ((b1->original->contentFlags & CONTENTS_DETAIL)
246 && !(b2->original->contentFlags & CONTENTS_DETAIL))
247 return false;
248 if (b1->original->contentFlags & CONTENTS_SOLID)
249 return true;
250 return false;
251}
252
264int 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
292bspbrush_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
390newlist:
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}
uint16_t FindOrCreateFloatPlane(vec3_t normal, vec_t dist)
Definition map.cpp:194
mapbrush_t mapbrushes[MAX_MAP_BRUSHES]
Definition map.cpp:34
void FreeBrushList(bspbrush_t *brushes)
Definition bspbrush.cpp:193
void FreeBrush(bspbrush_t *brushes)
Definition bspbrush.cpp:179
bspbrush_t * AllocBrush(int numsides)
Definition bspbrush.cpp:166
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
int CountBrushList(bspbrush_t *brushes)
Returns the amount of brushes in the given brushlist.
Definition bspbrush.cpp:152
Definition aabb.h:42
vec3_t maxs
Definition aabb.h:258
void setNegativeVolume()
Sets mins and maxs to their starting points before using addPoint.
Definition aabb.h:98
vec3_t mins
Definition aabb.h:257
void set(const AABB &other)
Copies the values from the given aabb.
Definition aabb.h:60
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 bspbrush_t * SubtractBrush(bspbrush_t *a, const bspbrush_t *b)
Definition csg.cpp:55
bspbrush_t * ChopBrushes(bspbrush_t *head)
Carves any intersecting solid brushes into the minimum number of non-intersecting brushes.
Definition csg.cpp:376
bspbrush_t * MakeBspBrushList(int startbrush, int endbrush, int level, const AABB &clip)
Definition csg.cpp:292
static bspbrush_t * AddBrushListToTail(bspbrush_t *list, bspbrush_t *tail)
Definition csg.cpp:199
static uint16_t maxplanenums[2]
Definition csg.cpp:107
static bool BrushGE(bspbrush_t *b1, bspbrush_t *b2)
Returns true if b1 is allowed to bite b2.
Definition csg.cpp:242
static bool BrushesDisjoint(bspbrush_t *a, bspbrush_t *b)
Definition csg.cpp:86
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
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 uint16_t minplanenums[2]
Definition csg.cpp:106
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
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
#define CONTENTS_WEAPONCLIP
Definition defines.h:249
#define CONTENTS_DETAIL
Definition defines.h:251
#define TEXINFO_NODE
Definition defines.h:48
#define CONTENTS_ACTORCLIP
Definition defines.h:243
#define LEVEL_LIGHTCLIP
Definition defines.h:349
#define CONTENTS_SOLID
Definition defines.h:223
#define SURF_HINT
Definition defines.h:261
#define LEVEL_WEAPONCLIP
Definition defines.h:351
#define MASK_CLIP
Definition defines.h:278
#define LEVEL_ACTORCLIP
Definition defines.h:352
#define CONTENTS_LIGHTCLIP
Definition defines.h:246
level_locals_t level
Definition g_main.cpp:38
winding_t * CopyWinding(const winding_t *w)
Copy a winding with all its points allocated.
Definition polylib.cpp:185
QGL_EXTERN GLint i
Definition r_gl.h:113
struct mapbrush_s * original
Definition bspbrush.h:40
AABB brBox
Definition bspbrush.h:37
struct bspbrush_s * next
Definition bspbrush.h:36
int numsides
Definition bspbrush.h:41
side_t sides[STANDARD_NUMBER_OF_BRUSHSIDES]
Definition bspbrush.h:42
struct side_s * original_sides
Definition map.h:84
bool finished
Definition map.h:94
int numsides
Definition map.h:83
uint32_t contentFlags
Definition map.h:79
AABB mbBox
Definition map.h:81
Definition map.h:60
uint16_t planenum
Definition map.h:61
winding_t * winding
Definition map.h:63
uint32_t surfaceFlags
Definition map.h:66
int texinfo
Definition map.h:62
bool visible
Definition map.h:67
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
@ VERB_EXTRA
Definition shared.h:46
@ VERB_DUMP
Definition shared.h:47
vec_t vec3_t[3]
Definition ufotypes.h:39