brushbsp.c (46529B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 #include "qbsp.h" 24 #include "l_mem.h" 25 #include "../botlib/aasfile.h" 26 #include "aas_store.h" 27 #include "aas_cfg.h" 28 29 #include <assert.h> 30 31 /* 32 each side has a count of the other sides it splits 33 34 the best split will be the one that minimizes the total split counts 35 of all remaining sides 36 37 precalc side on plane table 38 39 evaluate split side 40 { 41 cost = 0 42 for all sides 43 for all sides 44 get 45 if side splits side and splitside is on same child 46 cost++; 47 } 48 */ 49 50 int c_nodes; 51 int c_nonvis; 52 int c_active_brushes; 53 int c_solidleafnodes; 54 int c_totalsides; 55 int c_brushmemory; 56 int c_peak_brushmemory; 57 int c_nodememory; 58 int c_peak_totalbspmemory; 59 60 // if a brush just barely pokes onto the other side, 61 // let it slide by without chopping 62 #define PLANESIDE_EPSILON 0.001 63 //0.1 64 65 //#ifdef DEBUG 66 typedef struct cname_s 67 { 68 int value; 69 char *name; 70 } cname_t; 71 72 cname_t contentnames[] = 73 { 74 {CONTENTS_SOLID,"CONTENTS_SOLID"}, 75 {CONTENTS_WINDOW,"CONTENTS_WINDOW"}, 76 {CONTENTS_AUX,"CONTENTS_AUX"}, 77 {CONTENTS_LAVA,"CONTENTS_LAVA"}, 78 {CONTENTS_SLIME,"CONTENTS_SLIME"}, 79 {CONTENTS_WATER,"CONTENTS_WATER"}, 80 {CONTENTS_MIST,"CONTENTS_MIST"}, 81 {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"}, 82 83 {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"}, 84 {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"}, 85 {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"}, 86 {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"}, 87 {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"}, 88 {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"}, 89 {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"}, 90 {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"}, 91 {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"}, 92 {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"}, 93 {CONTENTS_MONSTER,"CONTENTS_MONSTER"}, 94 {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"}, 95 {CONTENTS_DETAIL,"CONTENTS_DETAIL"}, 96 {CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"}, 97 {CONTENTS_LADDER,"CONTENTS_LADDER"}, 98 {0, 0} 99 }; 100 101 void PrintContents(int contents) 102 { 103 int i; 104 105 for (i = 0; contentnames[i].value; i++) 106 { 107 if (contents & contentnames[i].value) 108 { 109 Log_Write("%s,", contentnames[i].name); 110 } //end if 111 } //end for 112 } //end of the function PrintContents 113 114 //#endif DEBUG 115 116 //=========================================================================== 117 // 118 // Parameter: - 119 // Returns: - 120 // Changes Globals: - 121 //=========================================================================== 122 void ResetBrushBSP(void) 123 { 124 c_nodes = 0; 125 c_nonvis = 0; 126 c_active_brushes = 0; 127 c_solidleafnodes = 0; 128 c_totalsides = 0; 129 c_brushmemory = 0; 130 c_peak_brushmemory = 0; 131 c_nodememory = 0; 132 c_peak_totalbspmemory = 0; 133 } //end of the function ResetBrushBSP 134 //=========================================================================== 135 // 136 // Parameter: - 137 // Returns: - 138 // Changes Globals: - 139 //=========================================================================== 140 void FindBrushInTree (node_t *node, int brushnum) 141 { 142 bspbrush_t *b; 143 144 if (node->planenum == PLANENUM_LEAF) 145 { 146 for (b=node->brushlist ; b ; b=b->next) 147 if (b->original->brushnum == brushnum) 148 Log_Print ("here\n"); 149 return; 150 } 151 FindBrushInTree(node->children[0], brushnum); 152 FindBrushInTree(node->children[1], brushnum); 153 } //end of the function FindBrushInTree 154 //=========================================================================== 155 // 156 // Parameter: - 157 // Returns: - 158 // Changes Globals: - 159 //=========================================================================== 160 void DrawBrushList (bspbrush_t *brush, node_t *node) 161 { 162 int i; 163 side_t *s; 164 165 GLS_BeginScene (); 166 for ( ; brush ; brush=brush->next) 167 { 168 for (i=0 ; i<brush->numsides ; i++) 169 { 170 s = &brush->sides[i]; 171 if (!s->winding) 172 continue; 173 if (s->texinfo == TEXINFO_NODE) 174 GLS_Winding (s->winding, 1); 175 else if (!(s->flags & SFL_VISIBLE)) 176 GLS_Winding (s->winding, 2); 177 else 178 GLS_Winding (s->winding, 0); 179 } 180 } 181 GLS_EndScene (); 182 } //end of the function DrawBrushList 183 //=========================================================================== 184 // 185 // Parameter: - 186 // Returns: - 187 // Changes Globals: - 188 //=========================================================================== 189 void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis) 190 { 191 int i; 192 side_t *s; 193 FILE *f; 194 195 qprintf ("writing %s\n", name); 196 f = SafeOpenWrite (name); 197 198 for ( ; brush ; brush=brush->next) 199 { 200 for (i=0 ; i<brush->numsides ; i++) 201 { 202 s = &brush->sides[i]; 203 if (!s->winding) 204 continue; 205 if (onlyvis && !(s->flags & SFL_VISIBLE)) 206 continue; 207 OutputWinding (brush->sides[i].winding, f); 208 } 209 } 210 211 fclose (f); 212 } //end of the function WriteBrushList 213 //=========================================================================== 214 // 215 // Parameter: - 216 // Returns: - 217 // Changes Globals: - 218 //=========================================================================== 219 void PrintBrush (bspbrush_t *brush) 220 { 221 int i; 222 223 printf ("brush: %p\n", brush); 224 for (i=0;i<brush->numsides ; i++) 225 { 226 pw(brush->sides[i].winding); 227 printf ("\n"); 228 } //end for 229 } //end of the function PrintBrush 230 //=========================================================================== 231 // Sets the mins/maxs based on the windings 232 // 233 // Parameter: - 234 // Returns: - 235 // Changes Globals: - 236 //=========================================================================== 237 void BoundBrush (bspbrush_t *brush) 238 { 239 int i, j; 240 winding_t *w; 241 242 ClearBounds (brush->mins, brush->maxs); 243 for (i=0 ; i<brush->numsides ; i++) 244 { 245 w = brush->sides[i].winding; 246 if (!w) 247 continue; 248 for (j=0 ; j<w->numpoints ; j++) 249 AddPointToBounds (w->p[j], brush->mins, brush->maxs); 250 } 251 } //end of the function BoundBrush 252 //=========================================================================== 253 // 254 // Parameter: - 255 // Returns: - 256 // Changes Globals: - 257 //=========================================================================== 258 void CreateBrushWindings (bspbrush_t *brush) 259 { 260 int i, j; 261 winding_t *w; 262 side_t *side; 263 plane_t *plane; 264 265 for (i=0 ; i<brush->numsides ; i++) 266 { 267 side = &brush->sides[i]; 268 plane = &mapplanes[side->planenum]; 269 w = BaseWindingForPlane (plane->normal, plane->dist); 270 for (j=0 ; j<brush->numsides && w; j++) 271 { 272 if (i == j) 273 continue; 274 if (brush->sides[j].flags & SFL_BEVEL) 275 continue; 276 plane = &mapplanes[brush->sides[j].planenum^1]; 277 ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); 278 } 279 280 side->winding = w; 281 } 282 283 BoundBrush (brush); 284 } //end of the function CreateBrushWindings 285 //=========================================================================== 286 // Creates a new axial brush 287 // 288 // Parameter: - 289 // Returns: - 290 // Changes Globals: - 291 //=========================================================================== 292 bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) 293 { 294 bspbrush_t *b; 295 int i; 296 vec3_t normal; 297 vec_t dist; 298 299 b = AllocBrush (6); 300 b->numsides = 6; 301 for (i=0 ; i<3 ; i++) 302 { 303 VectorClear (normal); 304 normal[i] = 1; 305 dist = maxs[i]; 306 b->sides[i].planenum = FindFloatPlane (normal, dist); 307 308 normal[i] = -1; 309 dist = -mins[i]; 310 b->sides[3+i].planenum = FindFloatPlane (normal, dist); 311 } 312 313 CreateBrushWindings (b); 314 315 return b; 316 } //end of the function BrushFromBounds 317 //=========================================================================== 318 // 319 // Parameter: - 320 // Returns: - 321 // Changes Globals: - 322 //=========================================================================== 323 int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon) 324 { 325 int i, j, n; 326 winding_t *w; 327 side_t *side; 328 329 for (i = 0; i < brush->numsides; i++) 330 { 331 side = &brush->sides[i]; 332 w = side->winding; 333 for (j = 0; j < w->numpoints; j++) 334 { 335 for (n = 0; n < 3; n++) 336 { 337 if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true; 338 } //end for 339 } //end for 340 } //end for 341 return false; 342 } //end of the function BrushOutOfBounds 343 //=========================================================================== 344 // 345 // Parameter: - 346 // Returns: - 347 // Changes Globals: - 348 //=========================================================================== 349 vec_t BrushVolume (bspbrush_t *brush) 350 { 351 int i; 352 winding_t *w; 353 vec3_t corner; 354 vec_t d, area, volume; 355 plane_t *plane; 356 357 if (!brush) return 0; 358 359 // grab the first valid point as the corner 360 w = NULL; 361 for (i = 0; i < brush->numsides; i++) 362 { 363 w = brush->sides[i].winding; 364 if (w) break; 365 } //end for 366 if (!w) return 0; 367 VectorCopy (w->p[0], corner); 368 369 // make tetrahedrons to all other faces 370 volume = 0; 371 for ( ; i < brush->numsides; i++) 372 { 373 w = brush->sides[i].winding; 374 if (!w) continue; 375 plane = &mapplanes[brush->sides[i].planenum]; 376 d = -(DotProduct (corner, plane->normal) - plane->dist); 377 area = WindingArea(w); 378 volume += d * area; 379 } //end for 380 381 volume /= 3; 382 return volume; 383 } //end of the function BrushVolume 384 //=========================================================================== 385 // 386 // Parameter: - 387 // Returns: - 388 // Changes Globals: - 389 //=========================================================================== 390 int CountBrushList (bspbrush_t *brushes) 391 { 392 int c; 393 394 c = 0; 395 for ( ; brushes; brushes = brushes->next) c++; 396 return c; 397 } //end of the function CountBrushList 398 //=========================================================================== 399 // 400 // Parameter: - 401 // Returns: - 402 // Changes Globals: - 403 //=========================================================================== 404 node_t *AllocNode (void) 405 { 406 node_t *node; 407 408 node = GetMemory(sizeof(*node)); 409 memset (node, 0, sizeof(*node)); 410 if (numthreads == 1) 411 { 412 c_nodememory += MemorySize(node); 413 } //end if 414 return node; 415 } //end of the function AllocNode 416 //=========================================================================== 417 // 418 // Parameter: - 419 // Returns: - 420 // Changes Globals: - 421 //=========================================================================== 422 bspbrush_t *AllocBrush (int numsides) 423 { 424 bspbrush_t *bb; 425 int c; 426 427 c = (int)&(((bspbrush_t *)0)->sides[numsides]); 428 bb = GetMemory(c); 429 memset (bb, 0, c); 430 if (numthreads == 1) 431 { 432 c_active_brushes++; 433 c_brushmemory += MemorySize(bb); 434 if (c_brushmemory > c_peak_brushmemory) 435 c_peak_brushmemory = c_brushmemory; 436 } //end if 437 return bb; 438 } //end of the function AllocBrush 439 //=========================================================================== 440 // 441 // Parameter: - 442 // Returns: - 443 // Changes Globals: - 444 //=========================================================================== 445 void FreeBrush (bspbrush_t *brushes) 446 { 447 int i; 448 449 for (i=0 ; i<brushes->numsides ; i++) 450 if (brushes->sides[i].winding) 451 FreeWinding(brushes->sides[i].winding); 452 if (numthreads == 1) 453 { 454 c_active_brushes--; 455 c_brushmemory -= MemorySize(brushes); 456 if (c_brushmemory < 0) c_brushmemory = 0; 457 } //end if 458 FreeMemory(brushes); 459 } //end of the function FreeBrush 460 //=========================================================================== 461 // 462 // Parameter: - 463 // Returns: - 464 // Changes Globals: - 465 //=========================================================================== 466 void FreeBrushList (bspbrush_t *brushes) 467 { 468 bspbrush_t *next; 469 470 for ( ; brushes; brushes = next) 471 { 472 next = brushes->next; 473 474 FreeBrush(brushes); 475 } //end for 476 } //end of the function FreeBrushList 477 //=========================================================================== 478 // Duplicates the brush, the sides, and the windings 479 // 480 // Parameter: - 481 // Returns: - 482 // Changes Globals: - 483 //=========================================================================== 484 bspbrush_t *CopyBrush (bspbrush_t *brush) 485 { 486 bspbrush_t *newbrush; 487 int size; 488 int i; 489 490 size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); 491 492 newbrush = AllocBrush (brush->numsides); 493 memcpy (newbrush, brush, size); 494 495 for (i=0 ; i<brush->numsides ; i++) 496 { 497 if (brush->sides[i].winding) 498 newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); 499 } 500 501 return newbrush; 502 } //end of the function CopyBrush 503 //=========================================================================== 504 // 505 // Parameter: - 506 // Returns: - 507 // Changes Globals: - 508 //=========================================================================== 509 node_t *PointInLeaf (node_t *node, vec3_t point) 510 { 511 vec_t d; 512 plane_t *plane; 513 514 while (node->planenum != PLANENUM_LEAF) 515 { 516 plane = &mapplanes[node->planenum]; 517 d = DotProduct (point, plane->normal) - plane->dist; 518 if (d > 0) 519 node = node->children[0]; 520 else 521 node = node->children[1]; 522 } 523 524 return node; 525 } //end of the function PointInLeaf 526 //=========================================================================== 527 // Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH 528 // 529 // Parameter: - 530 // Returns: - 531 // Changes Globals: - 532 //=========================================================================== 533 #if 0 534 int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane) 535 { 536 int side; 537 int i; 538 vec3_t corners[2]; 539 vec_t dist1, dist2; 540 541 // axial planes are easy 542 if (plane->type < 3) 543 { 544 side = 0; 545 if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON) 546 side |= PSIDE_FRONT; 547 if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON) 548 side |= PSIDE_BACK; 549 return side; 550 } 551 552 // create the proper leading and trailing verts for the box 553 554 for (i=0 ; i<3 ; i++) 555 { 556 if (plane->normal[i] < 0) 557 { 558 corners[0][i] = mins[i]; 559 corners[1][i] = maxs[i]; 560 } 561 else 562 { 563 corners[1][i] = mins[i]; 564 corners[0][i] = maxs[i]; 565 } 566 } 567 568 dist1 = DotProduct (plane->normal, corners[0]) - plane->dist; 569 dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; 570 side = 0; 571 if (dist1 >= PLANESIDE_EPSILON) 572 side = PSIDE_FRONT; 573 if (dist2 < PLANESIDE_EPSILON) 574 side |= PSIDE_BACK; 575 576 return side; 577 } 578 #else 579 int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p) 580 { 581 float dist1, dist2; 582 int sides; 583 584 // axial planes are easy 585 if (p->type < 3) 586 { 587 sides = 0; 588 if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT; 589 if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK; 590 return sides; 591 } //end if 592 593 // general case 594 switch (p->signbits) 595 { 596 case 0: 597 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; 598 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; 599 break; 600 case 1: 601 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; 602 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; 603 break; 604 case 2: 605 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; 606 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; 607 break; 608 case 3: 609 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; 610 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; 611 break; 612 case 4: 613 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; 614 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; 615 break; 616 case 5: 617 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; 618 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; 619 break; 620 case 6: 621 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; 622 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; 623 break; 624 case 7: 625 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; 626 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; 627 break; 628 default: 629 dist1 = dist2 = 0; // shut up compiler 630 // assert( 0 ); 631 break; 632 } 633 634 sides = 0; 635 if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT; 636 if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK; 637 638 // assert(sides != 0); 639 640 return sides; 641 } 642 #endif 643 //=========================================================================== 644 // 645 // Parameter: - 646 // Returns: - 647 // Changes Globals: - 648 //=========================================================================== 649 int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits) 650 { 651 int i, num; 652 plane_t *plane; 653 int s; 654 655 *numsplits = 0; 656 657 plane = &mapplanes[planenum]; 658 659 #ifdef ME 660 //fast axial cases 661 if (plane->type < 3) 662 { 663 if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type]) 664 return PSIDE_FRONT; 665 if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type]) 666 return PSIDE_BACK; 667 } //end if 668 #endif //ME*/ 669 670 // if the brush actually uses the planenum, 671 // we can tell the side for sure 672 for (i = 0; i < brush->numsides; i++) 673 { 674 num = brush->sides[i].planenum; 675 if (num >= MAX_MAPFILE_PLANES) 676 Error ("bad planenum"); 677 if (num == planenum) 678 return PSIDE_BACK|PSIDE_FACING; 679 if (num == (planenum ^ 1) ) 680 return PSIDE_FRONT|PSIDE_FACING; 681 682 } 683 684 // box on plane side 685 s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); 686 687 // if both sides, count the visible faces split 688 if (s == PSIDE_BOTH) 689 { 690 *numsplits += 3; 691 } 692 693 return s; 694 } //end of the function QuickTestBrushToPlanenum 695 //=========================================================================== 696 // 697 // Parameter: - 698 // Returns: - 699 // Changes Globals: - 700 //=========================================================================== 701 int TestBrushToPlanenum (bspbrush_t *brush, int planenum, 702 int *numsplits, qboolean *hintsplit, int *epsilonbrush) 703 { 704 int i, j, num; 705 plane_t *plane; 706 int s = 0; 707 winding_t *w; 708 vec_t d, d_front, d_back; 709 int front, back; 710 int type; 711 float dist; 712 713 *numsplits = 0; 714 *hintsplit = false; 715 716 plane = &mapplanes[planenum]; 717 718 #ifdef ME 719 //fast axial cases 720 type = plane->type; 721 if (type < 3) 722 { 723 dist = plane->dist; 724 if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT; 725 if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK; 726 if (brush->mins[type] < dist - PLANESIDE_EPSILON && 727 brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH; 728 } //end if 729 730 if (s != PSIDE_BOTH) 731 #endif //ME 732 { 733 // if the brush actually uses the planenum, 734 // we can tell the side for sure 735 for (i = 0; i < brush->numsides; i++) 736 { 737 num = brush->sides[i].planenum; 738 if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum"); 739 if (num == planenum) 740 { 741 //we don't need to test this side plane again 742 brush->sides[i].flags |= SFL_TESTED; 743 return PSIDE_BACK|PSIDE_FACING; 744 } //end if 745 if (num == (planenum ^ 1) ) 746 { 747 //we don't need to test this side plane again 748 brush->sides[i].flags |= SFL_TESTED; 749 return PSIDE_FRONT|PSIDE_FACING; 750 } //end if 751 } //end for 752 753 // box on plane side 754 s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); 755 756 if (s != PSIDE_BOTH) return s; 757 } //end if 758 759 // if both sides, count the visible faces split 760 d_front = d_back = 0; 761 762 for (i = 0; i < brush->numsides; i++) 763 { 764 if (brush->sides[i].texinfo == TEXINFO_NODE) 765 continue; // on node, don't worry about splits 766 if (!(brush->sides[i].flags & SFL_VISIBLE)) 767 continue; // we don't care about non-visible 768 w = brush->sides[i].winding; 769 if (!w) continue; 770 front = back = 0; 771 for (j = 0; j < w->numpoints; j++) 772 { 773 d = DotProduct(w->p[j], plane->normal) - plane->dist; 774 if (d > d_front) d_front = d; 775 if (d < d_back) d_back = d; 776 if (d > 0.1) // PLANESIDE_EPSILON) 777 front = 1; 778 if (d < -0.1) // PLANESIDE_EPSILON) 779 back = 1; 780 } //end for 781 if (front && back) 782 { 783 if ( !(brush->sides[i].surf & SURF_SKIP) ) 784 { 785 (*numsplits)++; 786 if (brush->sides[i].surf & SURF_HINT) 787 { 788 *hintsplit = true; 789 } //end if 790 } //end if 791 } //end if 792 } //end for 793 794 if ( (d_front > 0.0 && d_front < 1.0) 795 || (d_back < 0.0 && d_back > -1.0) ) 796 (*epsilonbrush)++; 797 798 #if 0 799 if (*numsplits == 0) 800 { // didn't really need to be split 801 if (front) s = PSIDE_FRONT; 802 else if (back) s = PSIDE_BACK; 803 else s = 0; 804 } 805 #endif 806 807 return s; 808 } //end of the function TestBrushToPlanenum 809 //=========================================================================== 810 // Returns true if the winding would be crunched out of 811 // existance by the vertex snapping. 812 // 813 // Parameter: - 814 // Returns: - 815 // Changes Globals: - 816 //=========================================================================== 817 #define EDGE_LENGTH 0.2 818 qboolean WindingIsTiny (winding_t *w) 819 { 820 #if 0 821 if (WindingArea (w) < 1) 822 return true; 823 return false; 824 #else 825 int i, j; 826 vec_t len; 827 vec3_t delta; 828 int edges; 829 830 edges = 0; 831 for (i=0 ; i<w->numpoints ; i++) 832 { 833 j = i == w->numpoints - 1 ? 0 : i+1; 834 VectorSubtract (w->p[j], w->p[i], delta); 835 len = VectorLength (delta); 836 if (len > EDGE_LENGTH) 837 { 838 if (++edges == 3) 839 return false; 840 } 841 } 842 return true; 843 #endif 844 } //end of the function WindingIsTiny 845 //=========================================================================== 846 // Returns true if the winding still has one of the points 847 // from basewinding for plane 848 // 849 // Parameter: - 850 // Returns: - 851 // Changes Globals: - 852 //=========================================================================== 853 qboolean WindingIsHuge (winding_t *w) 854 { 855 int i, j; 856 857 for (i=0 ; i<w->numpoints ; i++) 858 { 859 for (j=0 ; j<3 ; j++) 860 if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1) 861 return true; 862 } 863 return false; 864 } //end of the function WindingIsHuge 865 //=========================================================================== 866 // creates a leaf out of the given nodes with the given brushes 867 // 868 // Parameter: - 869 // Returns: - 870 // Changes Globals: - 871 //=========================================================================== 872 void LeafNode(node_t *node, bspbrush_t *brushes) 873 { 874 bspbrush_t *b; 875 int i; 876 877 node->side = NULL; 878 node->planenum = PLANENUM_LEAF; 879 node->contents = 0; 880 881 for (b = brushes; b; b = b->next) 882 { 883 // if the brush is solid and all of its sides are on nodes, 884 // it eats everything 885 if (b->original->contents & CONTENTS_SOLID) 886 { 887 for (i=0 ; i<b->numsides ; i++) 888 if (b->sides[i].texinfo != TEXINFO_NODE) 889 break; 890 if (i == b->numsides) 891 { 892 node->contents = CONTENTS_SOLID; 893 break; 894 } //end if 895 } //end if 896 node->contents |= b->original->contents; 897 } //end for 898 899 if (create_aas) 900 { 901 node->expansionbboxes = 0; 902 node->contents = 0; 903 for (b = brushes; b; b = b->next) 904 { 905 node->expansionbboxes |= b->original->expansionbbox; 906 node->contents |= b->original->contents; 907 if (b->original->modelnum) 908 node->modelnum = b->original->modelnum; 909 } //end for 910 if (node->contents & CONTENTS_SOLID) 911 { 912 if (node->expansionbboxes != cfg.allpresencetypes) 913 { 914 node->contents &= ~CONTENTS_SOLID; 915 } //end if 916 } //end if 917 } //end if 918 919 node->brushlist = brushes; 920 } //end of the function LeafNode 921 //=========================================================================== 922 // 923 // Parameter: - 924 // Returns: - 925 // Changes Globals: - 926 //=========================================================================== 927 void CheckPlaneAgainstParents (int pnum, node_t *node) 928 { 929 node_t *p; 930 931 for (p = node->parent; p; p = p->parent) 932 { 933 if (p->planenum == pnum) Error("Tried parent"); 934 } //end for 935 } //end of the function CheckPlaneAgainstParants 936 //=========================================================================== 937 // 938 // Parameter: - 939 // Returns: - 940 // Changes Globals: - 941 //=========================================================================== 942 qboolean CheckPlaneAgainstVolume (int pnum, node_t *node) 943 { 944 bspbrush_t *front, *back; 945 qboolean good; 946 947 SplitBrush (node->volume, pnum, &front, &back); 948 949 good = (front && back); 950 951 if (front) FreeBrush (front); 952 if (back) FreeBrush (back); 953 954 return good; 955 } //end of the function CheckPlaneAgaintsVolume 956 //=========================================================================== 957 // Using a hueristic, choses one of the sides out of the brushlist 958 // to partition the brushes with. 959 // Returns NULL if there are no valid planes to split with.. 960 // 961 // Parameter: - 962 // Returns: - 963 // Changes Globals: - 964 //=========================================================================== 965 side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node) 966 { 967 int value, bestvalue; 968 bspbrush_t *brush, *test; 969 side_t *side, *bestside; 970 int i, pass, numpasses; 971 int pnum; 972 int s; 973 int front, back, both, facing, splits; 974 int bsplits; 975 int bestsplits; 976 int epsilonbrush; 977 qboolean hintsplit = false; 978 979 bestside = NULL; 980 bestvalue = -99999; 981 bestsplits = 0; 982 983 // the search order goes: visible-structural, visible-detail, 984 // nonvisible-structural, nonvisible-detail. 985 // If any valid plane is available in a pass, no further 986 // passes will be tried. 987 numpasses = 2; 988 for (pass = 0; pass < numpasses; pass++) 989 { 990 for (brush = brushes; brush; brush = brush->next) 991 { 992 // only check detail the second pass 993 // if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) ) 994 // continue; 995 // if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) ) 996 // continue; 997 for (i = 0; i < brush->numsides; i++) 998 { 999 side = brush->sides + i; 1000 // if (side->flags & SFL_BEVEL) 1001 // continue; // never use a bevel as a spliter 1002 if (!side->winding) 1003 continue; // nothing visible, so it can't split 1004 if (side->texinfo == TEXINFO_NODE) 1005 continue; // allready a node splitter 1006 if (side->flags & SFL_TESTED) 1007 continue; // we allready have metrics for this plane 1008 // if (side->surf & SURF_SKIP) 1009 // continue; // skip surfaces are never chosen 1010 1011 // if (!(side->flags & SFL_VISIBLE) && (pass < 2)) 1012 // continue; // only check visible faces on first pass 1013 1014 if ((side->flags & SFL_CURVE) && (pass < 1)) 1015 continue; // only check curves the second pass 1016 1017 pnum = side->planenum; 1018 pnum &= ~1; // allways use positive facing plane 1019 1020 CheckPlaneAgainstParents (pnum, node); 1021 1022 if (!CheckPlaneAgainstVolume (pnum, node)) 1023 continue; // would produce a tiny volume 1024 1025 front = 0; 1026 back = 0; 1027 both = 0; 1028 facing = 0; 1029 splits = 0; 1030 epsilonbrush = 0; 1031 1032 //inner loop: optimize 1033 for (test = brushes; test; test = test->next) 1034 { 1035 s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush); 1036 1037 splits += bsplits; 1038 // if (bsplits && (s&PSIDE_FACING) ) 1039 // Error ("PSIDE_FACING with splits"); 1040 1041 test->testside = s; 1042 // 1043 if (s & PSIDE_FACING) facing++; 1044 if (s & PSIDE_FRONT) front++; 1045 if (s & PSIDE_BACK) back++; 1046 if (s == PSIDE_BOTH) both++; 1047 } //end for 1048 1049 // give a value estimate for using this plane 1050 value = 5*facing - 5*splits - abs(front-back); 1051 // value = -5*splits; 1052 // value = 5*facing - 5*splits; 1053 if (mapplanes[pnum].type < 3) 1054 value+=5; // axial is better 1055 1056 value -= epsilonbrush * 1000; // avoid! 1057 1058 // never split a hint side except with another hint 1059 if (hintsplit && !(side->surf & SURF_HINT) ) 1060 value = -9999999; 1061 1062 // save off the side test so we don't need 1063 // to recalculate it when we actually seperate 1064 // the brushes 1065 if (value > bestvalue) 1066 { 1067 bestvalue = value; 1068 bestside = side; 1069 bestsplits = splits; 1070 for (test = brushes; test ; test = test->next) 1071 test->side = test->testside; 1072 } //end if 1073 } //end for 1074 } //end for (brush = brushes; 1075 1076 // if we found a good plane, don't bother trying any 1077 // other passes 1078 if (bestside) 1079 { 1080 if (pass > 1) 1081 { 1082 if (numthreads == 1) c_nonvis++; 1083 } 1084 if (pass > 0) node->detail_seperator = true; // not needed for vis 1085 break; 1086 } //end if 1087 } //end for (pass = 0; 1088 1089 // 1090 // clear all the tested flags we set 1091 // 1092 for (brush = brushes ; brush ; brush=brush->next) 1093 { 1094 for (i = 0; i < brush->numsides; i++) 1095 { 1096 brush->sides[i].flags &= ~SFL_TESTED; 1097 } //end for 1098 } //end for 1099 1100 return bestside; 1101 } //end of the function SelectSplitSide 1102 //=========================================================================== 1103 // 1104 // Parameter: - 1105 // Returns: - 1106 // Changes Globals: - 1107 //=========================================================================== 1108 int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane) 1109 { 1110 int i, j; 1111 winding_t *w; 1112 vec_t d, max; 1113 int side; 1114 1115 max = 0; 1116 side = PSIDE_FRONT; 1117 for (i=0 ; i<brush->numsides ; i++) 1118 { 1119 w = brush->sides[i].winding; 1120 if (!w) 1121 continue; 1122 for (j=0 ; j<w->numpoints ; j++) 1123 { 1124 d = DotProduct (w->p[j], plane->normal) - plane->dist; 1125 if (d > max) 1126 { 1127 max = d; 1128 side = PSIDE_FRONT; 1129 } 1130 if (-d > max) 1131 { 1132 max = -d; 1133 side = PSIDE_BACK; 1134 } 1135 } 1136 } 1137 return side; 1138 } //end of the function BrushMostlyOnSide 1139 //=========================================================================== 1140 // Generates two new brushes, leaving the original 1141 // unchanged 1142 // 1143 // Parameter: - 1144 // Returns: - 1145 // Changes Globals: - 1146 //=========================================================================== 1147 void SplitBrush (bspbrush_t *brush, int planenum, 1148 bspbrush_t **front, bspbrush_t **back) 1149 { 1150 bspbrush_t *b[2]; 1151 int i, j; 1152 winding_t *w, *cw[2], *midwinding; 1153 plane_t *plane, *plane2; 1154 side_t *s, *cs; 1155 float d, d_front, d_back; 1156 1157 *front = *back = NULL; 1158 plane = &mapplanes[planenum]; 1159 1160 // check all points 1161 d_front = d_back = 0; 1162 for (i=0 ; i<brush->numsides ; i++) 1163 { 1164 w = brush->sides[i].winding; 1165 if (!w) 1166 continue; 1167 for (j=0 ; j<w->numpoints ; j++) 1168 { 1169 d = DotProduct (w->p[j], plane->normal) - plane->dist; 1170 if (d > 0 && d > d_front) 1171 d_front = d; 1172 if (d < 0 && d < d_back) 1173 d_back = d; 1174 } 1175 } 1176 1177 if (d_front < 0.2) // PLANESIDE_EPSILON) 1178 { // only on back 1179 *back = CopyBrush (brush); 1180 return; 1181 } 1182 if (d_back > -0.2) // PLANESIDE_EPSILON) 1183 { // only on front 1184 *front = CopyBrush (brush); 1185 return; 1186 } 1187 1188 // create a new winding from the split plane 1189 1190 w = BaseWindingForPlane (plane->normal, plane->dist); 1191 for (i=0 ; i<brush->numsides && w ; i++) 1192 { 1193 plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; 1194 ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); 1195 } 1196 1197 if (!w || WindingIsTiny(w)) 1198 { // the brush isn't really split 1199 int side; 1200 1201 side = BrushMostlyOnSide (brush, plane); 1202 if (side == PSIDE_FRONT) 1203 *front = CopyBrush (brush); 1204 if (side == PSIDE_BACK) 1205 *back = CopyBrush (brush); 1206 //free a possible winding 1207 if (w) FreeWinding(w); 1208 return; 1209 } 1210 1211 if (WindingIsHuge (w)) 1212 { 1213 Log_Write("WARNING: huge winding\n"); 1214 } 1215 1216 midwinding = w; 1217 1218 // split it for real 1219 1220 for (i=0 ; i<2 ; i++) 1221 { 1222 b[i] = AllocBrush (brush->numsides+1); 1223 b[i]->original = brush->original; 1224 } 1225 1226 // split all the current windings 1227 1228 for (i=0 ; i<brush->numsides ; i++) 1229 { 1230 s = &brush->sides[i]; 1231 w = s->winding; 1232 if (!w) 1233 continue; 1234 ClipWindingEpsilon (w, plane->normal, plane->dist, 1235 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); 1236 for (j=0 ; j<2 ; j++) 1237 { 1238 if (!cw[j]) 1239 continue; 1240 #if 0 1241 if (WindingIsTiny (cw[j])) 1242 { 1243 FreeWinding (cw[j]); 1244 continue; 1245 } 1246 #endif 1247 cs = &b[j]->sides[b[j]->numsides]; 1248 b[j]->numsides++; 1249 *cs = *s; 1250 // cs->planenum = s->planenum; 1251 // cs->texinfo = s->texinfo; 1252 // cs->original = s->original; 1253 cs->winding = cw[j]; 1254 cs->flags &= ~SFL_TESTED; 1255 } 1256 } 1257 1258 1259 // see if we have valid polygons on both sides 1260 1261 for (i=0 ; i<2 ; i++) 1262 { 1263 BoundBrush (b[i]); 1264 for (j=0 ; j<3 ; j++) 1265 { 1266 if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS) 1267 { 1268 Log_Write("bogus brush after clip"); 1269 break; 1270 } 1271 } 1272 1273 if (b[i]->numsides < 3 || j < 3) 1274 { 1275 FreeBrush (b[i]); 1276 b[i] = NULL; 1277 } 1278 } 1279 1280 if ( !(b[0] && b[1]) ) 1281 { 1282 if (!b[0] && !b[1]) 1283 Log_Write("split removed brush\r\n"); 1284 else 1285 Log_Write("split not on both sides\r\n"); 1286 if (b[0]) 1287 { 1288 FreeBrush (b[0]); 1289 *front = CopyBrush (brush); 1290 } 1291 if (b[1]) 1292 { 1293 FreeBrush (b[1]); 1294 *back = CopyBrush (brush); 1295 } 1296 return; 1297 } 1298 1299 // add the midwinding to both sides 1300 for (i=0 ; i<2 ; i++) 1301 { 1302 cs = &b[i]->sides[b[i]->numsides]; 1303 b[i]->numsides++; 1304 1305 cs->planenum = planenum^i^1; 1306 cs->texinfo = TEXINFO_NODE; //never use these sides as splitters 1307 cs->flags &= ~SFL_VISIBLE; 1308 cs->flags &= ~SFL_TESTED; 1309 if (i==0) 1310 cs->winding = CopyWinding (midwinding); 1311 else 1312 cs->winding = midwinding; 1313 } 1314 1315 { 1316 vec_t v1; 1317 int i; 1318 1319 for (i = 0; i < 2; i++) 1320 { 1321 v1 = BrushVolume (b[i]); 1322 if (v1 < 1.0) 1323 { 1324 FreeBrush(b[i]); 1325 b[i] = NULL; 1326 //Log_Write("tiny volume after clip"); 1327 } 1328 } 1329 if (!b[0] && !b[1]) 1330 { 1331 Log_Write("two tiny brushes\r\n"); 1332 } //end if 1333 } 1334 1335 *front = b[0]; 1336 *back = b[1]; 1337 } //end of the function SplitBrush 1338 //=========================================================================== 1339 // 1340 // Parameter: - 1341 // Returns: - 1342 // Changes Globals: - 1343 //=========================================================================== 1344 void SplitBrushList (bspbrush_t *brushes, 1345 node_t *node, bspbrush_t **front, bspbrush_t **back) 1346 { 1347 bspbrush_t *brush, *newbrush, *newbrush2; 1348 side_t *side; 1349 int sides; 1350 int i; 1351 1352 *front = *back = NULL; 1353 1354 for (brush = brushes; brush; brush = brush->next) 1355 { 1356 sides = brush->side; 1357 1358 if (sides == PSIDE_BOTH) 1359 { // split into two brushes 1360 SplitBrush (brush, node->planenum, &newbrush, &newbrush2); 1361 if (newbrush) 1362 { 1363 newbrush->next = *front; 1364 *front = newbrush; 1365 } //end if 1366 if (newbrush2) 1367 { 1368 newbrush2->next = *back; 1369 *back = newbrush2; 1370 } //end if 1371 continue; 1372 } //end if 1373 1374 newbrush = CopyBrush (brush); 1375 1376 // if the planenum is actualy a part of the brush 1377 // find the plane and flag it as used so it won't be tried 1378 // as a splitter again 1379 if (sides & PSIDE_FACING) 1380 { 1381 for (i=0 ; i<newbrush->numsides ; i++) 1382 { 1383 side = newbrush->sides + i; 1384 if ( (side->planenum& ~1) == node->planenum) 1385 side->texinfo = TEXINFO_NODE; 1386 } //end for 1387 } //end if 1388 if (sides & PSIDE_FRONT) 1389 { 1390 newbrush->next = *front; 1391 *front = newbrush; 1392 continue; 1393 } //end if 1394 if (sides & PSIDE_BACK) 1395 { 1396 newbrush->next = *back; 1397 *back = newbrush; 1398 continue; 1399 } //end if 1400 } //end for 1401 } //end of the function SplitBrushList 1402 //=========================================================================== 1403 // 1404 // Parameter: - 1405 // Returns: - 1406 // Changes Globals: - 1407 //=========================================================================== 1408 void CheckBrushLists(bspbrush_t *brushlist1, bspbrush_t *brushlist2) 1409 { 1410 bspbrush_t *brush1, *brush2; 1411 1412 for (brush1 = brushlist1; brush1; brush1 = brush1->next) 1413 { 1414 for (brush2 = brushlist2; brush2; brush2 = brush2->next) 1415 { 1416 assert(brush1 != brush2); 1417 } //end for 1418 } //end for 1419 } //end of the function CheckBrushLists 1420 //=========================================================================== 1421 // 1422 // Parameter: - 1423 // Returns: - 1424 // Changes Globals: - 1425 //=========================================================================== 1426 int numrecurse = 0; 1427 1428 node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) 1429 { 1430 node_t *newnode; 1431 side_t *bestside; 1432 int i, totalmem; 1433 bspbrush_t *children[2]; 1434 1435 qprintf("\r%6d", numrecurse); 1436 numrecurse++; 1437 1438 if (numthreads == 1) 1439 { 1440 totalmem = WindingMemory() + c_nodememory + c_brushmemory; 1441 if (totalmem > c_peak_totalbspmemory) 1442 c_peak_totalbspmemory = totalmem; 1443 c_nodes++; 1444 } //endif 1445 1446 if (drawflag) 1447 DrawBrushList(brushes, node); 1448 1449 // find the best plane to use as a splitter 1450 bestside = SelectSplitSide (brushes, node); 1451 if (!bestside) 1452 { 1453 // leaf node 1454 node->side = NULL; 1455 node->planenum = -1; 1456 LeafNode(node, brushes); 1457 if (node->contents & CONTENTS_SOLID) c_solidleafnodes++; 1458 if (create_aas) 1459 { 1460 //free up memory!!! 1461 FreeBrushList(node->brushlist); 1462 node->brushlist = NULL; 1463 //free the node volume brush 1464 if (node->volume) 1465 { 1466 FreeBrush(node->volume); 1467 node->volume = NULL; 1468 } //end if 1469 } //end if 1470 return node; 1471 } //end if 1472 1473 // this is a splitplane node 1474 node->side = bestside; 1475 node->planenum = bestside->planenum & ~1; // always use front facing 1476 1477 //split the brush list in two for both children 1478 SplitBrushList (brushes, node, &children[0], &children[1]); 1479 //free the old brush list 1480 FreeBrushList (brushes); 1481 1482 // allocate children before recursing 1483 for (i = 0; i < 2; i++) 1484 { 1485 newnode = AllocNode (); 1486 newnode->parent = node; 1487 node->children[i] = newnode; 1488 } //end for 1489 1490 //split the volume brush of the node for the children 1491 SplitBrush (node->volume, node->planenum, &node->children[0]->volume, 1492 &node->children[1]->volume); 1493 1494 if (create_aas) 1495 { 1496 //free the volume brush 1497 if (node->volume) 1498 { 1499 FreeBrush(node->volume); 1500 node->volume = NULL; 1501 } //end if 1502 } //end if 1503 // recursively process children 1504 for (i = 0; i < 2; i++) 1505 { 1506 node->children[i] = BuildTree_r(node->children[i], children[i]); 1507 } //end for 1508 1509 return node; 1510 } //end of the function BuildTree_r 1511 //=========================================================================== 1512 // 1513 // Parameter: - 1514 // Returns: - 1515 // Changes Globals: - 1516 //=========================================================================== 1517 node_t *firstnode; //first node in the list 1518 node_t *lastnode; //last node in the list 1519 int nodelistsize; //number of nodes in the list 1520 int use_nodequeue = 0; //use nodequeue, otherwise a node stack is used 1521 int numwaiting = 0; 1522 1523 void (*AddNodeToList)(node_t *node); 1524 1525 //add the node to the front of the node list 1526 //(effectively using a node stack) 1527 void AddNodeToStack(node_t *node) 1528 { 1529 ThreadLock(); 1530 1531 node->next = firstnode; 1532 firstnode = node; 1533 if (!lastnode) lastnode = node; 1534 nodelistsize++; 1535 1536 ThreadUnlock(); 1537 // 1538 ThreadSemaphoreIncrease(1); 1539 } //end of the function AddNodeToStack 1540 //add the node to the end of the node list 1541 //(effectively using a node queue) 1542 void AddNodeToQueue(node_t *node) 1543 { 1544 ThreadLock(); 1545 1546 node->next = NULL; 1547 if (lastnode) lastnode->next = node; 1548 else firstnode = node; 1549 lastnode = node; 1550 nodelistsize++; 1551 1552 ThreadUnlock(); 1553 // 1554 ThreadSemaphoreIncrease(1); 1555 } //end of the function AddNodeToQueue 1556 //get the first node from the front of the node list 1557 node_t *NextNodeFromList(void) 1558 { 1559 node_t *node; 1560 1561 ThreadLock(); 1562 numwaiting++; 1563 if (!firstnode) 1564 { 1565 if (numwaiting >= GetNumThreads()) ThreadSemaphoreIncrease(GetNumThreads()); 1566 } //end if 1567 ThreadUnlock(); 1568 1569 ThreadSemaphoreWait(); 1570 1571 ThreadLock(); 1572 1573 numwaiting--; 1574 1575 node = firstnode; 1576 if (firstnode) 1577 { 1578 firstnode = firstnode->next; 1579 nodelistsize--; 1580 } //end if 1581 if (!firstnode) lastnode = NULL; 1582 1583 ThreadUnlock(); 1584 1585 return node; 1586 } //end of the function NextNodeFromList 1587 //returns the size of the node list 1588 int NodeListSize(void) 1589 { 1590 int size; 1591 1592 ThreadLock(); 1593 size = nodelistsize; 1594 ThreadUnlock(); 1595 1596 return size; 1597 } //end of the function NodeListSize 1598 // 1599 void IncreaseNodeCounter(void) 1600 { 1601 ThreadLock(); 1602 //if (verbose) printf("\r%6d", numrecurse++); 1603 qprintf("\r%6d", numrecurse++); 1604 //qprintf("\r%6d %d, %5d ", numrecurse++, GetNumThreads(), nodelistsize); 1605 ThreadUnlock(); 1606 } //end of the function IncreaseNodeCounter 1607 //thread function, gets nodes from the nodelist and processes them 1608 void BuildTreeThread(int threadid) 1609 { 1610 node_t *newnode, *node; 1611 side_t *bestside; 1612 int i, totalmem; 1613 bspbrush_t *brushes; 1614 1615 for (node = NextNodeFromList(); node; ) 1616 { 1617 //if the nodelist isn't empty try to add another thread 1618 //if (NodeListSize() > 10) AddThread(BuildTreeThread); 1619 //display the number of nodes processed so far 1620 if (numthreads == 1) 1621 IncreaseNodeCounter(); 1622 1623 brushes = node->brushlist; 1624 1625 if (numthreads == 1) 1626 { 1627 totalmem = WindingMemory() + c_nodememory + c_brushmemory; 1628 if (totalmem > c_peak_totalbspmemory) 1629 { 1630 c_peak_totalbspmemory = totalmem; 1631 } //end if 1632 c_nodes++; 1633 } //endif 1634 1635 if (drawflag) 1636 { 1637 DrawBrushList(brushes, node); 1638 } //end if 1639 1640 if (cancelconversion) 1641 { 1642 bestside = NULL; 1643 } //end if 1644 else 1645 { 1646 // find the best plane to use as a splitter 1647 bestside = SelectSplitSide(brushes, node); 1648 } //end else 1649 //if there's no split side left 1650 if (!bestside) 1651 { 1652 //create a leaf out of the node 1653 LeafNode(node, brushes); 1654 if (node->contents & CONTENTS_SOLID) c_solidleafnodes++; 1655 if (create_aas) 1656 { 1657 //free up memory!!! 1658 FreeBrushList(node->brushlist); 1659 node->brushlist = NULL; 1660 } //end if 1661 //free the node volume brush (it is not used anymore) 1662 if (node->volume) 1663 { 1664 FreeBrush(node->volume); 1665 node->volume = NULL; 1666 } //end if 1667 node = NextNodeFromList(); 1668 continue; 1669 } //end if 1670 1671 // this is a splitplane node 1672 node->side = bestside; 1673 node->planenum = bestside->planenum & ~1; //always use front facing 1674 1675 //allocate children 1676 for (i = 0; i < 2; i++) 1677 { 1678 newnode = AllocNode(); 1679 newnode->parent = node; 1680 node->children[i] = newnode; 1681 } //end for 1682 1683 //split the brush list in two for both children 1684 SplitBrushList(brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist); 1685 1686 CheckBrushLists(node->children[0]->brushlist, node->children[1]->brushlist); 1687 //free the old brush list 1688 FreeBrushList(brushes); 1689 node->brushlist = NULL; 1690 1691 //split the volume brush of the node for the children 1692 SplitBrush(node->volume, node->planenum, &node->children[0]->volume, 1693 &node->children[1]->volume); 1694 1695 if (!node->children[0]->volume || !node->children[1]->volume) 1696 { 1697 Error("child without volume brush"); 1698 } //end if 1699 1700 //free the volume brush 1701 if (node->volume) 1702 { 1703 FreeBrush(node->volume); 1704 node->volume = NULL; 1705 } //end if 1706 //add both children to the node list 1707 //AddNodeToList(node->children[0]); 1708 AddNodeToList(node->children[1]); 1709 node = node->children[0]; 1710 } //end while 1711 RemoveThread(threadid); 1712 } //end of the function BuildTreeThread 1713 //=========================================================================== 1714 // build the bsp tree using a node list 1715 // 1716 // Parameter: - 1717 // Returns: - 1718 // Changes Globals: - 1719 //=========================================================================== 1720 void BuildTree(tree_t *tree) 1721 { 1722 int i; 1723 1724 firstnode = NULL; 1725 lastnode = NULL; 1726 //use a node queue or node stack 1727 if (use_nodequeue) AddNodeToList = AddNodeToQueue; 1728 else AddNodeToList = AddNodeToStack; 1729 //setup thread locking 1730 ThreadSetupLock(); 1731 ThreadSetupSemaphore(); 1732 numwaiting = 0; 1733 // 1734 Log_Print("%6d threads max\n", numthreads); 1735 if (use_nodequeue) Log_Print("breadth first bsp building\n"); 1736 else Log_Print("depth first bsp building\n"); 1737 qprintf("%6d splits", 0); 1738 //add the first node to the list 1739 AddNodeToList(tree->headnode); 1740 //start the threads 1741 for (i = 0; i < numthreads; i++) 1742 AddThread(BuildTreeThread); 1743 //wait for all added threads to be finished 1744 WaitForAllThreadsFinished(); 1745 //shutdown the thread locking 1746 ThreadShutdownLock(); 1747 ThreadShutdownSemaphore(); 1748 } //end of the function BuildTree 1749 //=========================================================================== 1750 // The incoming brush list will be freed before exiting 1751 // 1752 // Parameter: - 1753 // Returns: - 1754 // Changes Globals: - 1755 //=========================================================================== 1756 tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs) 1757 { 1758 int i, c_faces, c_nonvisfaces, c_brushes; 1759 bspbrush_t *b; 1760 node_t *node; 1761 tree_t *tree; 1762 vec_t volume; 1763 // vec3_t point; 1764 1765 Log_Print("-------- Brush BSP ---------\n"); 1766 1767 tree = Tree_Alloc(); 1768 1769 c_faces = 0; 1770 c_nonvisfaces = 0; 1771 c_brushes = 0; 1772 c_totalsides = 0; 1773 for (b = brushlist; b; b = b->next) 1774 { 1775 c_brushes++; 1776 1777 volume = BrushVolume(b); 1778 if (volume < microvolume) 1779 { 1780 Log_Print("WARNING: entity %i, brush %i: microbrush\n", 1781 b->original->entitynum, b->original->brushnum); 1782 } //end if 1783 1784 for (i=0 ; i<b->numsides ; i++) 1785 { 1786 if (b->sides[i].flags & SFL_BEVEL) 1787 continue; 1788 if (!b->sides[i].winding) 1789 continue; 1790 if (b->sides[i].texinfo == TEXINFO_NODE) 1791 continue; 1792 if (b->sides[i].flags & SFL_VISIBLE) 1793 { 1794 c_faces++; 1795 } //end if 1796 else 1797 { 1798 c_nonvisfaces++; 1799 //if (create_aas) b->sides[i].texinfo = TEXINFO_NODE; 1800 } //end if 1801 } //end for 1802 c_totalsides += b->numsides; 1803 1804 AddPointToBounds (b->mins, tree->mins, tree->maxs); 1805 AddPointToBounds (b->maxs, tree->mins, tree->maxs); 1806 } //end for 1807 1808 Log_Print("%6i brushes\n", c_brushes); 1809 Log_Print("%6i visible faces\n", c_faces); 1810 Log_Print("%6i nonvisible faces\n", c_nonvisfaces); 1811 Log_Print("%6i total sides\n", c_totalsides); 1812 1813 c_active_brushes = c_brushes; 1814 c_nodememory = 0; 1815 c_brushmemory = 0; 1816 c_peak_brushmemory = 0; 1817 1818 c_nodes = 0; 1819 c_nonvis = 0; 1820 node = AllocNode (); 1821 1822 //volume of first node (head node) 1823 node->volume = BrushFromBounds (mins, maxs); 1824 // 1825 tree->headnode = node; 1826 //just get some statistics and the mins/maxs of the node 1827 numrecurse = 0; 1828 // qprintf("%6d splits", numrecurse); 1829 1830 tree->headnode->brushlist = brushlist; 1831 BuildTree(tree); 1832 1833 //build the bsp tree with the start node from the brushlist 1834 // node = BuildTree_r(node, brushlist); 1835 1836 //if the conversion is cancelled 1837 if (cancelconversion) return tree; 1838 1839 qprintf("\n"); 1840 Log_Write("%6d splits\r\n", numrecurse); 1841 // Log_Print("%6i visible nodes\n", c_nodes/2 - c_nonvis); 1842 // Log_Print("%6i nonvis nodes\n", c_nonvis); 1843 // Log_Print("%6i leaves\n", (c_nodes+1)/2); 1844 // Log_Print("%6i solid leaf nodes\n", c_solidleafnodes); 1845 // Log_Print("%6i active brushes\n", c_active_brushes); 1846 if (numthreads == 1) 1847 { 1848 // Log_Print("%6i KB of node memory\n", c_nodememory >> 10); 1849 // Log_Print("%6i KB of brush memory\n", c_brushmemory >> 10); 1850 // Log_Print("%6i KB of peak brush memory\n", c_peak_brushmemory >> 10); 1851 // Log_Print("%6i KB of winding memory\n", WindingMemory() >> 10); 1852 // Log_Print("%6i KB of peak winding memory\n", WindingPeakMemory() >> 10); 1853 Log_Print("%6i KB of peak total bsp memory\n", c_peak_totalbspmemory >> 10); 1854 } //end if 1855 1856 /* 1857 point[0] = 1485; 1858 point[1] = 956.125; 1859 point[2] = 352.125; 1860 node = PointInLeaf(tree->headnode, point); 1861 if (node->planenum != PLANENUM_LEAF) 1862 { 1863 Log_Print("node not a leaf\n"); 1864 } //end if 1865 Log_Print("at %f %f %f:\n", point[0], point[1], point[2]); 1866 PrintContents(node->contents); 1867 Log_Print("node->expansionbboxes = %d\n", node->expansionbboxes); 1868 //*/ 1869 return tree; 1870 } //end of the function BrushBSP 1871