brush.c (15683B)
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 #include "qbsp.h" 23 24 25 int c_active_brushes; 26 27 int c_nodes; 28 29 // if a brush just barely pokes onto the other side, 30 // let it slide by without chopping 31 #define PLANESIDE_EPSILON 0.001 32 //0.1 33 34 35 36 37 /* 38 ================ 39 CountBrushList 40 ================ 41 */ 42 int CountBrushList (bspbrush_t *brushes) 43 { 44 int c; 45 46 c = 0; 47 for ( ; brushes ; brushes = brushes->next) 48 c++; 49 return c; 50 } 51 52 53 /* 54 ================ 55 AllocBrush 56 ================ 57 */ 58 bspbrush_t *AllocBrush (int numsides) 59 { 60 bspbrush_t *bb; 61 int c; 62 63 c = (int)&(((bspbrush_t *)0)->sides[numsides]); 64 bb = malloc(c); 65 memset (bb, 0, c); 66 if (numthreads == 1) 67 c_active_brushes++; 68 return bb; 69 } 70 71 /* 72 ================ 73 FreeBrush 74 ================ 75 */ 76 void FreeBrush (bspbrush_t *brushes) 77 { 78 int i; 79 80 for (i=0 ; i<brushes->numsides ; i++) 81 if (brushes->sides[i].winding) 82 FreeWinding(brushes->sides[i].winding); 83 free (brushes); 84 if (numthreads == 1) 85 c_active_brushes--; 86 } 87 88 89 /* 90 ================ 91 FreeBrushList 92 ================ 93 */ 94 void FreeBrushList (bspbrush_t *brushes) 95 { 96 bspbrush_t *next; 97 98 for ( ; brushes ; brushes = next) 99 { 100 next = brushes->next; 101 102 FreeBrush (brushes); 103 } 104 } 105 106 /* 107 ================== 108 CopyBrush 109 110 Duplicates the brush, the sides, and the windings 111 ================== 112 */ 113 bspbrush_t *CopyBrush (bspbrush_t *brush) 114 { 115 bspbrush_t *newbrush; 116 int size; 117 int i; 118 119 size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); 120 121 newbrush = AllocBrush (brush->numsides); 122 memcpy (newbrush, brush, size); 123 124 for (i=0 ; i<brush->numsides ; i++) 125 { 126 if (brush->sides[i].winding) 127 newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); 128 } 129 130 return newbrush; 131 } 132 133 134 /* 135 ================ 136 DrawBrushList 137 ================ 138 */ 139 void DrawBrushList (bspbrush_t *brush) 140 { 141 int i; 142 side_t *s; 143 144 GLS_BeginScene (); 145 for ( ; brush ; brush=brush->next) 146 { 147 for (i=0 ; i<brush->numsides ; i++) 148 { 149 s = &brush->sides[i]; 150 if (!s->winding) 151 continue; 152 GLS_Winding (s->winding, 0); 153 } 154 } 155 GLS_EndScene (); 156 } 157 158 159 160 /* 161 ================ 162 WriteBrushList 163 ================ 164 */ 165 void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis) 166 { 167 int i; 168 side_t *s; 169 FILE *f; 170 171 qprintf ("writing %s\n", name); 172 f = SafeOpenWrite (name); 173 174 for ( ; brush ; brush=brush->next) 175 { 176 for (i=0 ; i<brush->numsides ; i++) 177 { 178 s = &brush->sides[i]; 179 if (!s->winding) 180 continue; 181 if (onlyvis && !s->visible) 182 continue; 183 OutputWinding (brush->sides[i].winding, f); 184 } 185 } 186 187 fclose (f); 188 } 189 190 191 /* 192 ============= 193 PrintBrush 194 ============= 195 */ 196 void PrintBrush (bspbrush_t *brush) 197 { 198 int i; 199 200 _printf ("brush: %p\n", brush); 201 for (i=0;i<brush->numsides ; i++) 202 { 203 pw(brush->sides[i].winding); 204 _printf ("\n"); 205 } 206 } 207 208 /* 209 ================== 210 BoundBrush 211 212 Sets the mins/maxs based on the windings 213 returns false if the brush doesn't enclose a valid volume 214 ================== 215 */ 216 qboolean BoundBrush (bspbrush_t *brush) 217 { 218 int i, j; 219 winding_t *w; 220 221 ClearBounds (brush->mins, brush->maxs); 222 for (i=0 ; i<brush->numsides ; i++) 223 { 224 w = brush->sides[i].winding; 225 if (!w) 226 continue; 227 for (j=0 ; j<w->numpoints ; j++) 228 AddPointToBounds (w->p[j], brush->mins, brush->maxs); 229 } 230 231 for (i=0 ; i<3 ; i++) { 232 if (brush->mins[i] < MIN_WORLD_COORD || brush->maxs[i] > MAX_WORLD_COORD 233 || brush->mins[i] >= brush->maxs[i] ) { 234 return qfalse; 235 } 236 } 237 238 return qtrue; 239 } 240 241 /* 242 ================== 243 CreateBrushWindings 244 245 makes basewindigs for sides and mins / maxs for the brush 246 returns false if the brush doesn't enclose a valid volume 247 ================== 248 */ 249 qboolean CreateBrushWindings (bspbrush_t *brush) 250 { 251 int i, j; 252 winding_t *w; 253 side_t *side; 254 plane_t *plane; 255 256 for ( i = 0; i < brush->numsides; i++ ) 257 { 258 side = &brush->sides[i]; 259 // don't create a winding for a bevel 260 if ( side->bevel ) { 261 continue; 262 } 263 plane = &mapplanes[side->planenum]; 264 w = BaseWindingForPlane (plane->normal, plane->dist); 265 for ( j = 0; j < brush->numsides && w; j++ ) 266 { 267 if (i == j) 268 continue; 269 if ( brush->sides[j].planenum == ( brush->sides[i].planenum ^ 1 ) ) 270 continue; // back side clipaway 271 if (brush->sides[j].bevel) 272 continue; 273 if (brush->sides[j].backSide) 274 continue; 275 plane = &mapplanes[brush->sides[j].planenum^1]; 276 ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); 277 } 278 // free any existing winding 279 if ( side->winding ) { 280 FreeWinding( side->winding ); 281 } 282 side->winding = w; 283 } 284 285 return BoundBrush (brush); 286 } 287 288 /* 289 ================== 290 BrushFromBounds 291 292 Creates a new axial brush 293 ================== 294 */ 295 bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) 296 { 297 bspbrush_t *b; 298 int i; 299 vec3_t normal; 300 vec_t dist; 301 302 b = AllocBrush (6); 303 b->numsides = 6; 304 for (i=0 ; i<3 ; i++) 305 { 306 VectorClear (normal); 307 normal[i] = 1; 308 dist = maxs[i]; 309 b->sides[i].planenum = FindFloatPlane (normal, dist); 310 311 normal[i] = -1; 312 dist = -mins[i]; 313 b->sides[3+i].planenum = FindFloatPlane (normal, dist); 314 } 315 316 CreateBrushWindings (b); 317 318 return b; 319 } 320 321 /* 322 ================== 323 BrushVolume 324 325 ================== 326 */ 327 vec_t BrushVolume (bspbrush_t *brush) 328 { 329 int i; 330 winding_t *w; 331 vec3_t corner; 332 vec_t d, area, volume; 333 plane_t *plane; 334 335 if (!brush) 336 return 0; 337 338 // grab the first valid point as the corner 339 340 w = NULL; 341 for (i=0 ; i<brush->numsides ; i++) 342 { 343 w = brush->sides[i].winding; 344 if (w) 345 break; 346 } 347 if (!w) 348 return 0; 349 VectorCopy (w->p[0], corner); 350 351 // make tetrahedrons to all other faces 352 353 volume = 0; 354 for ( ; i<brush->numsides ; i++) 355 { 356 w = brush->sides[i].winding; 357 if (!w) 358 continue; 359 plane = &mapplanes[brush->sides[i].planenum]; 360 d = -(DotProduct (corner, plane->normal) - plane->dist); 361 area = WindingArea (w); 362 volume += d*area; 363 } 364 365 volume /= 3; 366 return volume; 367 } 368 369 370 /* 371 ================== 372 WriteBspBrushMap 373 ================== 374 */ 375 void WriteBspBrushMap (char *name, bspbrush_t *list) 376 { 377 FILE *f; 378 side_t *s; 379 int i; 380 winding_t *w; 381 382 _printf ("writing %s\n", name); 383 f = fopen (name, "wb"); 384 if (!f) 385 Error ("Can't write %s\b", name); 386 387 fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); 388 389 for ( ; list ; list=list->next ) 390 { 391 fprintf (f, "{\n"); 392 for (i=0,s=list->sides ; i<list->numsides ; i++,s++) 393 { 394 w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); 395 396 fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); 397 fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); 398 fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); 399 400 fprintf (f, "notexture 0 0 0 1 1\n" ); 401 FreeWinding (w); 402 } 403 fprintf (f, "}\n"); 404 } 405 fprintf (f, "}\n"); 406 407 fclose (f); 408 409 } 410 411 412 //===================================================================================== 413 414 /* 415 ==================== 416 FilterBrushIntoTree_r 417 418 ==================== 419 */ 420 int FilterBrushIntoTree_r( bspbrush_t *b, node_t *node ) { 421 bspbrush_t *front, *back; 422 int c; 423 424 if ( !b ) { 425 return 0; 426 } 427 428 // add it to the leaf list 429 if ( node->planenum == PLANENUM_LEAF ) { 430 b->next = node->brushlist; 431 node->brushlist = b; 432 433 // classify the leaf by the structural brush 434 if ( !b->detail ) { 435 if ( b->opaque ) { 436 node->opaque = qtrue; 437 node->areaportal = qfalse; 438 } else if ( b->contents & CONTENTS_AREAPORTAL ) { 439 if ( !node->opaque ) { 440 node->areaportal = qtrue; 441 } 442 } 443 } 444 445 return 1; 446 } 447 448 // split it by the node plane 449 SplitBrush ( b, node->planenum, &front, &back ); 450 FreeBrush( b ); 451 452 c = 0; 453 c += FilterBrushIntoTree_r( front, node->children[0] ); 454 c += FilterBrushIntoTree_r( back, node->children[1] ); 455 456 return c; 457 } 458 459 /* 460 ===================== 461 FilterDetailBrushesIntoTree 462 463 Fragment all the detail brushes into the structural leafs 464 ===================== 465 */ 466 void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree ) { 467 bspbrush_t *b, *newb; 468 int r; 469 int c_unique, c_clusters; 470 int i; 471 472 qprintf( "----- FilterDetailBrushesIntoTree -----\n"); 473 474 c_unique = 0; 475 c_clusters = 0; 476 for ( b = e->brushes ; b ; b = b->next ) { 477 if ( !b->detail ) { 478 continue; 479 } 480 c_unique++; 481 newb = CopyBrush( b ); 482 r = FilterBrushIntoTree_r( newb, tree->headnode ); 483 c_clusters += r; 484 485 // mark all sides as visible so drawsurfs are created 486 if ( r ) { 487 for ( i = 0 ; i < b->numsides ; i++ ) { 488 if ( b->sides[i].winding ) { 489 b->sides[i].visible = qtrue; 490 } 491 } 492 } 493 } 494 495 qprintf( "%5i detail brushes\n", c_unique ); 496 qprintf( "%5i cluster references\n", c_clusters ); 497 } 498 499 /* 500 ===================== 501 FilterStructuralBrushesIntoTree 502 503 Mark the leafs as opaque and areaportals 504 ===================== 505 */ 506 void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree ) { 507 bspbrush_t *b, *newb; 508 int r; 509 int c_unique, c_clusters; 510 int i; 511 512 qprintf( "----- FilterStructuralBrushesIntoTree -----\n"); 513 514 c_unique = 0; 515 c_clusters = 0; 516 for ( b = e->brushes ; b ; b = b->next ) { 517 if ( b->detail ) { 518 continue; 519 } 520 c_unique++; 521 newb = CopyBrush( b ); 522 r = FilterBrushIntoTree_r( newb, tree->headnode ); 523 c_clusters += r; 524 525 // mark all sides as visible so drawsurfs are created 526 if ( r ) { 527 for ( i = 0 ; i < b->numsides ; i++ ) { 528 if ( b->sides[i].winding ) { 529 b->sides[i].visible = qtrue; 530 } 531 } 532 } 533 } 534 535 qprintf( "%5i structural brushes\n", c_unique ); 536 qprintf( "%5i cluster references\n", c_clusters ); 537 } 538 539 540 541 /* 542 ================ 543 AllocTree 544 ================ 545 */ 546 tree_t *AllocTree (void) 547 { 548 tree_t *tree; 549 550 tree = malloc(sizeof(*tree)); 551 memset (tree, 0, sizeof(*tree)); 552 ClearBounds (tree->mins, tree->maxs); 553 554 return tree; 555 } 556 557 /* 558 ================ 559 AllocNode 560 ================ 561 */ 562 node_t *AllocNode (void) 563 { 564 node_t *node; 565 566 node = malloc(sizeof(*node)); 567 memset (node, 0, sizeof(*node)); 568 569 return node; 570 } 571 572 573 /* 574 ================ 575 WindingIsTiny 576 577 Returns true if the winding would be crunched out of 578 existance by the vertex snapping. 579 ================ 580 */ 581 #define EDGE_LENGTH 0.2 582 qboolean WindingIsTiny (winding_t *w) 583 { 584 /* 585 if (WindingArea (w) < 1) 586 return qtrue; 587 return qfalse; 588 */ 589 int i, j; 590 vec_t len; 591 vec3_t delta; 592 int edges; 593 594 edges = 0; 595 for (i=0 ; i<w->numpoints ; i++) 596 { 597 j = i == w->numpoints - 1 ? 0 : i+1; 598 VectorSubtract (w->p[j], w->p[i], delta); 599 len = VectorLength (delta); 600 if (len > EDGE_LENGTH) 601 { 602 if (++edges == 3) 603 return qfalse; 604 } 605 } 606 return qtrue; 607 } 608 609 /* 610 ================ 611 WindingIsHuge 612 613 Returns true if the winding still has one of the points 614 from basewinding for plane 615 ================ 616 */ 617 qboolean WindingIsHuge (winding_t *w) 618 { 619 int i, j; 620 621 for (i=0 ; i<w->numpoints ; i++) 622 { 623 for (j=0 ; j<3 ; j++) 624 if (w->p[i][j] <= MIN_WORLD_COORD || w->p[i][j] >= MAX_WORLD_COORD) 625 return qtrue; 626 } 627 return qfalse; 628 } 629 630 //============================================================ 631 632 /* 633 ================== 634 BrushMostlyOnSide 635 636 ================== 637 */ 638 int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane) 639 { 640 int i, j; 641 winding_t *w; 642 vec_t d, max; 643 int side; 644 645 max = 0; 646 side = PSIDE_FRONT; 647 for (i=0 ; i<brush->numsides ; i++) 648 { 649 w = brush->sides[i].winding; 650 if (!w) 651 continue; 652 for (j=0 ; j<w->numpoints ; j++) 653 { 654 d = DotProduct (w->p[j], plane->normal) - plane->dist; 655 if (d > max) 656 { 657 max = d; 658 side = PSIDE_FRONT; 659 } 660 if (-d > max) 661 { 662 max = -d; 663 side = PSIDE_BACK; 664 } 665 } 666 } 667 return side; 668 } 669 670 /* 671 ================ 672 SplitBrush 673 674 Generates two new brushes, leaving the original 675 unchanged 676 ================ 677 */ 678 void SplitBrush (bspbrush_t *brush, int planenum, 679 bspbrush_t **front, bspbrush_t **back) 680 { 681 bspbrush_t *b[2]; 682 int i, j; 683 winding_t *w, *cw[2], *midwinding; 684 plane_t *plane, *plane2; 685 side_t *s, *cs; 686 float d, d_front, d_back; 687 688 *front = *back = NULL; 689 plane = &mapplanes[planenum]; 690 691 // check all points 692 d_front = d_back = 0; 693 for (i=0 ; i<brush->numsides ; i++) 694 { 695 w = brush->sides[i].winding; 696 if (!w) 697 continue; 698 for (j=0 ; j<w->numpoints ; j++) 699 { 700 d = DotProduct (w->p[j], plane->normal) - plane->dist; 701 if (d > 0 && d > d_front) 702 d_front = d; 703 if (d < 0 && d < d_back) 704 d_back = d; 705 } 706 } 707 if (d_front < 0.1) // PLANESIDE_EPSILON) 708 { // only on back 709 *back = CopyBrush (brush); 710 return; 711 } 712 if (d_back > -0.1) // PLANESIDE_EPSILON) 713 { // only on front 714 *front = CopyBrush (brush); 715 return; 716 } 717 718 // create a new winding from the split plane 719 720 w = BaseWindingForPlane (plane->normal, plane->dist); 721 for (i=0 ; i<brush->numsides && w ; i++) 722 { 723 if ( brush->sides[i].backSide ) { 724 continue; // fake back-sided polygons never split 725 } 726 plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; 727 ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); 728 } 729 730 if (!w || WindingIsTiny (w) ) 731 { // the brush isn't really split 732 int side; 733 734 side = BrushMostlyOnSide (brush, plane); 735 if (side == PSIDE_FRONT) 736 *front = CopyBrush (brush); 737 if (side == PSIDE_BACK) 738 *back = CopyBrush (brush); 739 return; 740 } 741 742 if (WindingIsHuge (w)) 743 { 744 qprintf ("WARNING: huge winding\n"); 745 } 746 747 midwinding = w; 748 749 // split it for real 750 751 for (i=0 ; i<2 ; i++) 752 { 753 b[i] = AllocBrush (brush->numsides+1); 754 memcpy( b[i], brush, sizeof( bspbrush_t ) - sizeof( brush->sides ) ); 755 b[i]->numsides = 0; 756 b[i]->next = NULL; 757 b[i]->original = brush->original; 758 } 759 760 // split all the current windings 761 762 for (i=0 ; i<brush->numsides ; i++) 763 { 764 s = &brush->sides[i]; 765 w = s->winding; 766 if (!w) 767 continue; 768 ClipWindingEpsilon (w, plane->normal, plane->dist, 769 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); 770 for (j=0 ; j<2 ; j++) 771 { 772 if (!cw[j]) 773 continue; 774 /* 775 if (WindingIsTiny (cw[j])) 776 { 777 FreeWinding (cw[j]); 778 continue; 779 } 780 */ 781 cs = &b[j]->sides[b[j]->numsides]; 782 b[j]->numsides++; 783 *cs = *s; 784 cs->winding = cw[j]; 785 } 786 } 787 788 789 // see if we have valid polygons on both sides 790 791 for (i=0 ; i<2 ; i++) 792 { 793 BoundBrush (b[i]); 794 for (j=0 ; j<3 ; j++) 795 { 796 if (b[i]->mins[j] < MIN_WORLD_COORD || b[i]->maxs[j] > MAX_WORLD_COORD) 797 { 798 qprintf ("bogus brush after clip\n"); 799 break; 800 } 801 } 802 803 if (b[i]->numsides < 3 || j < 3) 804 { 805 FreeBrush (b[i]); 806 b[i] = NULL; 807 } 808 } 809 810 if ( !(b[0] && b[1]) ) 811 { 812 if (!b[0] && !b[1]) 813 qprintf ("split removed brush\n"); 814 else 815 qprintf ("split not on both sides\n"); 816 if (b[0]) 817 { 818 FreeBrush (b[0]); 819 *front = CopyBrush (brush); 820 } 821 if (b[1]) 822 { 823 FreeBrush (b[1]); 824 *back = CopyBrush (brush); 825 } 826 return; 827 } 828 829 // add the midwinding to both sides 830 for (i=0 ; i<2 ; i++) 831 { 832 cs = &b[i]->sides[b[i]->numsides]; 833 b[i]->numsides++; 834 835 cs->planenum = planenum^i^1; 836 cs->shaderInfo = NULL; 837 if (i==0) 838 cs->winding = CopyWinding (midwinding); 839 else 840 cs->winding = midwinding; 841 } 842 843 { 844 vec_t v1; 845 int i; 846 847 for (i=0 ; i<2 ; i++) 848 { 849 v1 = BrushVolume (b[i]); 850 if (v1 < 1.0) 851 { 852 FreeBrush (b[i]); 853 b[i] = NULL; 854 // qprintf ("tiny volume after clip\n"); 855 } 856 } 857 } 858 859 *front = b[0]; 860 *back = b[1]; 861 }