00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "map.h"
00026 #include "bsp.h"
00027
00028 int c_nodes;
00029 static int c_nonvis;
00030 static int c_active_brushes;
00031
00032
00036 static void BoundBrush (bspbrush_t *brush)
00037 {
00038 int i, j;
00039 winding_t *w;
00040
00041 ClearBounds(brush->mins, brush->maxs);
00042 for (i = 0; i < brush->numsides; i++) {
00043 w = brush->sides[i].winding;
00044 if (!w)
00045 continue;
00046 for (j = 0; j < w->numpoints; j++)
00047 AddPointToBounds(w->p[j], brush->mins, brush->maxs);
00048 }
00049 }
00050
00051 #define SNAP_EPSILON 0.01
00052
00057 static void SnapWeldVector (const vec3_t a, const vec3_t b, vec3_t out)
00058 {
00059 int i;
00060 vec_t outi;
00061
00062
00063 if (a == NULL || b == NULL || out == NULL)
00064 return;
00065
00066
00067 for (i = 0; i < 3; i++) {
00068
00069 const double ai = rint(a[i]);
00070 const double bi = rint(a[i]);
00071
00072
00073 if (ai == a[i])
00074 out[i] = a[i];
00075 else if (bi == b[i])
00076 out[i] = b[i];
00077
00078
00079 else if (fabs(ai - a[i]) < fabs(bi < b[i]))
00080 out[i] = a[i];
00081 else
00082 out[i] = b[i];
00083
00084
00085 outi = rint(out[i]);
00086 if (fabs(outi - out[i]) <= SNAP_EPSILON)
00087 out[i] = outi;
00088 }
00089 }
00090
00095 static qboolean FixWinding (winding_t *w)
00096 {
00097 qboolean valid;
00098 int i, k;
00099
00100
00101 if (!w)
00102 return qfalse;
00103
00104 valid = qtrue;
00105
00106
00107 for (i = 0; i < w->numpoints; i++) {
00108
00109 const int j = (i + 1) % w->numpoints;
00110 vec3_t vec;
00111 float dist;
00112
00113
00114 if (w->numpoints == 3)
00115 return valid;
00116
00117
00118 VectorSubtract(w->p[i], w->p[j], vec);
00119 dist = VectorLength(vec);
00120 if (dist < ON_EPSILON) {
00121 valid = qfalse;
00122
00123
00124 SnapWeldVector(w->p[i], w->p[j], vec);
00125 VectorCopy(vec, w->p[i]);
00126
00127
00128 for (k = i + 2; k < w->numpoints; k++)
00129 VectorCopy(w->p[k], w->p[k - 1]);
00130
00131 w->numpoints--;
00132 }
00133 }
00134
00135
00136 if (w->numpoints < 3)
00137 valid = qfalse;
00138 return valid;
00139 }
00140
00141
00146 static void CreateBrushWindings (bspbrush_t *brush)
00147 {
00148 int i;
00149
00150 for (i = 0; i < brush->numsides; i++) {
00151 side_t *side = &brush->sides[i];
00152 const plane_t *plane = &mapplanes[side->planenum];
00153 int j;
00154
00155
00156 winding_t *w = BaseWindingForPlane(plane->normal, plane->dist);
00157
00158 for (j = 0; j < brush->numsides && w; j++) {
00159 if (i == j)
00160 continue;
00161
00162 if (brush->sides[j].planenum == (brush->sides[i].planenum ^ 1))
00163 continue;
00164 if (brush->sides[j].bevel)
00165 continue;
00166 plane = &mapplanes[brush->sides[j].planenum ^ 1];
00167 ChopWindingInPlace(&w, plane->normal, plane->dist, 0);
00168
00169
00170 if (!FixWinding(w))
00171 Verb_Printf(VERB_EXTRA, "removed degenerated edge(s) from winding\n");
00172 }
00173
00174 side->winding = w;
00175 }
00176
00177 BoundBrush(brush);
00178 }
00179
00183 static bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
00184 {
00185 bspbrush_t *b;
00186 int i;
00187 vec3_t normal;
00188 vec_t dist;
00189
00190 b = AllocBrush(6);
00191 b->numsides = 6;
00192 for (i = 0; i < 3; i++) {
00193 VectorClear(normal);
00194 normal[i] = 1;
00195 dist = maxs[i];
00196 b->sides[i].planenum = FindOrCreateFloatPlane(normal, dist);
00197
00198 normal[i] = -1;
00199 dist = -mins[i];
00200 b->sides[3 + i].planenum = FindOrCreateFloatPlane(normal, dist);
00201 }
00202
00203 CreateBrushWindings(b);
00204
00205 return b;
00206 }
00207
00211 static vec_t BrushVolume (bspbrush_t *brush)
00212 {
00213 int i;
00214 winding_t *w;
00215 vec3_t corner;
00216 vec_t volume;
00217
00218 if (!brush)
00219 return 0;
00220
00221
00222 w = NULL;
00223 for (i = 0; i < brush->numsides; i++) {
00224 w = brush->sides[i].winding;
00225 if (w)
00226 break;
00227 }
00228 if (!w)
00229 return 0;
00230 VectorCopy(w->p[0], corner);
00231
00232
00233 volume = 0;
00234 for (; i < brush->numsides; i++) {
00235 w = brush->sides[i].winding;
00236 if (w) {
00237 const plane_t *plane = &mapplanes[brush->sides[i].planenum];
00238 const vec_t d = -(DotProduct(corner, plane->normal) - plane->dist);
00239 const vec_t area = WindingArea(w);
00240 volume += d * area;
00241 }
00242 }
00243
00244 volume /= 3;
00245 return volume;
00246 }
00247
00251 int CountBrushList (bspbrush_t *brushes)
00252 {
00253 int c;
00254
00255 c = 0;
00256 for (; brushes; brushes = brushes->next)
00257 c++;
00258 return c;
00259 }
00260
00265 static tree_t *AllocTree (void)
00266 {
00267 tree_t *tree = Mem_Alloc(sizeof(*tree));
00268
00269 ClearBounds(tree->mins, tree->maxs);
00270
00271 return tree;
00272 }
00273
00278 static node_t *AllocNode (void)
00279 {
00280 return Mem_Alloc(sizeof(node_t));
00281 }
00282
00287 bspbrush_t *AllocBrush (int numsides)
00288 {
00289 if (threadstate.numthreads == 1)
00290 c_active_brushes++;
00291
00292 return Mem_Alloc(offsetof(bspbrush_t, sides[numsides]));
00293 }
00294
00298 void FreeBrush (bspbrush_t *brushes)
00299 {
00300 int i;
00301
00302 for (i = 0; i < brushes->numsides; i++)
00303 if (brushes->sides[i].winding)
00304 FreeWinding(brushes->sides[i].winding);
00305 Mem_Free(brushes);
00306 if (threadstate.numthreads == 1)
00307 c_active_brushes--;
00308 }
00309
00314 void FreeBrushList (bspbrush_t *brushes)
00315 {
00316 bspbrush_t *next;
00317
00318 for (; brushes; brushes = next) {
00319 next = brushes->next;
00320 FreeBrush(brushes);
00321 }
00322 }
00323
00328 bspbrush_t *CopyBrush (const bspbrush_t *brush)
00329 {
00330 bspbrush_t *newbrush;
00331 int i;
00332 size_t size = offsetof(bspbrush_t, sides[brush->numsides]);
00333
00334 newbrush = AllocBrush(brush->numsides);
00335 memcpy(newbrush, brush, size);
00336
00337 for (i = 0; i < brush->numsides; i++) {
00338 if (brush->sides[i].winding)
00339 newbrush->sides[i].winding = CopyWinding(brush->sides[i].winding);
00340 }
00341
00342 return newbrush;
00343 }
00344
00345
00346 static int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
00347 int *numsplits, qboolean *hintsplit, int *epsilonbrush)
00348 {
00349 int i, j, s;
00350 plane_t *plane;
00351 dBspPlane_t plane2;
00352 winding_t *w;
00353 vec_t d_front, d_back;
00354 int front, back;
00355
00356 *numsplits = 0;
00357 *hintsplit = qfalse;
00358
00359
00360
00361 for (i = 0; i < brush->numsides; i++) {
00362 const int num = brush->sides[i].planenum;
00363 if (num >= 0x10000)
00364 Sys_Error("bad planenum");
00365 if (num == planenum)
00366 return (PSIDE_BACK | PSIDE_FACING);
00367 if (num == (planenum ^ 1))
00368 return (PSIDE_FRONT | PSIDE_FACING);
00369 }
00370
00371
00372 plane = &mapplanes[planenum];
00373
00374
00375 VectorCopy(plane->normal, plane2.normal);
00376 plane2.dist = plane->dist;
00377 plane2.type = plane->type;
00378 s = TR_BoxOnPlaneSide(brush->mins, brush->maxs, &plane2);
00379
00380 if (s != PSIDE_BOTH)
00381 return s;
00382
00383
00384 d_front = d_back = 0;
00385
00386 for (i = 0; i < brush->numsides; i++) {
00387 if (brush->sides[i].texinfo == TEXINFO_NODE)
00388 continue;
00389 if (!brush->sides[i].visible)
00390 continue;
00391 w = brush->sides[i].winding;
00392 if (!w)
00393 continue;
00394 front = back = 0;
00395 for (j = 0; j < w->numpoints; j++) {
00396 const vec_t d = DotProduct(w->p[j], plane->normal) - plane->dist;
00397 if (d > d_front)
00398 d_front = d;
00399 if (d < d_back)
00400 d_back = d;
00401
00402 if (d > 0.1)
00403 front = 1;
00404 else if (d < -0.1)
00405 back = 1;
00406 }
00407 if (front && back) {
00408 (*numsplits)++;
00409 if (brush->sides[i].surfaceFlags & SURF_HINT)
00410 *hintsplit = qtrue;
00411 }
00412 }
00413
00414 if ((d_front > 0.0 && d_front < 1.0) || (d_back < 0.0 && d_back > -1.0))
00415 (*epsilonbrush)++;
00416
00417 return s;
00418 }
00419
00420
00421 #define EDGE_LENGTH 0.2
00422
00426 qboolean WindingIsTiny (winding_t *w)
00427 {
00428 int i, edges;
00429 vec_t len;
00430 vec3_t delta;
00431
00432 edges = 0;
00433 for (i = 0; i < w->numpoints; i++) {
00434 const int j = ((i == w->numpoints - 1) ? 0 : i) + 1;
00435 VectorSubtract(w->p[j], w->p[i], delta);
00436 len = VectorLength(delta);
00437 if (len > EDGE_LENGTH) {
00438 if (++edges == 3)
00439 return qfalse;
00440 }
00441 }
00442 return qtrue;
00443 }
00444
00449 static qboolean WindingIsHuge (const winding_t *w)
00450 {
00451 int i, j;
00452
00453 for (i = 0; i < w->numpoints; i++) {
00454 for (j = 0; j < 3; j++)
00455 if (w->p[i][j] < -MAX_WORLD_WIDTH || w->p[i][j] > MAX_WORLD_WIDTH)
00456 return qtrue;
00457 }
00458 return qfalse;
00459 }
00460
00461 static void LeafNode (node_t *node, bspbrush_t *brushes)
00462 {
00463 bspbrush_t *b;
00464 int i;
00465
00466 node->planenum = PLANENUM_LEAF;
00467 node->contentFlags = 0;
00468
00469 Verb_Printf(VERB_DUMP, "LeafNode: scanning brushes.\n");
00470
00471 for (b = brushes; b; b = b->next) {
00472 Verb_Printf(VERB_DUMP, "LeafNode: scanning brush %i\n", b->original->brushnum);
00473
00474
00475 if (b->original->contentFlags & CONTENTS_SOLID && !(b->original->contentFlags & CONTENTS_PASSABLE)) {
00476 for (i = 0; i < b->numsides; i++)
00477 if (b->sides[i].texinfo != TEXINFO_NODE)
00478 break;
00479 if (i == b->numsides) {
00480 node->contentFlags = CONTENTS_SOLID;
00481 break;
00482 }
00483 }
00484 node->contentFlags |= b->original->contentFlags;
00485 }
00486
00487 node->brushlist = brushes;
00488 }
00489
00490
00491 static void CheckPlaneAgainstParents (int pnum, const node_t *node)
00492 {
00493 node_t *p;
00494
00495 for (p = node->parent; p; p = p->parent) {
00496 if (p->planenum == pnum)
00497 Sys_Error("Tried parent");
00498 }
00499 }
00500
00501 static qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
00502 {
00503 bspbrush_t *front, *back;
00504 qboolean good;
00505
00506 SplitBrush(node->volume, pnum, &front, &back);
00507
00508 good = (front && back);
00509
00510 if (front)
00511 FreeBrush(front);
00512 if (back)
00513 FreeBrush(back);
00514
00515 return good;
00516 }
00517
00523 static side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
00524 {
00525 int value, bestvalue;
00526 bspbrush_t *brush, *test;
00527 side_t *bestside;
00528 int i, j, pass, numpasses, pnum;
00529 int front, back, both, facing, splits;
00530 int bsplits, epsilonbrush;
00531 qboolean hintsplit;
00532
00533 bestside = NULL;
00534 bestvalue = -99999;
00535
00542 numpasses = 4;
00543 for (pass = 0; pass < numpasses; pass++) {
00544 for (brush = brushes; brush; brush = brush->next) {
00545 if ((pass & 1) && !(brush->original->contentFlags & CONTENTS_DETAIL))
00546 continue;
00547 if (!(pass & 1) && (brush->original->contentFlags & CONTENTS_DETAIL))
00548 continue;
00549 for (i = 0; i < brush->numsides; i++) {
00552 side_t *side = brush->sides + i;
00553 if (side->bevel)
00554 continue;
00555 if (!side->winding)
00556 continue;
00557 if (side->texinfo == TEXINFO_NODE)
00558 continue;
00559 if (side->tested)
00560 continue;
00561 if (side->surfaceFlags & SURF_SKIP)
00562 continue;
00563 if (side->visible ^ (pass < 2))
00564 continue;
00565
00566 pnum = side->planenum;
00567 pnum &= ~1;
00568
00569 CheckPlaneAgainstParents(pnum, node);
00570
00571 if (!CheckPlaneAgainstVolume(pnum, node))
00572 continue;
00573
00574 front = 0;
00575 back = 0;
00576 both = 0;
00577 facing = 0;
00578 splits = 0;
00579 epsilonbrush = 0;
00580 hintsplit = qfalse;
00581
00582 for (test = brushes; test; test = test->next) {
00583 const int s = TestBrushToPlanenum(test, pnum, &bsplits, &hintsplit, &epsilonbrush);
00584
00585 splits += bsplits;
00586 if (bsplits && (s & PSIDE_FACING))
00587 Sys_Error("PSIDE_FACING with splits");
00588
00589 test->testside = s;
00590
00591
00592 if (s & PSIDE_FACING) {
00593 facing++;
00594 for (j = 0; j < test->numsides; j++) {
00595 if ((test->sides[j].planenum &~ 1) == pnum)
00596 test->sides[j].tested = qtrue;
00597 }
00598 }
00599 if (s & PSIDE_FRONT)
00600 front++;
00601 if (s & PSIDE_BACK)
00602 back++;
00603 if (s == PSIDE_BOTH)
00604 both++;
00605 }
00606
00607
00608
00609 value = 5 * facing - 5 * splits - abs(front - back);
00610 if (AXIAL(&mapplanes[pnum]))
00611 value += 5;
00612 value -= epsilonbrush * 1000;
00613
00614
00615 if (hintsplit && !(side->surfaceFlags & SURF_HINT))
00616 value = -9999999;
00617
00618
00619
00620
00621 if (value > bestvalue) {
00622 bestvalue = value;
00623 bestside = side;
00624 for (test = brushes; test; test = test->next)
00625 test->side = test->testside;
00626 }
00627 }
00628 }
00629
00630
00631 if (bestside) {
00632 if (pass > 1) {
00633 if (threadstate.numthreads == 1)
00634 c_nonvis++;
00635 }
00636 break;
00637 }
00638 }
00639
00640
00641 for (brush = brushes; brush; brush = brush->next) {
00642 for (i = 0; i < brush->numsides; i++)
00643 brush->sides[i].tested = qfalse;
00644 }
00645
00646 return bestside;
00647 }
00648
00653 static int BrushMostlyOnSide (const bspbrush_t *brush, const plane_t *plane)
00654 {
00655 int i, j, side;
00656 vec_t max;
00657
00658 max = 0;
00659 side = PSIDE_FRONT;
00660 for (i = 0; i < brush->numsides; i++) {
00661 const winding_t *w = brush->sides[i].winding;
00662 if (!w)
00663 continue;
00664 for (j = 0; j < w->numpoints; j++) {
00665 const vec_t d = DotProduct(w->p[j], plane->normal) - plane->dist;
00666 if (d > max) {
00667 max = d;
00668 side = PSIDE_FRONT;
00669 }
00670 if (-d > max) {
00671 max = -d;
00672 side = PSIDE_BACK;
00673 }
00674 }
00675 }
00676 return side;
00677 }
00678
00682 void SplitBrush (const bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back)
00683 {
00684 bspbrush_t *b[2];
00685 int i, j;
00686 winding_t *w, *cw[2], *midwinding;
00687 plane_t *plane, *plane2;
00688 side_t *cs;
00689 float d_front, d_back;
00690
00691 *front = *back = NULL;
00692 plane = &mapplanes[planenum];
00693
00694
00695 d_front = d_back = 0;
00696 for (i = 0; i < brush->numsides; i++) {
00697 w = brush->sides[i].winding;
00698 if (!w)
00699 continue;
00700 for (j = 0; j < w->numpoints; j++) {
00701 const float d = DotProduct(w->p[j], plane->normal) - plane->dist;
00702 if (d > 0 && d > d_front)
00703 d_front = d;
00704 if (d < 0 && d < d_back)
00705 d_back = d;
00706 }
00707 }
00708 if (d_front < 0.1) {
00709
00710 *back = CopyBrush(brush);
00711 return;
00712 }
00713 if (d_back > -0.1) {
00714
00715 *front = CopyBrush(brush);
00716 return;
00717 }
00718
00719
00720 w = BaseWindingForPlane(plane->normal, plane->dist);
00721 for (i = 0; i < brush->numsides && w; i++) {
00722 plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
00723 ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0);
00724 }
00725
00726
00727 if (!w || WindingIsTiny(w)) {
00728 const int side = BrushMostlyOnSide(brush, plane);
00729 if (side == PSIDE_FRONT)
00730 *front = CopyBrush(brush);
00731 else if (side == PSIDE_BACK)
00732 *back = CopyBrush(brush);
00733 return;
00734 }
00735
00736 if (WindingIsHuge(w)) {
00739 Com_Printf("WARNING: Large winding\n");
00740 }
00741
00742 midwinding = w;
00743
00744
00745 for (i = 0; i < 2; i++) {
00746 b[i] = AllocBrush(brush->numsides + 1);
00747 b[i]->original = brush->original;
00748 }
00749
00750
00751 for (i = 0; i < brush->numsides; i++) {
00752 const side_t *s = &brush->sides[i];
00753 w = s->winding;
00754 if (!w)
00755 continue;
00756 ClipWindingEpsilon(w, plane->normal, plane->dist,
00757 0 , &cw[0], &cw[1]);
00758 for (j = 0; j < 2; j++) {
00759 if (!cw[j])
00760 continue;
00761
00762 cs = &b[j]->sides[b[j]->numsides];
00763 b[j]->numsides++;
00764 *cs = *s;
00765
00766 cs->winding = cw[j];
00767 cs->tested = qfalse;
00768 }
00769 }
00770
00771
00772 for (i = 0; i < 2; i++) {
00773 BoundBrush(b[i]);
00774 for (j = 0; j < 3; j++) {
00775 if (b[i]->mins[j] < -MAX_WORLD_WIDTH || b[i]->maxs[j] > MAX_WORLD_WIDTH) {
00778 Verb_Printf(VERB_EXTRA, "bogus brush after clip\n");
00779 break;
00780 }
00781 }
00782
00783 if (b[i]->numsides < 3 || j < 3) {
00784 FreeBrush(b[i]);
00785 b[i] = NULL;
00786 }
00787 }
00788
00789 if (!(b[0] && b[1])) {
00792 if (!b[0] && !b[1])
00793 Verb_Printf(VERB_EXTRA, "split removed brush\n");
00794 else
00795 Verb_Printf(VERB_EXTRA, "split not on both sides\n");
00796 if (b[0]) {
00797 FreeBrush(b[0]);
00798 *front = CopyBrush(brush);
00799 }
00800 if (b[1]) {
00801 FreeBrush(b[1]);
00802 *back = CopyBrush(brush);
00803 }
00804 return;
00805 }
00806
00807
00808 for (i = 0; i < 2; i++) {
00809 cs = &b[i]->sides[b[i]->numsides];
00810 b[i]->numsides++;
00811
00812 cs->planenum = planenum ^ i ^ 1;
00813 cs->texinfo = TEXINFO_NODE;
00814 cs->visible = qfalse;
00815 cs->tested = qfalse;
00816 if (i == 0)
00817 cs->winding = CopyWinding(midwinding);
00818 else
00819 cs->winding = midwinding;
00820 }
00821
00822 for (i = 0; i < 2; i++) {
00823 const vec_t v1 = BrushVolume(b[i]);
00824 if (v1 < 1.0) {
00825 FreeBrush(b[i]);
00826 b[i] = NULL;
00829 Verb_Printf(VERB_EXTRA, "tiny volume after clip\n");
00830 }
00831 }
00832
00833 *front = b[0];
00834 *back = b[1];
00835 }
00836
00837 static void SplitBrushList (bspbrush_t *brushes, node_t *node, bspbrush_t **front, bspbrush_t **back)
00838 {
00839 bspbrush_t *brush, *newbrush, *newbrush2;
00840 side_t *side;
00841 int sides, i;
00842
00843 *front = *back = NULL;
00844
00845 for (brush = brushes; brush; brush = brush->next) {
00846 sides = brush->side;
00847
00848 if (sides == PSIDE_BOTH) {
00849 SplitBrush(brush, node->planenum, &newbrush, &newbrush2);
00850 if (newbrush) {
00851 newbrush->next = *front;
00852 Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
00853 *front = newbrush;
00854 }
00855 if (newbrush2) {
00856 newbrush2->next = *back;
00857 Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush2->original->brushnum);
00858 *back = newbrush2;
00859 }
00860 continue;
00861 }
00862
00863 newbrush = CopyBrush(brush);
00864
00865
00866
00867
00868 if (sides & PSIDE_FACING) {
00869 for (i = 0; i < newbrush->numsides; i++) {
00870 side = newbrush->sides + i;
00871 if ((side->planenum & ~1) == node->planenum)
00872 side->texinfo = TEXINFO_NODE;
00873 }
00874 }
00875
00876 if (sides & PSIDE_FRONT) {
00877 newbrush->next = *front;
00878 *front = newbrush;
00879 Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to front list.\n", newbrush->original->brushnum);
00880 continue;
00881 }
00882 if (sides & PSIDE_BACK) {
00883 newbrush->next = *back;
00884 Verb_Printf(VERB_DUMP, "SplitBrushList: Adding brush %i to back list.\n", newbrush->original->brushnum);
00885 *back = newbrush;
00886 continue;
00887 }
00888 Verb_Printf(VERB_DUMP, "SplitBrushList: Brush %i fell off the map.\n", newbrush->original->brushnum);
00889 }
00890 }
00891
00892
00893 static node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
00894 {
00895 node_t *newnode;
00896 side_t *bestside;
00897 int i;
00898 bspbrush_t *children[2];
00899
00900 if (threadstate.numthreads == 1)
00901 c_nodes++;
00902
00903
00904 bestside = SelectSplitSide(brushes, node);
00905 if (!bestside) {
00906
00907 node->side = NULL;
00908 node->planenum = PLANENUM_LEAF;
00909 LeafNode(node, brushes);
00910 Verb_Printf(VERB_DUMP, "BuildTree_r: Created a leaf node.\n");
00911 return node;
00912 }
00913
00914 Verb_Printf(VERB_DUMP, "BuildTree_r: splitting along plane %i\n", bestside->planenum);
00915
00916
00917 node->side = bestside;
00918 assert(bestside->planenum < MAX_MAP_PLANES);
00919 node->planenum = bestside->planenum & ~1;
00920
00921 SplitBrushList(brushes, node, &children[0], &children[1]);
00922 FreeBrushList(brushes);
00923
00924
00925 for (i = 0; i < 2; i++) {
00926 newnode = AllocNode();
00927 newnode->parent = node;
00928 node->children[i] = newnode;
00929 }
00930
00931 SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
00932 &node->children[1]->volume);
00933
00934
00935 for (i = 0; i < 2; i++) {
00936 node->children[i] = BuildTree_r(node->children[i], children[i]);
00937 }
00938
00939 return node;
00940 }
00941
00945 tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
00946 {
00947 node_t *node;
00948 bspbrush_t *b;
00949 int c_faces, c_nonvisfaces, c_brushes;
00950 tree_t *tree;
00951 int i;
00952 vec_t volume;
00953
00954 Verb_Printf(VERB_EXTRA, "--- BrushBSP ---\n");
00955
00956 tree = AllocTree();
00957
00958 c_faces = 0;
00959 c_nonvisfaces = 0;
00960 c_brushes = 0;
00961 for (b = brushlist; b; b = b->next) {
00962 c_brushes++;
00963
00964 volume = BrushVolume(b);
00965 if (volume < config.microvolume) {
00966 Com_Printf("\nWARNING: entity %i, brush %i: microbrush, volume %.3g\n",
00967 b->original->entitynum, b->original->brushnum, volume);
00968 }
00969
00970 for (i = 0; i < b->numsides; i++) {
00971 if (b->sides[i].bevel)
00972 continue;
00973 if (!b->sides[i].winding)
00974 continue;
00975 if (b->sides[i].texinfo == TEXINFO_NODE)
00976 continue;
00977 if (b->sides[i].visible)
00978 c_faces++;
00979 else
00980 c_nonvisfaces++;
00981 }
00982
00983 AddPointToBounds(b->mins, tree->mins, tree->maxs);
00984 AddPointToBounds(b->maxs, tree->mins, tree->maxs);
00985 }
00986
00987 Verb_Printf(VERB_EXTRA, "%5i brushes\n", c_brushes);
00988 Verb_Printf(VERB_EXTRA, "%5i visible faces\n", c_faces);
00989 Verb_Printf(VERB_EXTRA, "%5i nonvisible faces\n", c_nonvisfaces);
00990
00991 c_nodes = 0;
00992 c_nonvis = 0;
00993 node = AllocNode();
00994
00995 node->volume = BrushFromBounds(mins, maxs);
00996
00997 tree->headnode = node;
00998
00999 node = BuildTree_r(node, brushlist);
01000 Verb_Printf(VERB_EXTRA, "%5i visible nodes\n", c_nodes / 2 - c_nonvis);
01001 Verb_Printf(VERB_EXTRA, "%5i nonvis nodes\n", c_nonvis);
01002 Verb_Printf(VERB_EXTRA, "%5i leafs\n", (c_nodes + 1) / 2);
01003 return tree;
01004 }
01005
01006
01010 void WriteBSPBrushMap (const char *name, const bspbrush_t *list)
01011 {
01012 qFILE f;
01013
01014
01015 Verb_Printf(VERB_LESS, "Writing %s\n", name);
01016
01017
01018 FS_OpenFile(name, &f, FILE_WRITE);
01019 if (f.f == NULL)
01020 Sys_Error("Can't write %s\b", name);
01021
01022 FS_Printf(&f, "{\n\"classname\" \"worldspawn\"\n");
01023
01024 for (; list; list = list->next) {
01025 const side_t *s;
01026 int i;
01027
01028 FS_Printf(&f, "{\n");
01029 for (i = 0, s = list->sides; i < list->numsides; i++, s++) {
01030 winding_t *w = BaseWindingForPlane(mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
01031 const dBspTexinfo_t *t = &curTile->texinfo[s->texinfo];
01032
01033 FS_Printf(&f, "( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
01034 FS_Printf(&f, "( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
01035 FS_Printf(&f, "( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
01036
01037 FS_Printf(&f, "%s 0 0 0 1 1 0 %i %i\n", t->texture, t->surfaceFlags, t->value);
01038 FreeWinding(w);
01039 }
01040 FS_Printf(&f, "}\n");
01041 }
01042 FS_Printf(&f, "}\n");
01043
01044 FS_CloseFile(&f);
01045 }