portals.c (33180B)
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 26 int c_active_portals; 27 int c_peak_portals; 28 int c_boundary; 29 int c_boundary_sides; 30 int c_portalmemory; 31 32 //portal_t *portallist = NULL; 33 //=========================================================================== 34 // 35 // Parameter: - 36 // Returns: - 37 // Changes Globals: - 38 //=========================================================================== 39 portal_t *AllocPortal (void) 40 { 41 portal_t *p; 42 43 p = GetMemory(sizeof(portal_t)); 44 memset (p, 0, sizeof(portal_t)); 45 46 if (numthreads == 1) 47 { 48 c_active_portals++; 49 if (c_active_portals > c_peak_portals) 50 { 51 c_peak_portals = c_active_portals; 52 } //end if 53 c_portalmemory += MemorySize(p); 54 } //end if 55 56 // p->nextportal = portallist; 57 // portallist = p; 58 59 return p; 60 } //end of the function AllocPortal 61 //=========================================================================== 62 // 63 // Parameter: - 64 // Returns: - 65 // Changes Globals: - 66 //=========================================================================== 67 void FreePortal (portal_t *p) 68 { 69 if (p->winding) FreeWinding(p->winding); 70 if (numthreads == 1) 71 { 72 c_active_portals--; 73 c_portalmemory -= MemorySize(p); 74 } //end if 75 FreeMemory(p); 76 } //end of the function FreePortal 77 //=========================================================================== 78 // Returns the single content bit of the 79 // strongest visible content present 80 // 81 // Parameter: - 82 // Returns: - 83 // Changes Globals: - 84 //=========================================================================== 85 int VisibleContents (int contents) 86 { 87 int i; 88 89 for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1) 90 if (contents & i ) 91 return i; 92 93 return 0; 94 } //end of the function VisibleContents 95 //=========================================================================== 96 // 97 // Parameter: - 98 // Returns: - 99 // Changes Globals: - 100 //=========================================================================== 101 int ClusterContents (node_t *node) 102 { 103 int c1, c2, c; 104 105 if (node->planenum == PLANENUM_LEAF) 106 return node->contents; 107 108 c1 = ClusterContents(node->children[0]); 109 c2 = ClusterContents(node->children[1]); 110 c = c1|c2; 111 112 // a cluster may include some solid detail areas, but 113 // still be seen into 114 if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) ) 115 c &= ~CONTENTS_SOLID; 116 return c; 117 } //end of the function ClusterContents 118 119 //=========================================================================== 120 // Returns true if the portal is empty or translucent, allowing 121 // the PVS calculation to see through it. 122 // The nodes on either side of the portal may actually be clusters, 123 // not leaves, so all contents should be ored together 124 // 125 // Parameter: - 126 // Returns: - 127 // Changes Globals: - 128 //=========================================================================== 129 qboolean Portal_VisFlood (portal_t *p) 130 { 131 int c1, c2; 132 133 if (!p->onnode) 134 return false; // to global outsideleaf 135 136 c1 = ClusterContents(p->nodes[0]); 137 c2 = ClusterContents(p->nodes[1]); 138 139 if (!VisibleContents (c1^c2)) 140 return true; 141 142 if (c1 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL)) 143 c1 = 0; 144 if (c2 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL)) 145 c2 = 0; 146 147 if ( (c1|c2) & CONTENTS_SOLID ) 148 return false; // can't see through solid 149 150 if (! (c1 ^ c2)) 151 return true; // identical on both sides 152 153 if (!VisibleContents (c1^c2)) 154 return true; 155 return false; 156 } //end of the function Portal_VisFlood 157 //=========================================================================== 158 // The entity flood determines which areas are 159 // "outside" on the map, which are then filled in. 160 // Flowing from side s to side !s 161 // 162 // Parameter: - 163 // Returns: - 164 // Changes Globals: - 165 //=========================================================================== 166 qboolean Portal_EntityFlood (portal_t *p, int s) 167 { 168 if (p->nodes[0]->planenum != PLANENUM_LEAF 169 || p->nodes[1]->planenum != PLANENUM_LEAF) 170 Error ("Portal_EntityFlood: not a leaf"); 171 172 // can never cross to a solid 173 if ( (p->nodes[0]->contents & CONTENTS_SOLID) 174 || (p->nodes[1]->contents & CONTENTS_SOLID) ) 175 return false; 176 177 // can flood through everything else 178 return true; 179 } 180 181 182 //============================================================================= 183 184 int c_tinyportals; 185 186 //=========================================================================== 187 // 188 // Parameter: - 189 // Returns: - 190 // Changes Globals: - 191 //=========================================================================== 192 void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) 193 { 194 if (p->nodes[0] || p->nodes[1]) 195 Error ("AddPortalToNode: allready included"); 196 197 p->nodes[0] = front; 198 p->next[0] = front->portals; 199 front->portals = p; 200 201 p->nodes[1] = back; 202 p->next[1] = back->portals; 203 back->portals = p; 204 } //end of the function AddPortalToNodes 205 //=========================================================================== 206 // 207 // Parameter: - 208 // Returns: - 209 // Changes Globals: - 210 //=========================================================================== 211 void RemovePortalFromNode (portal_t *portal, node_t *l) 212 { 213 portal_t **pp, *t; 214 215 int s, i, n; 216 portal_t *p; 217 portal_t *portals[4096]; 218 219 // remove reference to the current portal 220 pp = &l->portals; 221 while (1) 222 { 223 t = *pp; 224 if (!t) 225 Error ("RemovePortalFromNode: portal not in leaf"); 226 227 if ( t == portal ) 228 break; 229 230 if (t->nodes[0] == l) 231 pp = &t->next[0]; 232 else if (t->nodes[1] == l) 233 pp = &t->next[1]; 234 else 235 Error ("RemovePortalFromNode: portal not bounding leaf"); 236 } 237 238 if (portal->nodes[0] == l) 239 { 240 *pp = portal->next[0]; 241 portal->nodes[0] = NULL; 242 } //end if 243 else if (portal->nodes[1] == l) 244 { 245 *pp = portal->next[1]; 246 portal->nodes[1] = NULL; 247 } //end else if 248 else 249 { 250 Error("RemovePortalFromNode: mislinked portal"); 251 } //end else 252 //#ifdef ME 253 n = 0; 254 for (p = l->portals; p; p = p->next[s]) 255 { 256 for (i = 0; i < n; i++) 257 { 258 if (p == portals[i]) Error("RemovePortalFromNode: circular linked\n"); 259 } //end for 260 if (p->nodes[0] != l && p->nodes[1] != l) 261 { 262 Error("RemovePortalFromNodes: portal does not belong to node\n"); 263 } //end if 264 portals[n] = p; 265 s = (p->nodes[1] == l); 266 // if (++n >= 4096) Error("RemovePortalFromNode: more than 4096 portals\n"); 267 } //end for 268 //#endif 269 } //end of the function RemovePortalFromNode 270 //=========================================================================== 271 // 272 // Parameter: - 273 // Returns: - 274 // Changes Globals: - 275 //=========================================================================== 276 void PrintPortal (portal_t *p) 277 { 278 int i; 279 winding_t *w; 280 281 w = p->winding; 282 for (i=0 ; i<w->numpoints ; i++) 283 printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0] 284 , w->p[i][1], w->p[i][2]); 285 } //end of the function PrintPortal 286 //=========================================================================== 287 // The created portals will face the global outside_node 288 // 289 // Parameter: - 290 // Returns: - 291 // Changes Globals: - 292 //=========================================================================== 293 #define SIDESPACE 8 294 295 void MakeHeadnodePortals (tree_t *tree) 296 { 297 vec3_t bounds[2]; 298 int i, j, n; 299 portal_t *p, *portals[6]; 300 plane_t bplanes[6], *pl; 301 node_t *node; 302 303 node = tree->headnode; 304 305 // pad with some space so there will never be null volume leaves 306 for (i=0 ; i<3 ; i++) 307 { 308 bounds[0][i] = tree->mins[i] - SIDESPACE; 309 bounds[1][i] = tree->maxs[i] + SIDESPACE; 310 if ( bounds[0][i] > bounds[1][i] ) { 311 Error("empty BSP tree"); 312 } 313 } 314 315 tree->outside_node.planenum = PLANENUM_LEAF; 316 tree->outside_node.brushlist = NULL; 317 tree->outside_node.portals = NULL; 318 tree->outside_node.contents = 0; 319 320 for (i=0 ; i<3 ; i++) 321 for (j=0 ; j<2 ; j++) 322 { 323 n = j*3 + i; 324 325 p = AllocPortal (); 326 portals[n] = p; 327 328 pl = &bplanes[n]; 329 memset (pl, 0, sizeof(*pl)); 330 if (j) 331 { 332 pl->normal[i] = -1; 333 pl->dist = -bounds[j][i]; 334 } 335 else 336 { 337 pl->normal[i] = 1; 338 pl->dist = bounds[j][i]; 339 } 340 p->plane = *pl; 341 p->winding = BaseWindingForPlane (pl->normal, pl->dist); 342 AddPortalToNodes (p, node, &tree->outside_node); 343 } 344 345 // clip the basewindings by all the other planes 346 for (i=0 ; i<6 ; i++) 347 { 348 for (j=0 ; j<6 ; j++) 349 { 350 if (j == i) continue; 351 ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); 352 } //end for 353 } //end for 354 } //end of the function MakeHeadNodePortals 355 //=========================================================================== 356 // 357 // Parameter: - 358 // Returns: - 359 // Changes Globals: - 360 //=========================================================================== 361 #define BASE_WINDING_EPSILON 0.001 362 #define SPLIT_WINDING_EPSILON 0.001 363 364 winding_t *BaseWindingForNode (node_t *node) 365 { 366 winding_t *w; 367 node_t *n; 368 plane_t *plane; 369 vec3_t normal; 370 vec_t dist; 371 372 w = BaseWindingForPlane (mapplanes[node->planenum].normal 373 , mapplanes[node->planenum].dist); 374 375 // clip by all the parents 376 for (n=node->parent ; n && w ; ) 377 { 378 plane = &mapplanes[n->planenum]; 379 380 if (n->children[0] == node) 381 { // take front 382 ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); 383 } 384 else 385 { // take back 386 VectorSubtract (vec3_origin, plane->normal, normal); 387 dist = -plane->dist; 388 ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); 389 } 390 node = n; 391 n = n->parent; 392 } 393 394 return w; 395 } //end of the function BaseWindingForNode 396 //=========================================================================== 397 // create the new portal by taking the full plane winding for the cutting 398 // plane and clipping it by all of parents of this node 399 // 400 // Parameter: - 401 // Returns: - 402 // Changes Globals: - 403 //=========================================================================== 404 qboolean WindingIsTiny (winding_t *w); 405 406 void MakeNodePortal (node_t *node) 407 { 408 portal_t *new_portal, *p; 409 winding_t *w; 410 vec3_t normal; 411 float dist; 412 int side; 413 414 w = BaseWindingForNode (node); 415 416 // clip the portal by all the other portals in the node 417 for (p = node->portals; p && w; p = p->next[side]) 418 { 419 if (p->nodes[0] == node) 420 { 421 side = 0; 422 VectorCopy (p->plane.normal, normal); 423 dist = p->plane.dist; 424 } //end if 425 else if (p->nodes[1] == node) 426 { 427 side = 1; 428 VectorSubtract (vec3_origin, p->plane.normal, normal); 429 dist = -p->plane.dist; 430 } //end else if 431 else 432 { 433 Error ("MakeNodePortal: mislinked portal"); 434 } //end else 435 ChopWindingInPlace (&w, normal, dist, 0.1); 436 } //end for 437 438 if (!w) 439 { 440 return; 441 } //end if 442 443 if (WindingIsTiny (w)) 444 { 445 c_tinyportals++; 446 FreeWinding(w); 447 return; 448 } //end if 449 450 #ifdef DEBUG 451 /* //NOTE: don't use this winding ok check 452 // all the invalid windings only have a degenerate edge 453 if (WindingError(w)) 454 { 455 Log_Print("MakeNodePortal: %s\n", WindingErrorString()); 456 FreeWinding(w); 457 return; 458 } //end if*/ 459 #endif //DEBUG 460 461 462 new_portal = AllocPortal(); 463 new_portal->plane = mapplanes[node->planenum]; 464 465 #ifdef ME 466 new_portal->planenum = node->planenum; 467 #endif //ME 468 469 new_portal->onnode = node; 470 new_portal->winding = w; 471 AddPortalToNodes (new_portal, node->children[0], node->children[1]); 472 } //end of the function MakeNodePortal 473 //=========================================================================== 474 // Move or split the portals that bound node so that the node's 475 // children have portals instead of node. 476 // 477 // Parameter: - 478 // Returns: - 479 // Changes Globals: - 480 //=========================================================================== 481 void SplitNodePortals (node_t *node) 482 { 483 portal_t *p, *next_portal, *new_portal; 484 node_t *f, *b, *other_node; 485 int side; 486 plane_t *plane; 487 winding_t *frontwinding, *backwinding; 488 489 plane = &mapplanes[node->planenum]; 490 f = node->children[0]; 491 b = node->children[1]; 492 493 for (p = node->portals ; p ; p = next_portal) 494 { 495 if (p->nodes[0] == node) side = 0; 496 else if (p->nodes[1] == node) side = 1; 497 else Error ("SplitNodePortals: mislinked portal"); 498 next_portal = p->next[side]; 499 500 other_node = p->nodes[!side]; 501 RemovePortalFromNode (p, p->nodes[0]); 502 RemovePortalFromNode (p, p->nodes[1]); 503 504 // 505 // cut the portal into two portals, one on each side of the cut plane 506 // 507 ClipWindingEpsilon (p->winding, plane->normal, plane->dist, 508 SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); 509 510 if (frontwinding && WindingIsTiny(frontwinding)) 511 { 512 FreeWinding (frontwinding); 513 frontwinding = NULL; 514 c_tinyportals++; 515 } //end if 516 517 if (backwinding && WindingIsTiny(backwinding)) 518 { 519 FreeWinding (backwinding); 520 backwinding = NULL; 521 c_tinyportals++; 522 } //end if 523 524 #ifdef DEBUG 525 /* //NOTE: don't use this winding ok check 526 // all the invalid windings only have a degenerate edge 527 if (frontwinding && WindingError(frontwinding)) 528 { 529 Log_Print("SplitNodePortals: front %s\n", WindingErrorString()); 530 FreeWinding(frontwinding); 531 frontwinding = NULL; 532 } //end if 533 if (backwinding && WindingError(backwinding)) 534 { 535 Log_Print("SplitNodePortals: back %s\n", WindingErrorString()); 536 FreeWinding(backwinding); 537 backwinding = NULL; 538 } //end if*/ 539 #endif //DEBUG 540 541 if (!frontwinding && !backwinding) 542 { // tiny windings on both sides 543 continue; 544 } 545 546 if (!frontwinding) 547 { 548 FreeWinding (backwinding); 549 if (side == 0) AddPortalToNodes (p, b, other_node); 550 else AddPortalToNodes (p, other_node, b); 551 continue; 552 } 553 if (!backwinding) 554 { 555 FreeWinding (frontwinding); 556 if (side == 0) AddPortalToNodes (p, f, other_node); 557 else AddPortalToNodes (p, other_node, f); 558 continue; 559 } 560 561 // the winding is split 562 new_portal = AllocPortal(); 563 *new_portal = *p; 564 new_portal->winding = backwinding; 565 FreeWinding (p->winding); 566 p->winding = frontwinding; 567 568 if (side == 0) 569 { 570 AddPortalToNodes (p, f, other_node); 571 AddPortalToNodes (new_portal, b, other_node); 572 } //end if 573 else 574 { 575 AddPortalToNodes (p, other_node, f); 576 AddPortalToNodes (new_portal, other_node, b); 577 } //end else 578 } 579 580 node->portals = NULL; 581 } //end of the function SplitNodePortals 582 //=========================================================================== 583 // 584 // Parameter: - 585 // Returns: - 586 // Changes Globals: - 587 //=========================================================================== 588 void CalcNodeBounds (node_t *node) 589 { 590 portal_t *p; 591 int s; 592 int i; 593 594 // calc mins/maxs for both leaves and nodes 595 ClearBounds (node->mins, node->maxs); 596 for (p = node->portals ; p ; p = p->next[s]) 597 { 598 s = (p->nodes[1] == node); 599 for (i=0 ; i<p->winding->numpoints ; i++) 600 AddPointToBounds (p->winding->p[i], node->mins, node->maxs); 601 } 602 } //end of the function CalcNodeBounds 603 //=========================================================================== 604 // 605 // Parameter: - 606 // Returns: - 607 // Changes Globals: - 608 //=========================================================================== 609 int c_numportalizednodes; 610 611 void MakeTreePortals_r (node_t *node) 612 { 613 int i; 614 615 #ifdef ME 616 qprintf("\r%6d", ++c_numportalizednodes); 617 if (cancelconversion) return; 618 #endif //ME 619 620 CalcNodeBounds (node); 621 if (node->mins[0] >= node->maxs[0]) 622 { 623 Log_Print("WARNING: node without a volume\n"); 624 } 625 626 for (i=0 ; i<3 ; i++) 627 { 628 if (node->mins[i] < -MAX_MAP_BOUNDS || node->maxs[i] > MAX_MAP_BOUNDS) 629 { 630 Log_Print("WARNING: node with unbounded volume\n"); 631 break; 632 } 633 } 634 if (node->planenum == PLANENUM_LEAF) 635 return; 636 637 MakeNodePortal (node); 638 SplitNodePortals (node); 639 640 MakeTreePortals_r (node->children[0]); 641 MakeTreePortals_r (node->children[1]); 642 } //end of the function MakeTreePortals_r 643 //=========================================================================== 644 // 645 // Parameter: - 646 // Returns: - 647 // Changes Globals: - 648 //=========================================================================== 649 void MakeTreePortals(tree_t *tree) 650 { 651 652 #ifdef ME 653 Log_Print("---- Node Portalization ----\n"); 654 c_numportalizednodes = 0; 655 c_portalmemory = 0; 656 qprintf("%6d nodes portalized", c_numportalizednodes); 657 #endif //ME 658 659 MakeHeadnodePortals(tree); 660 MakeTreePortals_r(tree->headnode); 661 662 #ifdef ME 663 qprintf("\n"); 664 Log_Write("%6d nodes portalized\r\n", c_numportalizednodes); 665 Log_Print("%6d tiny portals\r\n", c_tinyportals); 666 Log_Print("%6d KB of portal memory\r\n", c_portalmemory >> 10); 667 Log_Print("%6i KB of winding memory\r\n", WindingMemory() >> 10); 668 #endif //ME 669 } //end of the function MakeTreePortals 670 671 /* 672 ========================================================= 673 674 FLOOD ENTITIES 675 676 ========================================================= 677 */ 678 //#define P_NODESTACK 679 680 node_t *p_firstnode; 681 node_t *p_lastnode; 682 683 //=========================================================================== 684 // 685 // Parameter: - 686 // Returns: - 687 // Changes Globals: - 688 //=========================================================================== 689 #ifdef P_NODESTACK 690 void P_AddNodeToList(node_t *node) 691 { 692 node->next = p_firstnode; 693 p_firstnode = node; 694 if (!p_lastnode) p_lastnode = node; 695 } //end of the function P_AddNodeToList 696 #else //it's a node queue 697 //add the node to the end of the node list 698 void P_AddNodeToList(node_t *node) 699 { 700 node->next = NULL; 701 if (p_lastnode) p_lastnode->next = node; 702 else p_firstnode = node; 703 p_lastnode = node; 704 } //end of the function P_AddNodeToList 705 #endif //P_NODESTACK 706 //=========================================================================== 707 // get the first node from the front of the node list 708 // 709 // Parameter: - 710 // Returns: - 711 // Changes Globals: - 712 //=========================================================================== 713 node_t *P_NextNodeFromList(void) 714 { 715 node_t *node; 716 717 node = p_firstnode; 718 if (p_firstnode) p_firstnode = p_firstnode->next; 719 if (!p_firstnode) p_lastnode = NULL; 720 return node; 721 } //end of the function P_NextNodeFromList 722 //=========================================================================== 723 // 724 // Parameter: - 725 // Returns: - 726 // Changes Globals: - 727 //=========================================================================== 728 void FloodPortals(node_t *firstnode) 729 { 730 node_t *node; 731 portal_t *p; 732 int s; 733 734 firstnode->occupied = 1; 735 P_AddNodeToList(firstnode); 736 737 for (node = P_NextNodeFromList(); node; node = P_NextNodeFromList()) 738 { 739 for (p = node->portals; p; p = p->next[s]) 740 { 741 s = (p->nodes[1] == node); 742 //if the node at the other side of the portal is occupied already 743 if (p->nodes[!s]->occupied) continue; 744 //if it isn't possible to flood through this portal 745 if (!Portal_EntityFlood(p, s)) continue; 746 // 747 p->nodes[!s]->occupied = node->occupied + 1; 748 // 749 P_AddNodeToList(p->nodes[!s]); 750 } //end for 751 } //end for 752 } //end of the function FloodPortals 753 //=========================================================================== 754 // 755 // Parameter: - 756 // Returns: - 757 // Changes Globals: - 758 //=========================================================================== 759 int numrec; 760 761 void FloodPortals_r (node_t *node, int dist) 762 { 763 portal_t *p; 764 int s; 765 // int i; 766 767 Log_Print("\r%6d", ++numrec); 768 769 if (node->occupied) Error("FloodPortals_r: node already occupied\n"); 770 if (!node) 771 { 772 Error("FloodPortals_r: NULL node\n"); 773 } //end if*/ 774 node->occupied = dist; 775 776 for (p = node->portals; p; p = p->next[s]) 777 { 778 s = (p->nodes[1] == node); 779 //if the node at the other side of the portal is occupied already 780 if (p->nodes[!s]->occupied) continue; 781 //if it isn't possible to flood through this portal 782 if (!Portal_EntityFlood(p, s)) continue; 783 //flood recursively through the current portal 784 FloodPortals_r(p->nodes[!s], dist+1); 785 } //end for 786 Log_Print("\r%6d", --numrec); 787 } //end of the function FloodPortals_r 788 //=========================================================================== 789 // 790 // Parameter: - 791 // Returns: - 792 // Changes Globals: - 793 //=========================================================================== 794 qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant) 795 { 796 node_t *node; 797 vec_t d; 798 plane_t *plane; 799 800 //find the leaf to start in 801 node = headnode; 802 while(node->planenum != PLANENUM_LEAF) 803 { 804 if (node->planenum < 0 || node->planenum > nummapplanes) 805 { 806 Error("PlaceOccupant: invalid node->planenum\n"); 807 } //end if 808 plane = &mapplanes[node->planenum]; 809 d = DotProduct(origin, plane->normal) - plane->dist; 810 if (d >= 0) node = node->children[0]; 811 else node = node->children[1]; 812 if (!node) 813 { 814 Error("PlaceOccupant: invalid child %d\n", d < 0); 815 } //end if 816 } //end while 817 //don't start in solid 818 // if (node->contents == CONTENTS_SOLID) 819 //ME: replaced because in LeafNode in brushbsp.c 820 // some nodes have contents solid with other contents 821 if (node->contents & CONTENTS_SOLID) return false; 822 //if the node is already occupied 823 if (node->occupied) return false; 824 825 //place the occupant in the first leaf 826 node->occupant = occupant; 827 828 numrec = 0; 829 // Log_Print("%6d recurses", numrec); 830 // FloodPortals_r(node, 1); 831 // Log_Print("\n"); 832 FloodPortals(node); 833 834 return true; 835 } //end of the function PlaceOccupant 836 //=========================================================================== 837 // Marks all nodes that can be reached by entites 838 // 839 // Parameter: - 840 // Returns: - 841 // Changes Globals: - 842 //=========================================================================== 843 qboolean FloodEntities (tree_t *tree) 844 { 845 int i; 846 int x, y; 847 vec3_t origin; 848 char *cl; 849 qboolean inside; 850 node_t *headnode; 851 852 headnode = tree->headnode; 853 Log_Print("------ FloodEntities -------\n"); 854 inside = false; 855 tree->outside_node.occupied = 0; 856 857 //start at entity 1 not the world ( = 0) 858 for (i = 1; i < num_entities; i++) 859 { 860 GetVectorForKey(&entities[i], "origin", origin); 861 if (VectorCompare(origin, vec3_origin)) continue; 862 863 cl = ValueForKey(&entities[i], "classname"); 864 origin[2] += 1; //so objects on floor are ok 865 866 // Log_Print("flooding from entity %d: %s\n", i, cl); 867 //nudge playerstart around if needed so clipping hulls allways 868 //have a valid point 869 if (!strcmp(cl, "info_player_start")) 870 { 871 for (x = -16; x <= 16; x += 16) 872 { 873 for (y = -16; y <= 16; y += 16) 874 { 875 origin[0] += x; 876 origin[1] += y; 877 if (PlaceOccupant(headnode, origin, &entities[i])) 878 { 879 inside = true; 880 x = 999; //stop for this info_player_start 881 break; 882 } //end if 883 origin[0] -= x; 884 origin[1] -= y; 885 } //end for 886 } //end for 887 } //end if 888 else 889 { 890 if (PlaceOccupant(headnode, origin, &entities[i])) 891 { 892 inside = true; 893 } //end if 894 } //end else 895 } //end for 896 897 if (!inside) 898 { 899 Log_Print("WARNING: no entities inside\n"); 900 } //end if 901 else if (tree->outside_node.occupied) 902 { 903 Log_Print("WARNING: entity reached from outside\n"); 904 } //end else if 905 906 return (qboolean)(inside && !tree->outside_node.occupied); 907 } //end of the function FloodEntities 908 909 /* 910 ========================================================= 911 912 FILL OUTSIDE 913 914 ========================================================= 915 */ 916 917 int c_outside; 918 int c_inside; 919 int c_solid; 920 921 //=========================================================================== 922 // 923 // Parameter: - 924 // Returns: - 925 // Changes Globals: - 926 //=========================================================================== 927 void FillOutside_r (node_t *node) 928 { 929 if (node->planenum != PLANENUM_LEAF) 930 { 931 FillOutside_r (node->children[0]); 932 FillOutside_r (node->children[1]); 933 return; 934 } //end if 935 // anything not reachable by an entity 936 // can be filled away (by setting solid contents) 937 if (!node->occupied) 938 { 939 if (!(node->contents & CONTENTS_SOLID)) 940 { 941 c_outside++; 942 node->contents |= CONTENTS_SOLID; 943 } //end if 944 else 945 { 946 c_solid++; 947 } //end else 948 } //end if 949 else 950 { 951 c_inside++; 952 } //end else 953 } //end of the function FillOutside_r 954 //=========================================================================== 955 // Fill all nodes that can't be reached by entities 956 // 957 // Parameter: - 958 // Returns: - 959 // Changes Globals: - 960 //=========================================================================== 961 void FillOutside (node_t *headnode) 962 { 963 c_outside = 0; 964 c_inside = 0; 965 c_solid = 0; 966 Log_Print("------- FillOutside --------\n"); 967 FillOutside_r (headnode); 968 Log_Print("%5i solid leaves\n", c_solid); 969 Log_Print("%5i leaves filled\n", c_outside); 970 Log_Print("%5i inside leaves\n", c_inside); 971 } //end of the function FillOutside 972 973 /* 974 ========================================================= 975 976 FLOOD AREAS 977 978 ========================================================= 979 */ 980 981 int c_areas; 982 983 //=========================================================================== 984 // 985 // Parameter: - 986 // Returns: - 987 // Changes Globals: - 988 //=========================================================================== 989 void FloodAreas_r (node_t *node) 990 { 991 portal_t *p; 992 int s; 993 bspbrush_t *b; 994 entity_t *e; 995 996 if (node->contents == CONTENTS_AREAPORTAL) 997 { 998 // this node is part of an area portal 999 b = node->brushlist; 1000 e = &entities[b->original->entitynum]; 1001 1002 // if the current area has allready touched this 1003 // portal, we are done 1004 if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas) 1005 return; 1006 1007 // note the current area as bounding the portal 1008 if (e->portalareas[1]) 1009 { 1010 Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum); 1011 return; 1012 } 1013 if (e->portalareas[0]) 1014 e->portalareas[1] = c_areas; 1015 else 1016 e->portalareas[0] = c_areas; 1017 1018 return; 1019 } //end if 1020 1021 if (node->area) 1022 return; // allready got it 1023 node->area = c_areas; 1024 1025 for (p=node->portals ; p ; p = p->next[s]) 1026 { 1027 s = (p->nodes[1] == node); 1028 #if 0 1029 if (p->nodes[!s]->occupied) 1030 continue; 1031 #endif 1032 if (!Portal_EntityFlood (p, s)) 1033 continue; 1034 1035 FloodAreas_r (p->nodes[!s]); 1036 } //end for 1037 } //end of the function FloodAreas_r 1038 //=========================================================================== 1039 // Just decend the tree, and for each node that hasn't had an 1040 // area set, flood fill out from there 1041 // 1042 // Parameter: - 1043 // Returns: - 1044 // Changes Globals: - 1045 //=========================================================================== 1046 void FindAreas_r (node_t *node) 1047 { 1048 if (node->planenum != PLANENUM_LEAF) 1049 { 1050 FindAreas_r (node->children[0]); 1051 FindAreas_r (node->children[1]); 1052 return; 1053 } 1054 1055 if (node->area) 1056 return; // allready got it 1057 1058 if (node->contents & CONTENTS_SOLID) 1059 return; 1060 1061 if (!node->occupied) 1062 return; // not reachable by entities 1063 1064 // area portals are allways only flooded into, never 1065 // out of 1066 if (node->contents == CONTENTS_AREAPORTAL) 1067 return; 1068 1069 c_areas++; 1070 FloodAreas_r (node); 1071 } //end of the function FindAreas_r 1072 //=========================================================================== 1073 // Just decend the tree, and for each node that hasn't had an 1074 // area set, flood fill out from there 1075 // 1076 // Parameter: - 1077 // Returns: - 1078 // Changes Globals: - 1079 //=========================================================================== 1080 void SetAreaPortalAreas_r (node_t *node) 1081 { 1082 bspbrush_t *b; 1083 entity_t *e; 1084 1085 if (node->planenum != PLANENUM_LEAF) 1086 { 1087 SetAreaPortalAreas_r (node->children[0]); 1088 SetAreaPortalAreas_r (node->children[1]); 1089 return; 1090 } //end if 1091 1092 if (node->contents == CONTENTS_AREAPORTAL) 1093 { 1094 if (node->area) 1095 return; // allready set 1096 1097 b = node->brushlist; 1098 e = &entities[b->original->entitynum]; 1099 node->area = e->portalareas[0]; 1100 if (!e->portalareas[1]) 1101 { 1102 Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum); 1103 return; 1104 } //end if 1105 } //end if 1106 } //end of the function SetAreaPortalAreas_r 1107 //=========================================================================== 1108 // 1109 // Parameter: - 1110 // Returns: - 1111 // Changes Globals: - 1112 //=========================================================================== 1113 /* 1114 void EmitAreaPortals(node_t *headnode) 1115 { 1116 int i, j; 1117 entity_t *e; 1118 dareaportal_t *dp; 1119 1120 if (c_areas > MAX_MAP_AREAS) 1121 Error ("MAX_MAP_AREAS"); 1122 numareas = c_areas+1; 1123 numareaportals = 1; // leave 0 as an error 1124 1125 for (i=1 ; i<=c_areas ; i++) 1126 { 1127 dareas[i].firstareaportal = numareaportals; 1128 for (j=0 ; j<num_entities ; j++) 1129 { 1130 e = &entities[j]; 1131 if (!e->areaportalnum) 1132 continue; 1133 dp = &dareaportals[numareaportals]; 1134 if (e->portalareas[0] == i) 1135 { 1136 dp->portalnum = e->areaportalnum; 1137 dp->otherarea = e->portalareas[1]; 1138 numareaportals++; 1139 } //end if 1140 else if (e->portalareas[1] == i) 1141 { 1142 dp->portalnum = e->areaportalnum; 1143 dp->otherarea = e->portalareas[0]; 1144 numareaportals++; 1145 } //end else if 1146 } //end for 1147 dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal; 1148 } //end for 1149 1150 Log_Print("%5i numareas\n", numareas); 1151 Log_Print("%5i numareaportals\n", numareaportals); 1152 } //end of the function EmitAreaPortals 1153 */ 1154 //=========================================================================== 1155 // Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL 1156 // 1157 // Parameter: - 1158 // Returns: - 1159 // Changes Globals: - 1160 //=========================================================================== 1161 void FloodAreas (tree_t *tree) 1162 { 1163 Log_Print("--- FloodAreas ---\n"); 1164 FindAreas_r (tree->headnode); 1165 SetAreaPortalAreas_r (tree->headnode); 1166 Log_Print("%5i areas\n", c_areas); 1167 } //end of the function FloodAreas 1168 //=========================================================================== 1169 // Finds a brush side to use for texturing the given portal 1170 // 1171 // Parameter: - 1172 // Returns: - 1173 // Changes Globals: - 1174 //=========================================================================== 1175 void FindPortalSide (portal_t *p) 1176 { 1177 int viscontents; 1178 bspbrush_t *bb; 1179 mapbrush_t *brush; 1180 node_t *n; 1181 int i,j; 1182 int planenum; 1183 side_t *side, *bestside; 1184 float dot, bestdot; 1185 plane_t *p1, *p2; 1186 1187 // decide which content change is strongest 1188 // solid > lava > water, etc 1189 viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents); 1190 if (!viscontents) 1191 return; 1192 1193 planenum = p->onnode->planenum; 1194 bestside = NULL; 1195 bestdot = 0; 1196 1197 for (j=0 ; j<2 ; j++) 1198 { 1199 n = p->nodes[j]; 1200 p1 = &mapplanes[p->onnode->planenum]; 1201 for (bb=n->brushlist ; bb ; bb=bb->next) 1202 { 1203 brush = bb->original; 1204 if ( !(brush->contents & viscontents) ) 1205 continue; 1206 for (i=0 ; i<brush->numsides ; i++) 1207 { 1208 side = &brush->original_sides[i]; 1209 if (side->flags & SFL_BEVEL) 1210 continue; 1211 if (side->texinfo == TEXINFO_NODE) 1212 continue; // non-visible 1213 if ((side->planenum&~1) == planenum) 1214 { // exact match 1215 bestside = &brush->original_sides[i]; 1216 goto gotit; 1217 } //end if 1218 // see how close the match is 1219 p2 = &mapplanes[side->planenum&~1]; 1220 dot = DotProduct (p1->normal, p2->normal); 1221 if (dot > bestdot) 1222 { 1223 bestdot = dot; 1224 bestside = side; 1225 } //end if 1226 } //end for 1227 } //end for 1228 } //end for 1229 1230 gotit: 1231 if (!bestside) 1232 Log_Print("WARNING: side not found for portal\n"); 1233 1234 p->sidefound = true; 1235 p->side = bestside; 1236 } //end of the function FindPortalSide 1237 //=========================================================================== 1238 // 1239 // Parameter: - 1240 // Returns: - 1241 // Changes Globals: - 1242 //=========================================================================== 1243 void MarkVisibleSides_r (node_t *node) 1244 { 1245 portal_t *p; 1246 int s; 1247 1248 if (node->planenum != PLANENUM_LEAF) 1249 { 1250 MarkVisibleSides_r (node->children[0]); 1251 MarkVisibleSides_r (node->children[1]); 1252 return; 1253 } //end if 1254 1255 // empty leaves are never boundary leaves 1256 if (!node->contents) return; 1257 1258 // see if there is a visible face 1259 for (p=node->portals ; p ; p = p->next[!s]) 1260 { 1261 s = (p->nodes[0] == node); 1262 if (!p->onnode) 1263 continue; // edge of world 1264 if (!p->sidefound) 1265 FindPortalSide (p); 1266 if (p->side) 1267 p->side->flags |= SFL_VISIBLE; 1268 } //end for 1269 } //end of the function MarkVisibleSides_r 1270 //=========================================================================== 1271 // 1272 // Parameter: - 1273 // Returns: - 1274 // Changes Globals: - 1275 //=========================================================================== 1276 void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush) 1277 { 1278 int i, j; 1279 mapbrush_t *mb; 1280 int numsides; 1281 1282 Log_Print("--- MarkVisibleSides ---\n"); 1283 1284 // clear all the visible flags 1285 for (i=startbrush ; i<endbrush ; i++) 1286 { 1287 mb = &mapbrushes[i]; 1288 1289 numsides = mb->numsides; 1290 for (j=0 ; j<numsides ; j++) 1291 mb->original_sides[j].flags &= ~SFL_VISIBLE; 1292 } 1293 1294 // set visible flags on the sides that are used by portals 1295 MarkVisibleSides_r (tree->headnode); 1296 } //end of the function MarkVisibleSides 1297