UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
bspbrush.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "bsp.h"
26 #include "map.h"
27 
28 extern int c_nodes;
29 extern int c_nonvis;
30 static int c_active_brushes;
31 
32 
36 static void BoundBrush (bspbrush_t* brush)
37 {
38  brush->brBox.setNegativeVolume();
39  for (int i = 0; i < brush->numsides; i++) {
40  winding_t* w = brush->sides[i].winding;
41  if (!w)
42  continue;
43  for (int j = 0; j < w->numpoints; j++)
44  brush->brBox.add(w->p[j]);
45  }
46 }
47 
48 
53 static void CreateBrushWindings (bspbrush_t* brush)
54 {
55  for (int i = 0; i < brush->numsides; i++) {
56  side_t* side = &brush->sides[i];
57  const plane_t* plane = &mapplanes[side->planenum];
58 
59  /* evidence that winding_t represents a hessian normal plane */
60  winding_t* w = BaseWindingForPlane(plane->normal, plane->dist);
61 
62  for (int j = 0; j < brush->numsides && w; j++) {
63  if (i == j)
64  continue;
65  /* back side clipaway */
66  if (brush->sides[j].planenum == (side->planenum ^ 1))
67  continue;
68  if (brush->sides[j].bevel)
69  continue;
70  plane = &mapplanes[brush->sides[j].planenum ^ 1];
71  ChopWindingInPlace(&w, plane->normal, plane->dist, 0); /*CLIP_EPSILON); */
72 
73  /* fix broken windings that would generate trifans */
74  if (!FixWinding(w))
75  Verb_Printf(VERB_EXTRA, "removed degenerated edge(s) from winding\n");
76  }
77 
78  side->winding = w;
79  }
80 
81  BoundBrush(brush);
82 }
83 
87 bspbrush_t* BrushFromBounds (const vec3_t mins, const vec3_t maxs)
88 {
89  vec3_t normal;
90 
91  bspbrush_t* b = AllocBrush(6);
92  b->numsides = 6;
93  for (int i = 0; i < 3; i++) {
94  VectorClear(normal);
95  normal[i] = 1;
96  vec_t dist = maxs[i];
97  b->sides[i].planenum = FindOrCreateFloatPlane(normal, dist);
98 
99  normal[i] = -1;
100  dist = -mins[i];
101  b->sides[3 + i].planenum = FindOrCreateFloatPlane(normal, dist);
102  }
103 
105 
106  return b;
107 }
108 
112 static vec_t BrushVolume (const bspbrush_t* brush)
113 {
114  int i;
115  const winding_t* w;
116  vec3_t corner;
117  vec_t volume;
118 
119  if (!brush)
120  return 0;
121 
122  /* grab the first valid point as the corner */
123  w = nullptr;
124  for (i = 0; i < brush->numsides; i++) {
125  w = brush->sides[i].winding;
126  if (w)
127  break;
128  }
129  if (!w)
130  return 0;
131  VectorCopy(w->p[0], corner);
132 
133  /* make tetrahedrons to all other faces */
134  volume = 0;
135  for (; i < brush->numsides; i++) {
136  w = brush->sides[i].winding;
137  if (w) {
138  const plane_t* plane = &mapplanes[brush->sides[i].planenum];
139  const vec_t d = -(DotProduct(corner, plane->normal) - plane->dist);
140  const vec_t area = WindingArea(w);
141  volume += d * area;
142  }
143  }
144 
145  volume /= 3;
146  return volume;
147 }
148 
153 {
154  int c;
155 
156  c = 0;
157  for (; brushes; brushes = brushes->next)
158  c++;
159  return c;
160 }
161 
166 bspbrush_t* AllocBrush (int numsides)
167 {
168  const size_t size = sizeof(bspbrush_t) + sizeof(side_t) * (numsides - STANDARD_NUMBER_OF_BRUSHSIDES);
169 
170  if (threadstate.numthreads == 1)
172 
173  return (bspbrush_t*)Mem_Alloc(size);
174 }
175 
179 void FreeBrush (bspbrush_t* brushes)
180 {
181  for (int i = 0; i < brushes->numsides; i++)
182  if (brushes->sides[i].winding)
183  FreeWinding(brushes->sides[i].winding);
184  Mem_Free(brushes);
185  if (threadstate.numthreads == 1)
187 }
188 
193 void FreeBrushList (bspbrush_t* brushes)
194 {
195  bspbrush_t* next;
196 
197  for (; brushes; brushes = next) {
198  next = brushes->next;
199  FreeBrush(brushes);
200  }
201 }
202 
208 {
209  const size_t size = sizeof(bspbrush_t) + sizeof(side_t) * (brush->numsides - STANDARD_NUMBER_OF_BRUSHSIDES);
210 
211  bspbrush_t* newbrush = AllocBrush(brush->numsides);
212  memcpy(newbrush, brush, size);
213 
214  for (int i = 0; i < brush->numsides; i++) {
215  const side_t* side = &brush->sides[i];
216  if (side->winding)
217  newbrush->sides[i].winding = CopyWinding(side->winding);
218  }
219 
220  return newbrush;
221 }
222 
223 
224 static int TestBrushToPlanenum (bspbrush_t* brush, uint16_t planenum,
225  int* numsplits, bool* hintsplit, int* epsilonbrush)
226 {
227  int i, s;
228  plane_t* plane;
229  dBspPlane_t plane2;
230  vec_t d_front, d_back;
231  int front, back;
232 
233  *numsplits = 0;
234  *hintsplit = false;
235 
236  /* if the brush actually uses the planenum,
237  * we can tell the side for sure */
238  for (i = 0; i < brush->numsides; i++) {
239  const uint16_t num = brush->sides[i].planenum;
240  if (num == planenum)
241  return (PSIDE_BACK | PSIDE_FACING);
242  if (num == (planenum ^ 1))
243  return (PSIDE_FRONT | PSIDE_FACING);
244  }
245 
246  /* box on plane side */
247  plane = &mapplanes[planenum];
248 
249  /* Convert to cBspPlane */
250  VectorCopy(plane->normal, plane2.normal);
251  plane2.dist = plane->dist;
252  plane2.type = plane->type;
253  s = TR_BoxOnPlaneSide(brush->brBox.mins, brush->brBox.maxs, &plane2);
254 
255  if (s != PSIDE_BOTH)
256  return s;
257 
258  /* if both sides, count the visible faces split */
259  d_front = d_back = 0;
260 
261  for (i = 0; i < brush->numsides; i++) {
262  const side_t* side = &brush->sides[i];
263  const winding_t* w;
264  if (side->texinfo == TEXINFO_NODE)
265  continue; /* on node, don't worry about splits */
266  if (!side->visible)
267  continue; /* we don't care about non-visible */
268  w = side->winding;
269  if (!w)
270  continue;
271  front = back = 0;
272  for (int j = 0; j < w->numpoints; j++) {
273  const vec_t d = DotProduct(w->p[j], plane->normal) - plane->dist;
274  if (d > d_front)
275  d_front = d;
276  if (d < d_back)
277  d_back = d;
278 
279  if (d > 0.1) /* PLANESIDE_EPSILON) */
280  front = 1;
281  else if (d < -0.1) /* PLANESIDE_EPSILON) */
282  back = 1;
283  }
284  if (front && back) {
285  (*numsplits)++;
286  if (side->surfaceFlags & SURF_HINT)
287  *hintsplit = true;
288  }
289  }
290 
291  if ((d_front > 0.0 && d_front < 1.0) || (d_back < 0.0 && d_back > -1.0))
292  (*epsilonbrush)++;
293 
294  return s;
295 }
296 
301 {
302  bspbrush_t* b;
303  uint32_t contentFlags = 0;
304 
305  for (b = brushlist; b; b = b->next) {
306  /* if the brush is solid and all of its sides are on nodes,
307  * it eats everything */
309  int i;
310  for (i = 0; i < b->numsides; i++)
311  if (b->sides[i].texinfo != TEXINFO_NODE)
312  break;
313  if (i == b->numsides) {
314  contentFlags = CONTENTS_SOLID;
315  break;
316  }
317  }
318  contentFlags |= b->original->contentFlags;
319  }
320 
321  return contentFlags;
322 }
323 
328 static int BrushMostlyOnSide (const bspbrush_t* brush, const plane_t* plane)
329 {
330  vec_t max = 0;
331  int side = PSIDE_FRONT;
332 
333  for (int i = 0; i < brush->numsides; i++) {
334  const winding_t* w = brush->sides[i].winding;
335  if (!w)
336  continue;
337  for (int j = 0; j < w->numpoints; j++) {
338  const vec_t d = DotProduct(w->p[j], plane->normal) - plane->dist;
339  if (d > max) {
340  max = d;
341  side = PSIDE_FRONT;
342  }
343  if (-d > max) {
344  max = -d;
345  side = PSIDE_BACK;
346  }
347  }
348  }
349  return side;
350 }
351 
352 #define TESTING_MOCK_SPLIT 1
353 #if TESTING_MOCK_SPLIT
354 
357 static bool DoesPlaneSplitBrush (const bspbrush_t* brush, int planenum)
358 {
359  plane_t* plane = &mapplanes[planenum];
360  int front_cnt = 0, back_cnt = 0;
361 
362  /* check all points */
363  for (int i = 0; i < brush->numsides; i++) {
364  winding_t* w = brush->sides[i].winding;
365  if (!w)
366  continue;
367  for (int j = 0; j < w->numpoints; j++) {
368  const float d = DotProduct(w->p[j], plane->normal) - plane->dist;
369  if (d > 0.1f) /* PLANESIDE_EPSILON) */
370  front_cnt++;
371  if (d < -0.1f) /* PLANESIDE_EPSILON) */
372  back_cnt++;
373  }
374  }
375 
376  /* if brush vertices are both in front and back of given plane, in splits brush */
377  return front_cnt && back_cnt ;
378 }
379 #endif
380 
381 #if TESTING_MOCK_SPLIT
382 /* DoesPlaneSplitBrush does not yet work for all maps, namely city_train.map
383  * Until we know why, let's use the old stuff. */
384 static bool CheckPlaneAgainstVolume (int pnum, const bspbrush_t* volume)
385 {
386  bool good;
387 
388  good = DoesPlaneSplitBrush(volume, pnum);
389 
390  return good;
391 }
392 
393 #else
394 static bool CheckPlaneAgainstVolume (uint16_t pnum, const bspbrush_t* volume)
395 {
396  bspbrush_t* front, *back;
397  bool good;
398 
399  SplitBrush(volume, pnum, &front, &back);
400 
401  good = (front && back);
402 
403  if (front)
404  FreeBrush(front);
405  if (back)
406  FreeBrush(back);
407 
408  return good;
409 }
410 #endif
411 
417 {
418  int value;
419  bspbrush_t* brush, *test;
420  int i, pass;
421  int front, back, both, facing, splits;
422  int bsplits, epsilonbrush;
423  bool hintsplit;
424 
425  if (!volume)
426  return nullptr; /* can't split empty brush */
427 
428  side_t* bestside = nullptr;
429  int bestvalue = -99999;
430 
437  int numpasses = 4;
438  for (pass = 0; pass < numpasses; pass++) {
439  for (brush = brushes; brush; brush = brush->next) {
440  if ((pass & 1) && !(brush->original->contentFlags & CONTENTS_DETAIL))
441  continue;
442  if (!(pass & 1) && (brush->original->contentFlags & CONTENTS_DETAIL))
443  continue;
444  for (i = 0; i < brush->numsides; i++) {
445  uint16_t pnum;
446  side_t* side = &brush->sides[i];
447  if (side->bevel)
448  continue; /* never use a bevel as a spliter */
449  if (!side->winding)
450  continue; /* nothing visible, so it can't split */
451  if (side->texinfo == TEXINFO_NODE)
452  continue; /* already a node splitter */
453  if (side->tested)
454  continue; /* we already have metrics for this plane */
455  if (side->surfaceFlags & SURF_SKIP)
456  continue; /* skip surfaces are never chosen */
457  if (side->visible ^ (pass < 2))
458  continue; /* only check visible faces on first pass */
459 
460  pnum = side->planenum;
461  pnum &= ~1; /* always use positive facing plane */
462 
463  if (!CheckPlaneAgainstVolume(pnum, volume))
464  continue; /* would produce a tiny volume */
465 
466  front = 0;
467  back = 0;
468  both = 0;
469  facing = 0;
470  splits = 0;
471  epsilonbrush = 0;
472  hintsplit = false;
473 
474  for (test = brushes; test; test = test->next) {
475  const int s = TestBrushToPlanenum(test, pnum, &bsplits, &hintsplit, &epsilonbrush);
476 
477  splits += bsplits;
478  if (bsplits && (s & PSIDE_FACING))
479  Sys_Error("PSIDE_FACING with splits");
480 
481  test->testside = s;
482  /* if the brush shares this face, don't bother
483  * testing that facenum as a splitter again */
484  if (s & PSIDE_FACING) {
485  facing++;
486  for (int j = 0; j < test->numsides; j++) {
487  if ((test->sides[j].planenum &~ 1) == pnum)
488  test->sides[j].tested = true;
489  }
490  }
491  if (s & PSIDE_FRONT)
492  front++;
493  if (s & PSIDE_BACK)
494  back++;
495  if (s == PSIDE_BOTH)
496  both++;
497  }
498 
499  /* give a value estimate for using this plane */
500 
501  value = 5 * facing - 5 * splits - abs(front - back);
502  if (AXIAL(&mapplanes[pnum]))
503  value += 5; /* axial is better */
504  value -= epsilonbrush * 1000; /* avoid! */
505 
506  /* never split a hint side except with another hint */
507  if (hintsplit && !(side->surfaceFlags & SURF_HINT))
508  value = -9999999;
509 
510  /* save off the side test so we don't need
511  * to recalculate it when we actually seperate
512  * the brushes */
513  if (value > bestvalue) {
514  bestvalue = value;
515  bestside = side;
516  for (test = brushes; test; test = test->next)
517  test->side = test->testside;
518  }
519  }
520  }
521 
522  /* if we found a good plane, don't bother trying any other passes */
523  if (bestside) {
524  if (pass > 1) {
525  if (threadstate.numthreads == 1)
526  c_nonvis++;
527  }
528  break;
529  }
530  }
531 
532  /* clear all the tested flags we set */
533  for (brush = brushes; brush; brush = brush->next) {
534  for (i = 0; i < brush->numsides; i++)
535  brush->sides[i].tested = false;
536  }
537 
538  return bestside;
539 }
540 
544 void SplitBrush (const bspbrush_t* brush, uint16_t planenum, bspbrush_t** front, bspbrush_t** back)
545 {
546  bspbrush_t* b[2];
547  int i, j;
548  winding_t* w, *cw[2], *midwinding;
549  plane_t* plane;
550  float d_front, d_back;
551 
552  *front = *back = nullptr;
553  plane = &mapplanes[planenum];
554 
555  /* check all points */
556  d_front = d_back = 0;
557  for (i = 0; i < brush->numsides; i++) {
558  w = brush->sides[i].winding;
559  if (!w)
560  continue;
561  for (j = 0; j < w->numpoints; j++) {
562  const float d = DotProduct(w->p[j], plane->normal) - plane->dist;
563  if (d > 0 && d > d_front)
564  d_front = d;
565  else if (d < 0 && d < d_back)
566  d_back = d;
567  }
568  }
569  if (d_front < 0.1) { /* PLANESIDE_EPSILON) */
570  /* only on back */
571  *back = CopyBrush(brush);
572  return;
573  }
574  if (d_back > -0.1) { /* PLANESIDE_EPSILON) */
575  /* only on front */
576  *front = CopyBrush(brush);
577  return;
578  }
579 
580  /* create a new winding from the split plane */
581  w = BaseWindingForPlane(plane->normal, plane->dist);
582  for (i = 0; i < brush->numsides && w; i++) {
583  plane_t* plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
584  ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); /* PLANESIDE_EPSILON); */
585  }
586 
587  /* the brush isn't really split */
588  if (!w || WindingIsTiny(w)) {
589  const int side = BrushMostlyOnSide(brush, plane);
590  if (side == PSIDE_FRONT)
591  *front = CopyBrush(brush);
592  else if (side == PSIDE_BACK)
593  *back = CopyBrush(brush);
594  return;
595  }
596 
597  if (WindingIsHuge(w)) {
600  Com_Printf("WARNING: Large winding\n");
601  }
602 
603  midwinding = w;
604 
605  /* split it for real */
606  for (i = 0; i < 2; i++) {
607  b[i] = AllocBrush(brush->numsides + 1);
608  b[i]->original = brush->original;
609  }
610 
611  /* split all the current windings */
612  for (i = 0; i < brush->numsides; i++) {
613  const side_t* s = &brush->sides[i];
614  w = s->winding;
615  if (!w)
616  continue;
617  ClipWindingEpsilon(w, plane->normal, plane->dist,
618  0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
619  for (j = 0; j < 2; j++) {
620  side_t* cs;
621 
622  if (!cw[j])
623  continue;
624 
625  cs = &b[j]->sides[b[j]->numsides];
626  b[j]->numsides++;
627  *cs = *s;
628 
629  cs->winding = cw[j];
630  cs->tested = false;
631  }
632  }
633 
634  /* see if we have valid polygons on both sides */
635  for (i = 0; i < 2; i++) {
636  BoundBrush(b[i]);
637  for (j = 0; j < 3; j++) {
638  if (b[i]->brBox.mins[j] < -MAX_WORLD_WIDTH || b[i]->brBox.maxs[j] > MAX_WORLD_WIDTH) {
641  Verb_Printf(VERB_EXTRA, "bogus brush after clip\n");
642  break;
643  }
644  }
645 
646  if (b[i]->numsides < 3 || j < 3) {
647  FreeBrush(b[i]);
648  b[i] = nullptr;
649  }
650  }
651 
652  if (!(b[0] && b[1])) {
655  if (!b[0] && !b[1])
656  Verb_Printf(VERB_EXTRA, "split removed brush\n");
657  else
658  Verb_Printf(VERB_EXTRA, "split not on both sides\n");
659  if (b[0]) {
660  FreeBrush(b[0]);
661  *front = CopyBrush(brush);
662  }
663  if (b[1]) {
664  FreeBrush(b[1]);
665  *back = CopyBrush(brush);
666  }
667  return;
668  }
669 
670  /* add the midwinding to both sides */
671  for (i = 0; i < 2; i++) {
672  side_t* cs = &b[i]->sides[b[i]->numsides];
673  b[i]->numsides++;
674 
675  cs->planenum = planenum ^ i ^ 1;
676  cs->texinfo = TEXINFO_NODE;
677  cs->visible = false;
678  cs->tested = false;
679  if (i == 0)
680  cs->winding = CopyWinding(midwinding);
681  else
682  cs->winding = midwinding;
683  }
684 
685  for (i = 0; i < 2; i++) {
686  const vec_t v1 = BrushVolume(b[i]);
687  if (v1 < 1.0) {
688  FreeBrush(b[i]);
689  b[i] = nullptr;
692  Verb_Printf(VERB_EXTRA, "tiny volume after clip\n");
693  }
694  }
695 
696  *front = b[0];
697  *back = b[1];
698 }
699 
700 void SplitBrushList (bspbrush_t* brushes, uint16_t planenum, bspbrush_t** front, bspbrush_t** back)
701 {
702  bspbrush_t* brush;
703 
704  *front = *back = nullptr;
705 
706  for (brush = brushes; brush; brush = brush->next) {
707  const int sides = brush->side;
708  bspbrush_t* newbrush;
709 
710  if (sides == PSIDE_BOTH) { /* split into two brushes */
711  bspbrush_t* newbrush2;
712  SplitBrush(brush, planenum, &newbrush, &newbrush2);
713  if (newbrush) {
714  newbrush->next = *front;
715  Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
716  *front = newbrush;
717  }
718  if (newbrush2) {
719  newbrush2->next = *back;
720  Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush2->original->brushnum);
721  *back = newbrush2;
722  }
723  continue;
724  }
725 
726  newbrush = CopyBrush(brush);
727 
728  /* if the planenum is actually a part of the brush
729  * find the plane and flag it as used so it won't be tried
730  * as a splitter again */
731  if (sides & PSIDE_FACING) {
732  for (int i = 0; i < newbrush->numsides; i++) {
733  side_t* side = newbrush->sides + i;
734  if ((side->planenum & ~1) == planenum)
735  side->texinfo = TEXINFO_NODE;
736  }
737  }
738 
739  if (sides & PSIDE_FRONT) {
740  newbrush->next = *front;
741  *front = newbrush;
742  Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
743  continue;
744  }
745  if (sides & PSIDE_BACK) {
746  newbrush->next = *back;
747  Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush->original->brushnum);
748  *back = newbrush;
749  continue;
750  }
751  Verb_Printf(VERB_DUMP, "SplitBrushList: Brush %i fell off the map.\n", newbrush->original->brushnum);
752  }
753 }
754 
755 
760 {
761  bspbrush_t* b;
762  int c_faces = 0, c_nonvisfaces = 0, c_brushes = 0;
763 
764  for (b = brushlist; b; b = b->next) {
765  c_brushes++;
766 
767  vec_t volume = BrushVolume(b);
768  if (volume < config.microvolume) {
769  Com_Printf("\nWARNING: entity %i, brush %i: microbrush, volume %.3g\n",
770  b->original->entitynum, b->original->brushnum, volume);
771  }
772 
773  for (int i = 0; i < b->numsides; i++) {
774  side_t* side = &b->sides[i];
775  if (side->bevel)
776  continue;
777  if (!side->winding)
778  continue;
779  if (side->texinfo == TEXINFO_NODE)
780  continue;
781  if (side->visible)
782  c_faces++;
783  else
784  c_nonvisfaces++;
785  }
786 
787  blBox.add(b->brBox);
788  }
789 
790  Verb_Printf(VERB_EXTRA, "%5i brushes\n", c_brushes);
791  Verb_Printf(VERB_EXTRA, "%5i visible faces\n", c_faces);
792  Verb_Printf(VERB_EXTRA, "%5i nonvisible faces\n", c_nonvisfaces);
793 }
int32_t contentFlags
Definition: bsp.h:56
vec3_t normal
Definition: map.h:99
#define VectorCopy(src, dest)
Definition: vector.h:51
static void BoundBrush(bspbrush_t *brush)
Sets the mins/maxs based on the windings.
Definition: bspbrush.cpp:36
void setNegativeVolume()
Sets mins and maxs to their starting points before using addPoint.
Definition: aabb.h:98
static int c_faces
Definition: faces.cpp:34
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
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
void SplitBrushList(bspbrush_t *brushes, uint16_t planenum, bspbrush_t **front, bspbrush_t **back)
Definition: bspbrush.cpp:700
#define PSIDE_BACK
Definition: defines.h:368
#define CONTENTS_PASSABLE
Definition: defines.h:244
bool bevel
Definition: map.h:69
int entitynum
Definition: map.h:76
uint16_t FindOrCreateFloatPlane(vec3_t normal, vec_t dist)
Definition: map.cpp:194
#define CONTENTS_SOLID
Definition: defines.h:223
bspbrush_t * BrushFromBounds(const vec3_t mins, const vec3_t maxs)
Creates a new axial brush.
Definition: bspbrush.cpp:87
int type
Definition: map.h:105
Definition: aabb.h:42
float vec_t
Definition: ufotypes.h:37
bool FixWinding(winding_t *w)
removes degenerate edges from a winding
Definition: polylib.cpp:478
static vec_t BrushVolume(const bspbrush_t *brush)
Returns the volume of the given brush.
Definition: bspbrush.cpp:112
void FreeBrushList(bspbrush_t *brushes)
Definition: bspbrush.cpp:193
#define PSIDE_BOTH
Definition: defines.h:369
void ChopWindingInPlace(winding_t **inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
Definition: polylib.cpp:299
winding_t * winding
Definition: map.h:63
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
AABB brBox
Definition: bspbrush.h:37
float dist
Definition: typedefs.h:374
vec3_t maxs
Definition: aabb.h:258
#define PSIDE_FRONT
Definition: defines.h:367
int side
Definition: bspbrush.h:38
int32_t planenum
Definition: bsp.h:44
#define CONTENTS_DETAIL
Definition: defines.h:251
#define PSIDE_FACING
Definition: defines.h:370
void BrushlistCalcStats(bspbrush_t *brushlist, AABB &blBox)
Counts the faces and calculate the aabb.
Definition: bspbrush.cpp:759
uint32_t BrushListCalcContents(bspbrush_t *brushlist)
Collects the contentsflags of the brushes in the given list.
Definition: bspbrush.cpp:300
side_t * side
Definition: bsp.h:50
bspbrush_t * AllocBrush(int numsides)
Definition: bspbrush.cpp:166
#define AXIAL(p)
Definition: defines.h:201
side_t * SelectSplitSide(bspbrush_t *brushes, bspbrush_t *volume)
Using a heuristic, choses one of the sides out of the brushlist to partition the brushes with...
Definition: bspbrush.cpp:416
Definition: map.h:98
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition: aabb.cpp:57
#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
static int c_active_brushes
Definition: bspbrush.cpp:30
GLsizei size
Definition: r_gl.h:152
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
bspbrush_t * volume
Definition: bsp.h:47
void FreeBrush(bspbrush_t *brushes)
Definition: bspbrush.cpp:179
static bool DoesPlaneSplitBrush(const bspbrush_t *brush, int planenum)
Checks if the plane splits the brush.
Definition: bspbrush.cpp:357
#define STANDARD_NUMBER_OF_BRUSHSIDES
Definition: bspbrush.h:34
uint16_t planenum
Definition: map.h:61
#define Mem_Alloc(size)
Definition: mem.h:40
threadstate_t threadstate
Definition: threads.cpp:32
static void CreateBrushWindings(bspbrush_t *brush)
makes basewindigs for sides and mins/maxs for the brush
Definition: bspbrush.cpp:53
int c_nonvis
Definition: tree.cpp:28
for storing the vertices of the side of a brush or other polygon
Definition: polylib.h:30
bool visible
Definition: map.h:67
static bool CheckPlaneAgainstVolume(int pnum, const bspbrush_t *volume)
Definition: bspbrush.cpp:384
bool WindingIsTiny(winding_t *w)
Returns true if the winding would be crunched out of existance by the vertex snapping.
Definition: polylib.cpp:407
plane_t mapplanes[MAX_MAP_PLANES]
Definition: map.cpp:43
bool tested
Definition: map.h:68
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
Definition: map.h:60
static config_t config
Definition: test_all.cpp:43
bspbrush_t * CopyBrush(const bspbrush_t *brush)
Duplicates the brush, the sides, and the windings.
Definition: bspbrush.cpp:207
struct bspbrush_s * next
Definition: bspbrush.h:36
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
int numsides
Definition: bspbrush.h:41
#define SURF_SKIP
Definition: defines.h:262
side_t sides[STANDARD_NUMBER_OF_BRUSHSIDES]
Definition: bspbrush.h:42
vec_t WindingArea(const winding_t *w)
Definition: polylib.cpp:81
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
QGL_EXTERN GLint i
Definition: r_gl.h:113
struct mapbrush_s * original
Definition: bspbrush.h:40
vec3_t p[4]
Definition: polylib.h:32
struct bspbrush_s bspbrush_t
int brushnum
Definition: map.h:77
bspbrush_t * brushlist
Definition: bsp.h:55
vec_t dist
Definition: map.h:100
#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
static int BrushMostlyOnSide(const bspbrush_t *brush, const plane_t *plane)
Checks on which side a of plane the brush is.
Definition: bspbrush.cpp:328
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition: defines.h:288
vec3_t mins
Definition: aabb.h:257
int testside
Definition: bspbrush.h:39
#define SURF_HINT
Definition: defines.h:261
uint32_t surfaceFlags
Definition: map.h:66
vec3_t normal
Definition: typedefs.h:373
int area
Definition: bsp.h:57
#define TEXINFO_NODE
Definition: defines.h:48
uint32_t contentFlags
Definition: map.h:79
int c_nodes
Definition: tree.cpp:27
void FreeWinding(winding_t *w)
Definition: polylib.cpp:46
int numpoints
Definition: polylib.h:31
static int TestBrushToPlanenum(bspbrush_t *brush, uint16_t planenum, int *numsplits, bool *hintsplit, int *epsilonbrush)
Definition: bspbrush.cpp:224
int TR_BoxOnPlaneSide(const vec3_t mins, const vec3_t maxs, const TR_PLANE_TYPE *plane)
Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH.
Definition: tracing.cpp:542