csg.c (25901B)
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 25 /* 26 27 tag all brushes with original contents 28 brushes may contain multiple contents 29 there will be no brush overlap after csg phase 30 31 */ 32 33 int minplanenums[3]; 34 int maxplanenums[3]; 35 36 //=========================================================================== 37 // 38 // Parameter: - 39 // Returns: - 40 // Changes Globals: - 41 //=========================================================================== 42 void CheckBSPBrush(bspbrush_t *brush) 43 { 44 int i, j; 45 plane_t *plane1, *plane2; 46 47 //check if the brush is convex... flipped planes make a brush non-convex 48 for (i = 0; i < brush->numsides; i++) 49 { 50 for (j = 0; j < brush->numsides; j++) 51 { 52 if (i == j) continue; 53 plane1 = &mapplanes[brush->sides[i].planenum]; 54 plane2 = &mapplanes[brush->sides[j].planenum]; 55 // 56 if (WindingsNonConvex(brush->sides[i].winding, 57 brush->sides[j].winding, 58 plane1->normal, plane2->normal, 59 plane1->dist, plane2->dist)) 60 { 61 Log_Print("non convex brush"); 62 break; 63 } //end if 64 } //end for 65 } //end for 66 BoundBrush(brush); 67 //check for out of bound brushes 68 for (i = 0; i < 3; i++) 69 { 70 if (brush->mins[i] < -MAX_MAP_BOUNDS || brush->maxs[i] > MAX_MAP_BOUNDS) 71 { 72 Log_Print("brush: bounds out of range\n"); 73 Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]); 74 break; 75 } //end if 76 if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS) 77 { 78 Log_Print("brush: no visible sides on brush\n"); 79 Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]); 80 break; 81 } //end if 82 } //end for 83 } //end of the function CheckBSPBrush 84 //=========================================================================== 85 // 86 // Parameter: - 87 // Returns: - 88 // Changes Globals: - 89 //=========================================================================== 90 void BSPBrushWindings(bspbrush_t *brush) 91 { 92 int i, j; 93 winding_t *w; 94 plane_t *plane; 95 96 for (i = 0; i < brush->numsides; i++) 97 { 98 plane = &mapplanes[brush->sides[i].planenum]; 99 w = BaseWindingForPlane(plane->normal, plane->dist); 100 for (j = 0; j < brush->numsides && w; j++) 101 { 102 if (i == j) continue; 103 plane = &mapplanes[brush->sides[j].planenum^1]; 104 ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); 105 } //end for 106 brush->sides[i].winding = w; 107 } //end for 108 } //end of the function BSPBrushWindings 109 //=========================================================================== 110 // NOTE: can't keep brush->original intact 111 // 112 // Parameter: - 113 // Returns: - 114 // Changes Globals: - 115 //=========================================================================== 116 bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2) 117 { 118 int i, j, k, n, shared; 119 side_t *side1, *side2, *cs; 120 plane_t *plane1, *plane2; 121 bspbrush_t *newbrush; 122 123 //check for bounding box overlapp 124 for (i = 0; i < 3; i++) 125 { 126 if (brush1->mins[i] > brush2->maxs[i] + 2 127 || brush1->maxs[i] < brush2->mins[i] - 2) 128 { 129 return NULL; 130 } //end if 131 } //end for 132 // 133 shared = 0; 134 //check if the brush is convex... flipped planes make a brush non-convex 135 for (i = 0; i < brush1->numsides; i++) 136 { 137 side1 = &brush1->sides[i]; 138 //don't check the "shared" sides 139 for (k = 0; k < brush2->numsides; k++) 140 { 141 side2 = &brush2->sides[k]; 142 if (side1->planenum == (side2->planenum^1)) 143 { 144 shared++; 145 //there may only be ONE shared side 146 if (shared > 1) return NULL; 147 break; 148 } //end if 149 } //end for 150 if (k < brush2->numsides) continue; 151 // 152 for (j = 0; j < brush2->numsides; j++) 153 { 154 side2 = &brush2->sides[j]; 155 //don't check the "shared" sides 156 for (n = 0; n < brush1->numsides; n++) 157 { 158 side1 = &brush1->sides[n]; 159 if (side1->planenum == (side2->planenum^1)) break; 160 } //end for 161 if (n < brush1->numsides) continue; 162 // 163 side1 = &brush1->sides[i]; 164 //if the side is in the same plane 165 //* 166 if (side1->planenum == side2->planenum) 167 { 168 if (side1->texinfo != TEXINFO_NODE && 169 side2->texinfo != TEXINFO_NODE && 170 side1->texinfo != side2->texinfo) return NULL; 171 continue; 172 } //end if 173 // 174 plane1 = &mapplanes[side1->planenum]; 175 plane2 = &mapplanes[side2->planenum]; 176 // 177 if (WindingsNonConvex(side1->winding, side2->winding, 178 plane1->normal, plane2->normal, 179 plane1->dist, plane2->dist)) 180 { 181 return NULL; 182 } //end if 183 } //end for 184 } //end for 185 newbrush = AllocBrush(brush1->numsides + brush2->numsides); 186 newbrush->original = brush1->original; 187 newbrush->numsides = 0; 188 //newbrush->side = brush1->side; //brush contents 189 //fix texinfos for sides lying in the same plane 190 for (i = 0; i < brush1->numsides; i++) 191 { 192 side1 = &brush1->sides[i]; 193 // 194 for (n = 0; n < brush2->numsides; n++) 195 { 196 side2 = &brush2->sides[n]; 197 //if both sides are in the same plane get the texinfo right 198 if (side1->planenum == side2->planenum) 199 { 200 if (side1->texinfo == TEXINFO_NODE) side1->texinfo = side2->texinfo; 201 if (side2->texinfo == TEXINFO_NODE) side2->texinfo = side1->texinfo; 202 } //end if 203 } //end for 204 } //end for 205 // 206 for (i = 0; i < brush1->numsides; i++) 207 { 208 side1 = &brush1->sides[i]; 209 //don't add the "shared" sides 210 for (n = 0; n < brush2->numsides; n++) 211 { 212 side2 = &brush2->sides[n]; 213 if (side1->planenum == (side2->planenum ^ 1)) break; 214 } //end for 215 if (n < brush2->numsides) continue; 216 // 217 for (n = 0; n < newbrush->numsides; n++) 218 { 219 cs = &newbrush->sides[n]; 220 if (cs->planenum == side1->planenum) 221 { 222 Log_Print("brush duplicate plane\n"); 223 break; 224 } //end if 225 } //end if 226 if (n < newbrush->numsides) continue; 227 //add this side 228 cs = &newbrush->sides[newbrush->numsides]; 229 newbrush->numsides++; 230 *cs = *side1; 231 } //end for 232 for (j = 0; j < brush2->numsides; j++) 233 { 234 side2 = &brush2->sides[j]; 235 for (n = 0; n < brush1->numsides; n++) 236 { 237 side1 = &brush1->sides[n]; 238 //if the side is in the same plane 239 if (side2->planenum == side1->planenum) break; 240 //don't add the "shared" sides 241 if (side2->planenum == (side1->planenum ^ 1)) break; 242 } //end for 243 if (n < brush1->numsides) continue; 244 // 245 for (n = 0; n < newbrush->numsides; n++) 246 { 247 cs = &newbrush->sides[n]; 248 if (cs->planenum == side2->planenum) 249 { 250 Log_Print("brush duplicate plane\n"); 251 break; 252 } //end if 253 } //end if 254 if (n < newbrush->numsides) continue; 255 //add this side 256 cs = &newbrush->sides[newbrush->numsides]; 257 newbrush->numsides++; 258 *cs = *side2; 259 } //end for 260 BSPBrushWindings(newbrush); 261 BoundBrush(newbrush); 262 CheckBSPBrush(newbrush); 263 return newbrush; 264 } //end of the function TryMergeBrushes 265 //=========================================================================== 266 // 267 // Parameter: - 268 // Returns: - 269 // Changes Globals: - 270 //=========================================================================== 271 bspbrush_t *MergeBrushes(bspbrush_t *brushlist) 272 { 273 int nummerges, merged; 274 bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist; 275 bspbrush_t *lastb2; 276 277 if (!brushlist) return NULL; 278 279 qprintf("%5d brushes merged", nummerges = 0); 280 do 281 { 282 for (tail = brushlist; tail; tail = tail->next) 283 { 284 if (!tail->next) break; 285 } //end for 286 merged = 0; 287 newbrushlist = NULL; 288 for (b1 = brushlist; b1; b1 = brushlist) 289 { 290 lastb2 = b1; 291 for (b2 = b1->next; b2; b2 = b2->next) 292 { 293 //if the brushes don't have the same contents 294 if (b1->original->contents != b2->original->contents || 295 b1->original->expansionbbox != b2->original->expansionbbox) newbrush = NULL; 296 else newbrush = TryMergeBrushes(b1, b2); 297 if (newbrush) 298 { 299 tail->next = newbrush; 300 lastb2->next = b2->next; 301 brushlist = brushlist->next; 302 FreeBrush(b1); 303 FreeBrush(b2); 304 for (tail = brushlist; tail; tail = tail->next) 305 { 306 if (!tail->next) break; 307 } //end for 308 merged++; 309 qprintf("\r%5d", nummerges++); 310 break; 311 } //end if 312 lastb2 = b2; 313 } //end for 314 //if b1 can't be merged with any of the other brushes 315 if (!b2) 316 { 317 brushlist = brushlist->next; 318 //keep b1 319 b1->next = newbrushlist; 320 newbrushlist = b1; 321 } //end else 322 } //end for 323 brushlist = newbrushlist; 324 } while(merged); 325 qprintf("\n"); 326 return newbrushlist; 327 } //end of the function MergeBrushes 328 //=========================================================================== 329 // 330 // Parameter: - 331 // Returns: - 332 // Changes Globals: - 333 //=========================================================================== 334 void SplitBrush2 (bspbrush_t *brush, int planenum, 335 bspbrush_t **front, bspbrush_t **back) 336 { 337 SplitBrush (brush, planenum, front, back); 338 #if 0 339 if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1) 340 (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1 341 if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1) 342 (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1 343 #endif 344 } //end of the function SplitBrush2 345 //=========================================================================== 346 // Returns a list of brushes that remain after B is subtracted from A. 347 // May by empty if A is contained inside B. 348 // The originals are undisturbed. 349 // 350 // Parameter: - 351 // Returns: - 352 // Changes Globals: - 353 //=========================================================================== 354 bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b) 355 { // a - b = out (list) 356 int i; 357 bspbrush_t *front, *back; 358 bspbrush_t *out, *in; 359 360 in = a; 361 out = NULL; 362 for (i = 0; i < b->numsides && in; i++) 363 { 364 SplitBrush2(in, b->sides[i].planenum, &front, &back); 365 if (in != a) FreeBrush(in); 366 if (front) 367 { // add to list 368 front->next = out; 369 out = front; 370 } //end if 371 in = back; 372 } //end for 373 if (in) 374 { 375 FreeBrush (in); 376 } //end if 377 else 378 { // didn't really intersect 379 FreeBrushList (out); 380 return a; 381 } //end else 382 return out; 383 } //end of the function SubtractBrush 384 //=========================================================================== 385 // Returns a single brush made up by the intersection of the 386 // two provided brushes, or NULL if they are disjoint. 387 // 388 // The originals are undisturbed. 389 // 390 // Parameter: - 391 // Returns: - 392 // Changes Globals: - 393 //=========================================================================== 394 bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b) 395 { 396 int i; 397 bspbrush_t *front, *back; 398 bspbrush_t *in; 399 400 in = a; 401 for (i=0 ; i<b->numsides && in ; i++) 402 { 403 SplitBrush2(in, b->sides[i].planenum, &front, &back); 404 if (in != a) FreeBrush(in); 405 if (front) FreeBrush(front); 406 in = back; 407 } //end for 408 409 if (in == a) return NULL; 410 411 in->next = NULL; 412 return in; 413 } //end of the function IntersectBrush 414 //=========================================================================== 415 // Returns true if the two brushes definately do not intersect. 416 // There will be false negatives for some non-axial combinations. 417 // 418 // Parameter: - 419 // Returns: - 420 // Changes Globals: - 421 //=========================================================================== 422 qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b) 423 { 424 int i, j; 425 426 // check bounding boxes 427 for (i=0 ; i<3 ; i++) 428 if (a->mins[i] >= b->maxs[i] 429 || a->maxs[i] <= b->mins[i]) 430 return true; // bounding boxes don't overlap 431 432 // check for opposing planes 433 for (i=0 ; i<a->numsides ; i++) 434 { 435 for (j=0 ; j<b->numsides ; j++) 436 { 437 if (a->sides[i].planenum == 438 (b->sides[j].planenum^1) ) 439 return true; // opposite planes, so not touching 440 } 441 } 442 443 return false; // might intersect 444 } //end of the function BrushesDisjoint 445 //=========================================================================== 446 // Returns a content word for the intersection of two brushes. 447 // Some combinations will generate a combination (water + clip), 448 // but most will be the stronger of the two contents. 449 // 450 // Parameter: - 451 // Returns: - 452 // Changes Globals: - 453 //=========================================================================== 454 int IntersectionContents (int c1, int c2) 455 { 456 int out; 457 458 out = c1 | c2; 459 460 if (out & CONTENTS_SOLID) out = CONTENTS_SOLID; 461 462 return out; 463 } //end of the function IntersectionContents 464 //=========================================================================== 465 // Any planes shared with the box edge will be set to no texinfo 466 // 467 // Parameter: - 468 // Returns: - 469 // Changes Globals: - 470 //=========================================================================== 471 bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) 472 { 473 int i, j; 474 bspbrush_t *front, *back; 475 int p; 476 477 for (j=0 ; j<2 ; j++) 478 { 479 if (brush->maxs[j] > clipmaxs[j]) 480 { 481 SplitBrush (brush, maxplanenums[j], &front, &back); 482 if (front) 483 FreeBrush (front); 484 brush = back; 485 if (!brush) 486 return NULL; 487 } 488 if (brush->mins[j] < clipmins[j]) 489 { 490 SplitBrush (brush, minplanenums[j], &front, &back); 491 if (back) 492 FreeBrush (back); 493 brush = front; 494 if (!brush) 495 return NULL; 496 } 497 } 498 499 // remove any colinear faces 500 501 for (i=0 ; i<brush->numsides ; i++) 502 { 503 p = brush->sides[i].planenum & ~1; 504 if (p == maxplanenums[0] || p == maxplanenums[1] 505 || p == minplanenums[0] || p == minplanenums[1]) 506 { 507 brush->sides[i].texinfo = TEXINFO_NODE; 508 brush->sides[i].flags &= ~SFL_VISIBLE; 509 } 510 } 511 return brush; 512 } //end of the function ClipBrushToBox 513 //=========================================================================== 514 // 515 // Parameter: - 516 // Returns: - 517 // Changes Globals: - 518 //=========================================================================== 519 bspbrush_t *MakeBspBrushList(int startbrush, int endbrush, 520 vec3_t clipmins, vec3_t clipmaxs) 521 { 522 mapbrush_t *mb; 523 bspbrush_t *brushlist, *newbrush; 524 int i, j; 525 int c_faces; 526 int c_brushes; 527 int numsides; 528 int vis; 529 vec3_t normal; 530 float dist; 531 532 for (i=0 ; i<2 ; i++) 533 { 534 VectorClear (normal); 535 normal[i] = 1; 536 dist = clipmaxs[i]; 537 maxplanenums[i] = FindFloatPlane(normal, dist); 538 dist = clipmins[i]; 539 minplanenums[i] = FindFloatPlane(normal, dist); 540 } 541 542 brushlist = NULL; 543 c_faces = 0; 544 c_brushes = 0; 545 546 for (i=startbrush ; i<endbrush ; i++) 547 { 548 mb = &mapbrushes[i]; 549 550 numsides = mb->numsides; 551 if (!numsides) 552 continue; 553 554 // make sure the brush has at least one face showing 555 vis = 0; 556 for (j=0 ; j<numsides ; j++) 557 if ((mb->original_sides[j].flags & SFL_VISIBLE) && mb->original_sides[j].winding) 558 vis++; 559 #if 0 560 if (!vis) 561 continue; // no faces at all 562 #endif 563 // if the brush is outside the clip area, skip it 564 for (j=0 ; j<3 ; j++) 565 if (mb->mins[j] >= clipmaxs[j] 566 || mb->maxs[j] <= clipmins[j]) 567 break; 568 if (j != 3) 569 continue; 570 571 // 572 // make a copy of the brush 573 // 574 newbrush = AllocBrush (mb->numsides); 575 newbrush->original = mb; 576 newbrush->numsides = mb->numsides; 577 memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t)); 578 for (j=0 ; j<numsides ; j++) 579 { 580 if (newbrush->sides[j].winding) 581 newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding); 582 if (newbrush->sides[j].surf & SURF_HINT) 583 newbrush->sides[j].flags |= SFL_VISIBLE; // hints are always visible 584 } 585 VectorCopy (mb->mins, newbrush->mins); 586 VectorCopy (mb->maxs, newbrush->maxs); 587 588 // 589 // carve off anything outside the clip box 590 // 591 newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs); 592 if (!newbrush) 593 continue; 594 595 c_faces += vis; 596 c_brushes++; 597 598 newbrush->next = brushlist; 599 brushlist = newbrush; 600 } 601 602 return brushlist; 603 } //end of the function MakeBspBrushList 604 //=========================================================================== 605 // 606 // Parameter: - 607 // Returns: - 608 // Changes Globals: - 609 //=========================================================================== 610 bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail) 611 { 612 bspbrush_t *walk, *next; 613 614 for (walk=list ; walk ; walk=next) 615 { // add to end of list 616 next = walk->next; 617 walk->next = NULL; 618 tail->next = walk; 619 tail = walk; 620 } //end for 621 return tail; 622 } //end of the function AddBrushListToTail 623 //=========================================================================== 624 // Builds a new list that doesn't hold the given brush 625 // 626 // Parameter: - 627 // Returns: - 628 // Changes Globals: - 629 //=========================================================================== 630 bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1) 631 { 632 bspbrush_t *newlist; 633 bspbrush_t *next; 634 635 newlist = NULL; 636 637 for ( ; list ; list = next) 638 { 639 next = list->next; 640 if (list == skip1) 641 { 642 FreeBrush (list); 643 continue; 644 } 645 list->next = newlist; 646 newlist = list; 647 } 648 return newlist; 649 } //end of the function CullList 650 //=========================================================================== 651 // 652 // Parameter: - 653 // Returns: - 654 // Changes Globals: - 655 //=========================================================================== 656 /* 657 void WriteBrushMap(char *name, bspbrush_t *list) 658 { 659 FILE *f; 660 side_t *s; 661 int i; 662 winding_t *w; 663 664 Log_Print("writing %s\n", name); 665 f = fopen (name, "wb"); 666 if (!f) 667 Error ("Can't write %s\b", name); 668 669 fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); 670 671 for ( ; list ; list=list->next ) 672 { 673 fprintf (f, "{\n"); 674 for (i=0,s=list->sides ; i<list->numsides ; i++,s++) 675 { 676 w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); 677 678 fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); 679 fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); 680 fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); 681 682 fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); 683 FreeWinding (w); 684 } 685 fprintf (f, "}\n"); 686 } 687 fprintf (f, "}\n"); 688 689 fclose (f); 690 } //end of the function WriteBrushMap 691 */ 692 //=========================================================================== 693 // Returns true if b1 is allowed to bite b2 694 // 695 // Parameter: - 696 // Returns: - 697 // Changes Globals: - 698 //=========================================================================== 699 qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2) 700 { 701 #ifdef ME 702 if (create_aas) 703 { 704 if (b1->original->expansionbbox != b2->original->expansionbbox) 705 { 706 return false; 707 } //end if 708 //never have something else bite a ladder brush 709 //never have a ladder brush bite something else 710 if ( (b1->original->contents & CONTENTS_LADDER) 711 && !(b2->original->contents & CONTENTS_LADDER)) 712 { 713 return false; 714 } //end if 715 } //end if 716 #endif //ME 717 // detail brushes never bite structural brushes 718 if ( (b1->original->contents & CONTENTS_DETAIL) 719 && !(b2->original->contents & CONTENTS_DETAIL) ) 720 { 721 return false; 722 } //end if 723 if (b1->original->contents & CONTENTS_SOLID) 724 { 725 return true; 726 } //end if 727 return false; 728 } //end of the function BrushGE 729 //=========================================================================== 730 // Carves any intersecting solid brushes into the minimum number 731 // of non-intersecting brushes. 732 // 733 // Parameter: - 734 // Returns: - 735 // Changes Globals: - 736 //=========================================================================== 737 bspbrush_t *ChopBrushes (bspbrush_t *head) 738 { 739 bspbrush_t *b1, *b2, *next; 740 bspbrush_t *tail; 741 bspbrush_t *keep; 742 bspbrush_t *sub, *sub2; 743 int c1, c2; 744 int num_csg_iterations; 745 746 Log_Print("-------- Brush CSG ---------\n"); 747 Log_Print("%6d original brushes\n", CountBrushList (head)); 748 749 num_csg_iterations = 0; 750 qprintf("%6d output brushes", num_csg_iterations); 751 752 #if 0 753 if (startbrush == 0) 754 WriteBrushList ("before.gl", head, false); 755 #endif 756 keep = NULL; 757 758 newlist: 759 // find tail 760 if (!head) return NULL; 761 762 for (tail = head; tail->next; tail = tail->next) 763 ; 764 765 for (b1=head ; b1 ; b1=next) 766 { 767 next = b1->next; 768 769 //if the conversion is cancelled 770 if (cancelconversion) 771 { 772 b1->next = keep; 773 keep = b1; 774 continue; 775 } //end if 776 777 for (b2 = b1->next; b2; b2 = b2->next) 778 { 779 if (BrushesDisjoint (b1, b2)) 780 continue; 781 782 sub = NULL; 783 sub2 = NULL; 784 c1 = 999999; 785 c2 = 999999; 786 787 if (BrushGE (b2, b1)) 788 { 789 sub = SubtractBrush (b1, b2); 790 if (sub == b1) 791 { 792 continue; // didn't really intersect 793 } //end if 794 if (!sub) 795 { // b1 is swallowed by b2 796 head = CullList (b1, b1); 797 goto newlist; 798 } 799 c1 = CountBrushList (sub); 800 } 801 802 if ( BrushGE (b1, b2) ) 803 { 804 sub2 = SubtractBrush (b2, b1); 805 if (sub2 == b2) 806 continue; // didn't really intersect 807 if (!sub2) 808 { // b2 is swallowed by b1 809 FreeBrushList (sub); 810 head = CullList (b1, b2); 811 goto newlist; 812 } 813 c2 = CountBrushList (sub2); 814 } 815 816 if (!sub && !sub2) 817 continue; // neither one can bite 818 819 // only accept if it didn't fragment 820 // (commenting this out allows full fragmentation) 821 if (c1 > 1 && c2 > 1) 822 { 823 if (sub2) 824 FreeBrushList (sub2); 825 if (sub) 826 FreeBrushList (sub); 827 continue; 828 } 829 830 if (c1 < c2) 831 { 832 if (sub2) FreeBrushList (sub2); 833 tail = AddBrushListToTail (sub, tail); 834 head = CullList (b1, b1); 835 goto newlist; 836 } //end if 837 else 838 { 839 if (sub) FreeBrushList (sub); 840 tail = AddBrushListToTail (sub2, tail); 841 head = CullList (b1, b2); 842 goto newlist; 843 } //end else 844 } //end for 845 846 if (!b2) 847 { // b1 is no longer intersecting anything, so keep it 848 b1->next = keep; 849 keep = b1; 850 } //end if 851 num_csg_iterations++; 852 qprintf("\r%6d", num_csg_iterations); 853 } //end for 854 855 if (cancelconversion) return keep; 856 // 857 qprintf("\n"); 858 Log_Write("%6d output brushes\r\n", num_csg_iterations); 859 860 #if 0 861 { 862 WriteBrushList ("after.gl", keep, false); 863 WriteBrushMap ("after.map", keep); 864 } 865 #endif 866 867 return keep; 868 } //end of the function ChopBrushes 869 //=========================================================================== 870 // 871 // Parameter: - 872 // Returns: - 873 // Changes Globals: - 874 //=========================================================================== 875 bspbrush_t *InitialBrushList (bspbrush_t *list) 876 { 877 bspbrush_t *b; 878 bspbrush_t *out, *newb; 879 int i; 880 881 // only return brushes that have visible faces 882 out = NULL; 883 for (b=list ; b ; b=b->next) 884 { 885 #if 0 886 for (i=0 ; i<b->numsides ; i++) 887 if (b->sides[i].flags & SFL_VISIBLE) 888 break; 889 if (i == b->numsides) 890 continue; 891 #endif 892 newb = CopyBrush (b); 893 newb->next = out; 894 out = newb; 895 896 // clear visible, so it must be set by MarkVisibleFaces_r 897 // to be used in the optimized list 898 for (i=0 ; i<b->numsides ; i++) 899 { 900 newb->sides[i].original = &b->sides[i]; 901 // newb->sides[i].visible = true; 902 b->sides[i].flags &= ~SFL_VISIBLE; 903 } 904 } 905 906 return out; 907 } //end of the function InitialBrushList 908 //=========================================================================== 909 // 910 // Parameter: - 911 // Returns: - 912 // Changes Globals: - 913 //=========================================================================== 914 bspbrush_t *OptimizedBrushList (bspbrush_t *list) 915 { 916 bspbrush_t *b; 917 bspbrush_t *out, *newb; 918 int i; 919 920 // only return brushes that have visible faces 921 out = NULL; 922 for (b=list ; b ; b=b->next) 923 { 924 for (i=0 ; i<b->numsides ; i++) 925 if (b->sides[i].flags & SFL_VISIBLE) 926 break; 927 if (i == b->numsides) 928 continue; 929 newb = CopyBrush (b); 930 newb->next = out; 931 out = newb; 932 } //end for 933 934 // WriteBrushList ("vis.gl", out, true); 935 return out; 936 } //end of the function OptimizeBrushList 937 //=========================================================================== 938 // 939 // Parameter: - 940 // Returns: - 941 // Changes Globals: - 942 //=========================================================================== 943 tree_t *ProcessWorldBrushes(int brush_start, int brush_end) 944 { 945 bspbrush_t *brushes; 946 tree_t *tree; 947 node_t *node; 948 vec3_t mins, maxs; 949 950 //take the whole world 951 mins[0] = map_mins[0] - 8; 952 mins[1] = map_mins[1] - 8; 953 mins[2] = map_mins[2] - 8; 954 955 maxs[0] = map_maxs[0] + 8; 956 maxs[1] = map_maxs[1] + 8; 957 maxs[2] = map_maxs[2] + 8; 958 959 //reset the brush bsp 960 ResetBrushBSP(); 961 962 // the makelist and chopbrushes could be cached between the passes... 963 964 //create a list with brushes that are within the given mins/maxs 965 //some brushes will be cut and only the part that falls within the 966 //mins/maxs will be in the bush list 967 brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs); 968 // 969 970 if (!brushes) 971 { 972 node = AllocNode (); 973 node->planenum = PLANENUM_LEAF; 974 node->contents = CONTENTS_SOLID; 975 976 tree = Tree_Alloc(); 977 tree->headnode = node; 978 VectorCopy(mins, tree->mins); 979 VectorCopy(maxs, tree->maxs); 980 } //end if 981 else 982 { 983 //Carves any intersecting solid brushes into the minimum number 984 //of non-intersecting brushes. 985 if (!nocsg) 986 { 987 brushes = ChopBrushes(brushes); 988 /* 989 if (create_aas) 990 { 991 brushes = MergeBrushes(brushes); 992 } //end if*/ 993 } //end if 994 //if the conversion is cancelled 995 if (cancelconversion) 996 { 997 FreeBrushList(brushes); 998 return NULL; 999 } //end if 1000 //create the actual bsp tree 1001 tree = BrushBSP(brushes, mins, maxs); 1002 } //end else 1003 //return the tree 1004 return tree; 1005 } //end of the function ProcessWorldBrushes