visflow.c (36073B)
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 "vis.h" 23 24 /* 25 26 each portal will have a list of all possible to see from first portal 27 28 if (!thread->portalmightsee[portalnum]) 29 30 portal mightsee 31 32 for p2 = all other portals in leaf 33 get sperating planes 34 for all portals that might be seen by p2 35 mark as unseen if not present in seperating plane 36 flood fill a new mightsee 37 save as passagemightsee 38 39 40 void CalcMightSee (leaf_t *leaf, 41 */ 42 43 int CountBits (byte *bits, int numbits) 44 { 45 int i; 46 int c; 47 48 c = 0; 49 for (i=0 ; i<numbits ; i++) 50 if (bits[i>>3] & (1<<(i&7)) ) 51 c++; 52 53 return c; 54 } 55 56 int c_fullskip; 57 int c_portalskip, c_leafskip; 58 int c_vistest, c_mighttest; 59 60 int c_chop, c_nochop; 61 62 int active; 63 64 void CheckStack (leaf_t *leaf, threaddata_t *thread) 65 { 66 pstack_t *p, *p2; 67 68 for (p=thread->pstack_head.next ; p ; p=p->next) 69 { 70 // _printf ("="); 71 if (p->leaf == leaf) 72 Error ("CheckStack: leaf recursion"); 73 for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next) 74 if (p2->leaf == p->leaf) 75 Error ("CheckStack: late leaf recursion"); 76 } 77 // _printf ("\n"); 78 } 79 80 81 winding_t *AllocStackWinding (pstack_t *stack) 82 { 83 int i; 84 85 for (i=0 ; i<3 ; i++) 86 { 87 if (stack->freewindings[i]) 88 { 89 stack->freewindings[i] = 0; 90 return &stack->windings[i]; 91 } 92 } 93 94 Error ("AllocStackWinding: failed"); 95 96 return NULL; 97 } 98 99 void FreeStackWinding (winding_t *w, pstack_t *stack) 100 { 101 int i; 102 103 i = w - stack->windings; 104 105 if (i<0 || i>2) 106 return; // not from local 107 108 if (stack->freewindings[i]) 109 Error ("FreeStackWinding: allready free"); 110 stack->freewindings[i] = 1; 111 } 112 113 /* 114 ============== 115 VisChopWinding 116 117 ============== 118 */ 119 winding_t *VisChopWinding (winding_t *in, pstack_t *stack, plane_t *split) 120 { 121 vec_t dists[128]; 122 int sides[128]; 123 int counts[3]; 124 vec_t dot; 125 int i, j; 126 vec_t *p1, *p2; 127 vec3_t mid; 128 winding_t *neww; 129 130 counts[0] = counts[1] = counts[2] = 0; 131 132 // determine sides for each point 133 for (i=0 ; i<in->numpoints ; i++) 134 { 135 dot = DotProduct (in->points[i], split->normal); 136 dot -= split->dist; 137 dists[i] = dot; 138 if (dot > ON_EPSILON) 139 sides[i] = SIDE_FRONT; 140 else if (dot < -ON_EPSILON) 141 sides[i] = SIDE_BACK; 142 else 143 { 144 sides[i] = SIDE_ON; 145 } 146 counts[sides[i]]++; 147 } 148 149 if (!counts[1]) 150 return in; // completely on front side 151 152 if (!counts[0]) 153 { 154 FreeStackWinding (in, stack); 155 return NULL; 156 } 157 158 sides[i] = sides[0]; 159 dists[i] = dists[0]; 160 161 neww = AllocStackWinding (stack); 162 163 neww->numpoints = 0; 164 165 for (i=0 ; i<in->numpoints ; i++) 166 { 167 p1 = in->points[i]; 168 169 if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) 170 { 171 FreeStackWinding (neww, stack); 172 return in; // can't chop -- fall back to original 173 } 174 175 if (sides[i] == SIDE_ON) 176 { 177 VectorCopy (p1, neww->points[neww->numpoints]); 178 neww->numpoints++; 179 continue; 180 } 181 182 if (sides[i] == SIDE_FRONT) 183 { 184 VectorCopy (p1, neww->points[neww->numpoints]); 185 neww->numpoints++; 186 } 187 188 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 189 continue; 190 191 if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) 192 { 193 FreeStackWinding (neww, stack); 194 return in; // can't chop -- fall back to original 195 } 196 197 // generate a split point 198 p2 = in->points[(i+1)%in->numpoints]; 199 200 dot = dists[i] / (dists[i]-dists[i+1]); 201 for (j=0 ; j<3 ; j++) 202 { // avoid round off error when possible 203 if (split->normal[j] == 1) 204 mid[j] = split->dist; 205 else if (split->normal[j] == -1) 206 mid[j] = -split->dist; 207 else 208 mid[j] = p1[j] + dot*(p2[j]-p1[j]); 209 } 210 211 VectorCopy (mid, neww->points[neww->numpoints]); 212 neww->numpoints++; 213 } 214 215 // free the original winding 216 FreeStackWinding (in, stack); 217 218 return neww; 219 } 220 221 /* 222 ============== 223 ClipToSeperators 224 225 Source, pass, and target are an ordering of portals. 226 227 Generates seperating planes canidates by taking two points from source and one 228 point from pass, and clips target by them. 229 230 If target is totally clipped away, that portal can not be seen through. 231 232 Normal clip keeps target on the same side as pass, which is correct if the 233 order goes source, pass, target. If the order goes pass, source, target then 234 flipclip should be set. 235 ============== 236 */ 237 winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack) 238 { 239 int i, j, k, l; 240 plane_t plane; 241 vec3_t v1, v2; 242 float d; 243 vec_t length; 244 int counts[3]; 245 qboolean fliptest; 246 247 // check all combinations 248 for (i=0 ; i<source->numpoints ; i++) 249 { 250 l = (i+1)%source->numpoints; 251 VectorSubtract (source->points[l] , source->points[i], v1); 252 253 // find a vertex of pass that makes a plane that puts all of the 254 // vertexes of pass on the front side and all of the vertexes of 255 // source on the back side 256 for (j=0 ; j<pass->numpoints ; j++) 257 { 258 VectorSubtract (pass->points[j], source->points[i], v2); 259 260 plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; 261 plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; 262 plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; 263 264 // if points don't make a valid plane, skip it 265 266 length = plane.normal[0] * plane.normal[0] 267 + plane.normal[1] * plane.normal[1] 268 + plane.normal[2] * plane.normal[2]; 269 270 if (length < ON_EPSILON) 271 continue; 272 273 length = 1/sqrt(length); 274 275 plane.normal[0] *= length; 276 plane.normal[1] *= length; 277 plane.normal[2] *= length; 278 279 plane.dist = DotProduct (pass->points[j], plane.normal); 280 281 // 282 // find out which side of the generated seperating plane has the 283 // source portal 284 // 285 #if 1 286 fliptest = qfalse; 287 for (k=0 ; k<source->numpoints ; k++) 288 { 289 if (k == i || k == l) 290 continue; 291 d = DotProduct (source->points[k], plane.normal) - plane.dist; 292 if (d < -ON_EPSILON) 293 { // source is on the negative side, so we want all 294 // pass and target on the positive side 295 fliptest = qfalse; 296 break; 297 } 298 else if (d > ON_EPSILON) 299 { // source is on the positive side, so we want all 300 // pass and target on the negative side 301 fliptest = qtrue; 302 break; 303 } 304 } 305 if (k == source->numpoints) 306 continue; // planar with source portal 307 #else 308 fliptest = flipclip; 309 #endif 310 // 311 // flip the normal if the source portal is backwards 312 // 313 if (fliptest) 314 { 315 VectorSubtract (vec3_origin, plane.normal, plane.normal); 316 plane.dist = -plane.dist; 317 } 318 #if 1 319 // 320 // if all of the pass portal points are now on the positive side, 321 // this is the seperating plane 322 // 323 counts[0] = counts[1] = counts[2] = 0; 324 for (k=0 ; k<pass->numpoints ; k++) 325 { 326 if (k==j) 327 continue; 328 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 329 if (d < -ON_EPSILON) 330 break; 331 else if (d > ON_EPSILON) 332 counts[0]++; 333 else 334 counts[2]++; 335 } 336 if (k != pass->numpoints) 337 continue; // points on negative side, not a seperating plane 338 339 if (!counts[0]) 340 continue; // planar with seperating plane 341 #else 342 k = (j+1)%pass->numpoints; 343 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 344 if (d < -ON_EPSILON) 345 continue; 346 k = (j+pass->numpoints-1)%pass->numpoints; 347 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 348 if (d < -ON_EPSILON) 349 continue; 350 #endif 351 // 352 // flip the normal if we want the back side 353 // 354 if (flipclip) 355 { 356 VectorSubtract (vec3_origin, plane.normal, plane.normal); 357 plane.dist = -plane.dist; 358 } 359 360 #ifdef SEPERATORCACHE 361 stack->seperators[flipclip][stack->numseperators[flipclip]] = plane; 362 if (++stack->numseperators[flipclip] >= MAX_SEPERATORS) 363 Error("MAX_SEPERATORS"); 364 #endif 365 //MrE: fast check first 366 d = DotProduct (stack->portal->origin, plane.normal) - plane.dist; 367 //if completely at the back of the seperator plane 368 if (d < -stack->portal->radius) 369 return NULL; 370 //if completely on the front of the seperator plane 371 if (d > stack->portal->radius) 372 break; 373 374 // 375 // clip target by the seperating plane 376 // 377 target = VisChopWinding (target, stack, &plane); 378 if (!target) 379 return NULL; // target is not visible 380 381 break; // optimization by Antony Suter 382 } 383 } 384 385 return target; 386 } 387 388 /* 389 ================== 390 RecursiveLeafFlow 391 392 Flood fill through the leafs 393 If src_portal is NULL, this is the originating leaf 394 ================== 395 */ 396 void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) 397 { 398 pstack_t stack; 399 vportal_t *p; 400 plane_t backplane; 401 leaf_t *leaf; 402 int i, j, n; 403 long *test, *might, *prevmight, *vis, more; 404 int pnum; 405 406 thread->c_chains++; 407 408 leaf = &leafs[leafnum]; 409 // CheckStack (leaf, thread); 410 411 prevstack->next = &stack; 412 413 stack.next = NULL; 414 stack.leaf = leaf; 415 stack.portal = NULL; 416 stack.depth = prevstack->depth + 1; 417 418 #ifdef SEPERATORCACHE 419 stack.numseperators[0] = 0; 420 stack.numseperators[1] = 0; 421 #endif 422 423 might = (long *)stack.mightsee; 424 vis = (long *)thread->base->portalvis; 425 426 // check all portals for flowing into other leafs 427 for (i = 0; i < leaf->numportals; i++) 428 { 429 p = leaf->portals[i]; 430 if (p->removed) 431 continue; 432 pnum = p - portals; 433 434 /* MrE: portal trace debug code 435 { 436 int portaltrace[] = {13, 16, 17, 37}; 437 pstack_t *s; 438 439 s = &thread->pstack_head; 440 for (j = 0; s->next && j < sizeof(portaltrace)/sizeof(int) - 1; j++, s = s->next) 441 { 442 if (s->portal->num != portaltrace[j]) 443 break; 444 } 445 if (j >= sizeof(portaltrace)/sizeof(int) - 1) 446 { 447 if (p->num == portaltrace[j]) 448 n = 0; //traced through all the portals 449 } 450 } 451 */ 452 453 if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) 454 { 455 continue; // can't possibly see it 456 } 457 458 // if the portal can't see anything we haven't allready seen, skip it 459 if (p->status == stat_done) 460 { 461 test = (long *)p->portalvis; 462 } 463 else 464 { 465 test = (long *)p->portalflood; 466 } 467 468 more = 0; 469 prevmight = (long *)prevstack->mightsee; 470 for (j=0 ; j<portallongs ; j++) 471 { 472 might[j] = prevmight[j] & test[j]; 473 more |= (might[j] & ~vis[j]); 474 } 475 476 if (!more && 477 (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) ) 478 { // can't see anything new 479 continue; 480 } 481 482 // get plane of portal, point normal into the neighbor leaf 483 stack.portalplane = p->plane; 484 VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); 485 backplane.dist = -p->plane.dist; 486 487 // c_portalcheck++; 488 489 stack.portal = p; 490 stack.next = NULL; 491 stack.freewindings[0] = 1; 492 stack.freewindings[1] = 1; 493 stack.freewindings[2] = 1; 494 495 #if 1 496 { 497 float d; 498 499 d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); 500 d -= thread->pstack_head.portalplane.dist; 501 if (d < -p->radius) 502 { 503 continue; 504 } 505 else if (d > p->radius) 506 { 507 stack.pass = p->winding; 508 } 509 else 510 { 511 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); 512 if (!stack.pass) 513 continue; 514 } 515 } 516 #else 517 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); 518 if (!stack.pass) 519 continue; 520 #endif 521 522 523 #if 1 524 { 525 float d; 526 527 d = DotProduct (thread->base->origin, p->plane.normal); 528 d -= p->plane.dist; 529 //MrE: vis-bug fix 530 //if (d > p->radius) 531 if (d > thread->base->radius) 532 { 533 continue; 534 } 535 //MrE: vis-bug fix 536 //if (d < -p->radius) 537 else if (d < -thread->base->radius) 538 { 539 stack.source = prevstack->source; 540 } 541 else 542 { 543 stack.source = VisChopWinding (prevstack->source, &stack, &backplane); 544 //FIXME: shouldn't we create a new source origin and radius for fast checks? 545 if (!stack.source) 546 continue; 547 } 548 } 549 #else 550 stack.source = VisChopWinding (prevstack->source, &stack, &backplane); 551 if (!stack.source) 552 continue; 553 #endif 554 555 if (!prevstack->pass) 556 { // the second leaf can only be blocked if coplanar 557 558 // mark the portal as visible 559 thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); 560 561 RecursiveLeafFlow (p->leaf, thread, &stack); 562 continue; 563 } 564 565 #ifdef SEPERATORCACHE 566 if (stack.numseperators[0]) 567 { 568 for (n = 0; n < stack.numseperators[0]; n++) 569 { 570 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]); 571 if (!stack.pass) 572 break; // target is not visible 573 } 574 if (n < stack.numseperators[0]) 575 continue; 576 } 577 else 578 { 579 stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack); 580 } 581 #else 582 stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack); 583 #endif 584 if (!stack.pass) 585 continue; 586 587 #ifdef SEPERATORCACHE 588 if (stack.numseperators[1]) 589 { 590 for (n = 0; n < stack.numseperators[1]; n++) 591 { 592 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]); 593 if (!stack.pass) 594 break; // target is not visible 595 } 596 } 597 else 598 { 599 stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack); 600 } 601 #else 602 stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack); 603 #endif 604 if (!stack.pass) 605 continue; 606 607 // mark the portal as visible 608 thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); 609 610 // flow through it for real 611 RecursiveLeafFlow (p->leaf, thread, &stack); 612 // 613 stack.next = NULL; 614 } 615 } 616 617 /* 618 =============== 619 PortalFlow 620 621 generates the portalvis bit vector 622 =============== 623 */ 624 void PortalFlow (int portalnum) 625 { 626 threaddata_t data; 627 int i; 628 vportal_t *p; 629 int c_might, c_can; 630 631 #ifdef MREDEBUG 632 _printf("\r%6d", portalnum); 633 #endif 634 635 p = sorted_portals[portalnum]; 636 637 if (p->removed) 638 { 639 p->status = stat_done; 640 return; 641 } 642 643 p->status = stat_working; 644 645 c_might = CountBits (p->portalflood, numportals*2); 646 647 memset (&data, 0, sizeof(data)); 648 data.base = p; 649 650 data.pstack_head.portal = p; 651 data.pstack_head.source = p->winding; 652 data.pstack_head.portalplane = p->plane; 653 data.pstack_head.depth = 0; 654 for (i=0 ; i<portallongs ; i++) 655 ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i]; 656 657 RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); 658 659 p->status = stat_done; 660 661 c_can = CountBits (p->portalvis, numportals*2); 662 663 qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", 664 (int)(p - portals), c_might, c_can, data.c_chains); 665 } 666 667 /* 668 ================== 669 RecursivePassageFlow 670 ================== 671 */ 672 void RecursivePassageFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack) 673 { 674 pstack_t stack; 675 vportal_t *p; 676 leaf_t *leaf; 677 passage_t *passage, *nextpassage; 678 int i, j; 679 long *might, *vis, *prevmight, *cansee, *portalvis, more; 680 int pnum; 681 682 leaf = &leafs[portal->leaf]; 683 684 prevstack->next = &stack; 685 686 stack.next = NULL; 687 stack.depth = prevstack->depth + 1; 688 689 vis = (long *)thread->base->portalvis; 690 691 passage = portal->passages; 692 nextpassage = passage; 693 // check all portals for flowing into other leafs 694 for (i = 0; i < leaf->numportals; i++, passage = nextpassage) 695 { 696 p = leaf->portals[i]; 697 if ( p->removed ) { 698 continue; 699 } 700 nextpassage = passage->next; 701 pnum = p - portals; 702 703 if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) { 704 continue; // can't possibly see it 705 } 706 707 // mark the portal as visible 708 thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); 709 710 prevmight = (long *)prevstack->mightsee; 711 cansee = (long *)passage->cansee; 712 might = (long *)stack.mightsee; 713 memcpy(might, prevmight, portalbytes); 714 if (p->status == stat_done) 715 portalvis = (long *) p->portalvis; 716 else 717 portalvis = (long *) p->portalflood; 718 more = 0; 719 for (j = 0; j < portallongs; j++) 720 { 721 if (*might) 722 { 723 *might &= *cansee++ & *portalvis++; 724 more |= (*might & ~vis[j]); 725 } 726 else 727 { 728 cansee++; 729 portalvis++; 730 } 731 might++; 732 } 733 734 if ( !more ) { 735 // can't see anything new 736 continue; 737 } 738 739 // flow through it for real 740 RecursivePassageFlow(p, thread, &stack); 741 742 stack.next = NULL; 743 } 744 } 745 746 /* 747 =============== 748 PassageFlow 749 =============== 750 */ 751 void PassageFlow (int portalnum) 752 { 753 threaddata_t data; 754 int i; 755 vportal_t *p; 756 // int c_might, c_can; 757 758 #ifdef MREDEBUG 759 _printf("\r%6d", portalnum); 760 #endif 761 762 p = sorted_portals[portalnum]; 763 764 if (p->removed) 765 { 766 p->status = stat_done; 767 return; 768 } 769 770 p->status = stat_working; 771 772 // c_might = CountBits (p->portalflood, numportals*2); 773 774 memset (&data, 0, sizeof(data)); 775 data.base = p; 776 777 data.pstack_head.portal = p; 778 data.pstack_head.source = p->winding; 779 data.pstack_head.portalplane = p->plane; 780 data.pstack_head.depth = 0; 781 for (i=0 ; i<portallongs ; i++) 782 ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i]; 783 784 RecursivePassageFlow (p, &data, &data.pstack_head); 785 786 p->status = stat_done; 787 788 /* 789 c_can = CountBits (p->portalvis, numportals*2); 790 791 qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", 792 (int)(p - portals), c_might, c_can, data.c_chains); 793 */ 794 } 795 796 /* 797 ================== 798 RecursivePassagePortalFlow 799 ================== 800 */ 801 void RecursivePassagePortalFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack) 802 { 803 pstack_t stack; 804 vportal_t *p; 805 leaf_t *leaf; 806 plane_t backplane; 807 passage_t *passage, *nextpassage; 808 int i, j, n; 809 long *might, *vis, *prevmight, *cansee, *portalvis, more; 810 int pnum; 811 812 // thread->c_chains++; 813 814 leaf = &leafs[portal->leaf]; 815 // CheckStack (leaf, thread); 816 817 prevstack->next = &stack; 818 819 stack.next = NULL; 820 stack.leaf = leaf; 821 stack.portal = NULL; 822 stack.depth = prevstack->depth + 1; 823 824 #ifdef SEPERATORCACHE 825 stack.numseperators[0] = 0; 826 stack.numseperators[1] = 0; 827 #endif 828 829 vis = (long *)thread->base->portalvis; 830 831 passage = portal->passages; 832 nextpassage = passage; 833 // check all portals for flowing into other leafs 834 for (i = 0; i < leaf->numportals; i++, passage = nextpassage) 835 { 836 p = leaf->portals[i]; 837 if (p->removed) 838 continue; 839 nextpassage = passage->next; 840 pnum = p - portals; 841 842 if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) 843 continue; // can't possibly see it 844 845 prevmight = (long *)prevstack->mightsee; 846 cansee = (long *)passage->cansee; 847 might = (long *)stack.mightsee; 848 memcpy(might, prevmight, portalbytes); 849 if (p->status == stat_done) 850 portalvis = (long *) p->portalvis; 851 else 852 portalvis = (long *) p->portalflood; 853 more = 0; 854 for (j = 0; j < portallongs; j++) 855 { 856 if (*might) 857 { 858 *might &= *cansee++ & *portalvis++; 859 more |= (*might & ~vis[j]); 860 } 861 else 862 { 863 cansee++; 864 portalvis++; 865 } 866 might++; 867 } 868 869 if (!more && (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) ) 870 { // can't see anything new 871 continue; 872 } 873 874 // get plane of portal, point normal into the neighbor leaf 875 stack.portalplane = p->plane; 876 VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); 877 backplane.dist = -p->plane.dist; 878 879 // c_portalcheck++; 880 881 stack.portal = p; 882 stack.next = NULL; 883 stack.freewindings[0] = 1; 884 stack.freewindings[1] = 1; 885 stack.freewindings[2] = 1; 886 887 #if 1 888 { 889 float d; 890 891 d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); 892 d -= thread->pstack_head.portalplane.dist; 893 if (d < -p->radius) 894 { 895 continue; 896 } 897 else if (d > p->radius) 898 { 899 stack.pass = p->winding; 900 } 901 else 902 { 903 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); 904 if (!stack.pass) 905 continue; 906 } 907 } 908 #else 909 stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); 910 if (!stack.pass) 911 continue; 912 #endif 913 914 915 #if 1 916 { 917 float d; 918 919 d = DotProduct (thread->base->origin, p->plane.normal); 920 d -= p->plane.dist; 921 //MrE: vis-bug fix 922 //if (d > p->radius) 923 if (d > thread->base->radius) 924 { 925 continue; 926 } 927 //MrE: vis-bug fix 928 //if (d < -p->radius) 929 else if (d < -thread->base->radius) 930 { 931 stack.source = prevstack->source; 932 } 933 else 934 { 935 stack.source = VisChopWinding (prevstack->source, &stack, &backplane); 936 //FIXME: shouldn't we create a new source origin and radius for fast checks? 937 if (!stack.source) 938 continue; 939 } 940 } 941 #else 942 stack.source = VisChopWinding (prevstack->source, &stack, &backplane); 943 if (!stack.source) 944 continue; 945 #endif 946 947 if (!prevstack->pass) 948 { // the second leaf can only be blocked if coplanar 949 950 // mark the portal as visible 951 thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); 952 953 RecursivePassagePortalFlow (p, thread, &stack); 954 continue; 955 } 956 957 #ifdef SEPERATORCACHE 958 if (stack.numseperators[0]) 959 { 960 for (n = 0; n < stack.numseperators[0]; n++) 961 { 962 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]); 963 if (!stack.pass) 964 break; // target is not visible 965 } 966 if (n < stack.numseperators[0]) 967 continue; 968 } 969 else 970 { 971 stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack); 972 } 973 #else 974 stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack); 975 #endif 976 if (!stack.pass) 977 continue; 978 979 #ifdef SEPERATORCACHE 980 if (stack.numseperators[1]) 981 { 982 for (n = 0; n < stack.numseperators[1]; n++) 983 { 984 stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]); 985 if (!stack.pass) 986 break; // target is not visible 987 } 988 } 989 else 990 { 991 stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack); 992 } 993 #else 994 stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack); 995 #endif 996 if (!stack.pass) 997 continue; 998 999 // mark the portal as visible 1000 thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); 1001 1002 // flow through it for real 1003 RecursivePassagePortalFlow(p, thread, &stack); 1004 // 1005 stack.next = NULL; 1006 } 1007 } 1008 1009 /* 1010 =============== 1011 PassagePortalFlow 1012 =============== 1013 */ 1014 void PassagePortalFlow (int portalnum) 1015 { 1016 threaddata_t data; 1017 int i; 1018 vportal_t *p; 1019 // int c_might, c_can; 1020 1021 #ifdef MREDEBUG 1022 _printf("\r%6d", portalnum); 1023 #endif 1024 1025 p = sorted_portals[portalnum]; 1026 1027 if (p->removed) 1028 { 1029 p->status = stat_done; 1030 return; 1031 } 1032 1033 p->status = stat_working; 1034 1035 // c_might = CountBits (p->portalflood, numportals*2); 1036 1037 memset (&data, 0, sizeof(data)); 1038 data.base = p; 1039 1040 data.pstack_head.portal = p; 1041 data.pstack_head.source = p->winding; 1042 data.pstack_head.portalplane = p->plane; 1043 data.pstack_head.depth = 0; 1044 for (i=0 ; i<portallongs ; i++) 1045 ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i]; 1046 1047 RecursivePassagePortalFlow (p, &data, &data.pstack_head); 1048 1049 p->status = stat_done; 1050 1051 /* 1052 c_can = CountBits (p->portalvis, numportals*2); 1053 1054 qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", 1055 (int)(p - portals), c_might, c_can, data.c_chains); 1056 */ 1057 } 1058 1059 winding_t *PassageChopWinding (winding_t *in, winding_t *out, plane_t *split) 1060 { 1061 vec_t dists[128]; 1062 int sides[128]; 1063 int counts[3]; 1064 vec_t dot; 1065 int i, j; 1066 vec_t *p1, *p2; 1067 vec3_t mid; 1068 winding_t *neww; 1069 1070 counts[0] = counts[1] = counts[2] = 0; 1071 1072 // determine sides for each point 1073 for (i=0 ; i<in->numpoints ; i++) 1074 { 1075 dot = DotProduct (in->points[i], split->normal); 1076 dot -= split->dist; 1077 dists[i] = dot; 1078 if (dot > ON_EPSILON) 1079 sides[i] = SIDE_FRONT; 1080 else if (dot < -ON_EPSILON) 1081 sides[i] = SIDE_BACK; 1082 else 1083 { 1084 sides[i] = SIDE_ON; 1085 } 1086 counts[sides[i]]++; 1087 } 1088 1089 if (!counts[1]) 1090 return in; // completely on front side 1091 1092 if (!counts[0]) 1093 { 1094 return NULL; 1095 } 1096 1097 sides[i] = sides[0]; 1098 dists[i] = dists[0]; 1099 1100 neww = out; 1101 1102 neww->numpoints = 0; 1103 1104 for (i=0 ; i<in->numpoints ; i++) 1105 { 1106 p1 = in->points[i]; 1107 1108 if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) 1109 { 1110 return in; // can't chop -- fall back to original 1111 } 1112 1113 if (sides[i] == SIDE_ON) 1114 { 1115 VectorCopy (p1, neww->points[neww->numpoints]); 1116 neww->numpoints++; 1117 continue; 1118 } 1119 1120 if (sides[i] == SIDE_FRONT) 1121 { 1122 VectorCopy (p1, neww->points[neww->numpoints]); 1123 neww->numpoints++; 1124 } 1125 1126 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 1127 continue; 1128 1129 if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) 1130 { 1131 return in; // can't chop -- fall back to original 1132 } 1133 1134 // generate a split point 1135 p2 = in->points[(i+1)%in->numpoints]; 1136 1137 dot = dists[i] / (dists[i]-dists[i+1]); 1138 for (j=0 ; j<3 ; j++) 1139 { // avoid round off error when possible 1140 if (split->normal[j] == 1) 1141 mid[j] = split->dist; 1142 else if (split->normal[j] == -1) 1143 mid[j] = -split->dist; 1144 else 1145 mid[j] = p1[j] + dot*(p2[j]-p1[j]); 1146 } 1147 1148 VectorCopy (mid, neww->points[neww->numpoints]); 1149 neww->numpoints++; 1150 } 1151 1152 return neww; 1153 } 1154 1155 /* 1156 =============== 1157 AddSeperators 1158 =============== 1159 */ 1160 int AddSeperators (winding_t *source, winding_t *pass, qboolean flipclip, plane_t *seperators, int maxseperators) 1161 { 1162 int i, j, k, l; 1163 plane_t plane; 1164 vec3_t v1, v2; 1165 float d; 1166 vec_t length; 1167 int counts[3], numseperators; 1168 qboolean fliptest; 1169 1170 numseperators = 0; 1171 // check all combinations 1172 for (i=0 ; i<source->numpoints ; i++) 1173 { 1174 l = (i+1)%source->numpoints; 1175 VectorSubtract (source->points[l] , source->points[i], v1); 1176 1177 // find a vertex of pass that makes a plane that puts all of the 1178 // vertexes of pass on the front side and all of the vertexes of 1179 // source on the back side 1180 for (j=0 ; j<pass->numpoints ; j++) 1181 { 1182 VectorSubtract (pass->points[j], source->points[i], v2); 1183 1184 plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; 1185 plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; 1186 plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; 1187 1188 // if points don't make a valid plane, skip it 1189 1190 length = plane.normal[0] * plane.normal[0] 1191 + plane.normal[1] * plane.normal[1] 1192 + plane.normal[2] * plane.normal[2]; 1193 1194 if (length < ON_EPSILON) 1195 continue; 1196 1197 length = 1/sqrt(length); 1198 1199 plane.normal[0] *= length; 1200 plane.normal[1] *= length; 1201 plane.normal[2] *= length; 1202 1203 plane.dist = DotProduct (pass->points[j], plane.normal); 1204 1205 // 1206 // find out which side of the generated seperating plane has the 1207 // source portal 1208 // 1209 #if 1 1210 fliptest = qfalse; 1211 for (k=0 ; k<source->numpoints ; k++) 1212 { 1213 if (k == i || k == l) 1214 continue; 1215 d = DotProduct (source->points[k], plane.normal) - plane.dist; 1216 if (d < -ON_EPSILON) 1217 { // source is on the negative side, so we want all 1218 // pass and target on the positive side 1219 fliptest = qfalse; 1220 break; 1221 } 1222 else if (d > ON_EPSILON) 1223 { // source is on the positive side, so we want all 1224 // pass and target on the negative side 1225 fliptest = qtrue; 1226 break; 1227 } 1228 } 1229 if (k == source->numpoints) 1230 continue; // planar with source portal 1231 #else 1232 fliptest = flipclip; 1233 #endif 1234 // 1235 // flip the normal if the source portal is backwards 1236 // 1237 if (fliptest) 1238 { 1239 VectorSubtract (vec3_origin, plane.normal, plane.normal); 1240 plane.dist = -plane.dist; 1241 } 1242 #if 1 1243 // 1244 // if all of the pass portal points are now on the positive side, 1245 // this is the seperating plane 1246 // 1247 counts[0] = counts[1] = counts[2] = 0; 1248 for (k=0 ; k<pass->numpoints ; k++) 1249 { 1250 if (k==j) 1251 continue; 1252 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 1253 if (d < -ON_EPSILON) 1254 break; 1255 else if (d > ON_EPSILON) 1256 counts[0]++; 1257 else 1258 counts[2]++; 1259 } 1260 if (k != pass->numpoints) 1261 continue; // points on negative side, not a seperating plane 1262 1263 if (!counts[0]) 1264 continue; // planar with seperating plane 1265 #else 1266 k = (j+1)%pass->numpoints; 1267 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 1268 if (d < -ON_EPSILON) 1269 continue; 1270 k = (j+pass->numpoints-1)%pass->numpoints; 1271 d = DotProduct (pass->points[k], plane.normal) - plane.dist; 1272 if (d < -ON_EPSILON) 1273 continue; 1274 #endif 1275 // 1276 // flip the normal if we want the back side 1277 // 1278 if (flipclip) 1279 { 1280 VectorSubtract (vec3_origin, plane.normal, plane.normal); 1281 plane.dist = -plane.dist; 1282 } 1283 1284 if (numseperators >= maxseperators) 1285 Error("max seperators"); 1286 seperators[numseperators] = plane; 1287 numseperators++; 1288 break; 1289 } 1290 } 1291 return numseperators; 1292 } 1293 1294 /* 1295 =============== 1296 CreatePassages 1297 1298 MrE: create passages from one portal to all the portals in the leaf the portal leads to 1299 every passage has a cansee bit string with all the portals that can be 1300 seen through the passage 1301 =============== 1302 */ 1303 void CreatePassages(int portalnum) 1304 { 1305 int i, j, k, n, numseperators, numsee; 1306 float d; 1307 vportal_t *portal, *p, *target; 1308 leaf_t *leaf; 1309 passage_t *passage, *lastpassage; 1310 plane_t seperators[MAX_SEPERATORS*2]; 1311 winding_t *w; 1312 winding_t in, out, *res; 1313 1314 #ifdef MREDEBUG 1315 _printf("\r%6d", portalnum); 1316 #endif 1317 1318 portal = sorted_portals[portalnum]; 1319 1320 if (portal->removed) 1321 { 1322 portal->status = stat_done; 1323 return; 1324 } 1325 1326 lastpassage = NULL; 1327 leaf = &leafs[portal->leaf]; 1328 for (i = 0; i < leaf->numportals; i++) 1329 { 1330 target = leaf->portals[i]; 1331 if (target->removed) 1332 continue; 1333 1334 passage = (passage_t *) malloc(sizeof(passage_t) + portalbytes); 1335 memset(passage, 0, sizeof(passage_t) + portalbytes); 1336 numseperators = AddSeperators(portal->winding, target->winding, qfalse, seperators, MAX_SEPERATORS*2); 1337 numseperators += AddSeperators(target->winding, portal->winding, qtrue, &seperators[numseperators], MAX_SEPERATORS*2-numseperators); 1338 1339 passage->next = NULL; 1340 if (lastpassage) 1341 lastpassage->next = passage; 1342 else 1343 portal->passages = passage; 1344 lastpassage = passage; 1345 1346 numsee = 0; 1347 //create the passage->cansee 1348 for (j = 0; j < numportals * 2; j++) 1349 { 1350 p = &portals[j]; 1351 if (p->removed) 1352 continue; 1353 if ( ! (target->portalflood[j >> 3] & (1<<(j&7)) ) ) 1354 continue; 1355 if ( ! (portal->portalflood[j >> 3] & (1<<(j&7)) ) ) 1356 continue; 1357 for (k = 0; k < numseperators; k++) 1358 { 1359 // 1360 d = DotProduct (p->origin, seperators[k].normal) - seperators[k].dist; 1361 //if completely at the back of the seperator plane 1362 if (d < -p->radius + ON_EPSILON) 1363 break; 1364 w = p->winding; 1365 for (n = 0; n < w->numpoints; n++) 1366 { 1367 d = DotProduct (w->points[n], seperators[k].normal) - seperators[k].dist; 1368 //if at the front of the seperator 1369 if (d > ON_EPSILON) 1370 break; 1371 } 1372 //if no points are at the front of the seperator 1373 if (n >= w->numpoints) 1374 break; 1375 } 1376 if (k < numseperators) 1377 continue; 1378 memcpy(&in, p->winding, sizeof(winding_t)); 1379 for (k = 0; k < numseperators; k++) 1380 { 1381 res = PassageChopWinding(&in, &out, &seperators[k]); 1382 if (res == &out) 1383 memcpy(&in, &out, sizeof(winding_t)); 1384 if (res == NULL) 1385 break; 1386 } 1387 if (k < numseperators) 1388 continue; 1389 passage->cansee[j >> 3] |= (1<<(j&7)); 1390 numsee++; 1391 } 1392 } 1393 } 1394 1395 void PassageMemory(void) 1396 { 1397 int i, j, totalmem, totalportals; 1398 vportal_t *portal, *target; 1399 leaf_t *leaf; 1400 1401 totalmem = 0; 1402 totalportals = 0; 1403 for (i = 0; i < numportals; i++) 1404 { 1405 portal = sorted_portals[i]; 1406 if (portal->removed) 1407 continue; 1408 leaf = &leafs[portal->leaf]; 1409 for (j = 0; j < leaf->numportals; j++) 1410 { 1411 target = leaf->portals[j]; 1412 if (target->removed) 1413 continue; 1414 totalmem += sizeof(passage_t) + portalbytes; 1415 totalportals++; 1416 } 1417 } 1418 _printf("%7i average number of passages per leaf\n", totalportals / numportals); 1419 _printf("%7i MB required passage memory\n", totalmem >> 10 >> 10); 1420 } 1421 1422 /* 1423 =============================================================================== 1424 1425 This is a rough first-order aproximation that is used to trivially reject some 1426 of the final calculations. 1427 1428 1429 Calculates portalfront and portalflood bit vectors 1430 1431 thinking about: 1432 1433 typedef struct passage_s 1434 { 1435 struct passage_s *next; 1436 struct portal_s *to; 1437 stryct sep_s *seperators; 1438 byte *mightsee; 1439 } passage_t; 1440 1441 typedef struct portal_s 1442 { 1443 struct passage_s *passages; 1444 int leaf; // leaf portal faces into 1445 } portal_s; 1446 1447 leaf = portal->leaf 1448 clear 1449 for all portals 1450 1451 1452 calc portal visibility 1453 clear bit vector 1454 for all passages 1455 passage visibility 1456 1457 1458 for a portal to be visible to a passage, it must be on the front of 1459 all seperating planes, and both portals must be behind the new portal 1460 1461 =============================================================================== 1462 */ 1463 1464 int c_flood, c_vis; 1465 1466 1467 /* 1468 ================== 1469 SimpleFlood 1470 1471 ================== 1472 */ 1473 void SimpleFlood (vportal_t *srcportal, int leafnum) 1474 { 1475 int i; 1476 leaf_t *leaf; 1477 vportal_t *p; 1478 int pnum; 1479 1480 leaf = &leafs[leafnum]; 1481 1482 for (i=0 ; i<leaf->numportals ; i++) 1483 { 1484 p = leaf->portals[i]; 1485 if (p->removed) 1486 continue; 1487 pnum = p - portals; 1488 if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) ) 1489 continue; 1490 1491 if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) ) 1492 continue; 1493 1494 srcportal->portalflood[pnum>>3] |= (1<<(pnum&7)); 1495 1496 SimpleFlood (srcportal, p->leaf); 1497 } 1498 } 1499 1500 /* 1501 ============== 1502 BasePortalVis 1503 ============== 1504 */ 1505 void BasePortalVis (int portalnum) 1506 { 1507 int j, k; 1508 vportal_t *tp, *p; 1509 float d; 1510 winding_t *w; 1511 1512 p = portals+portalnum; 1513 1514 if (p->removed) 1515 return; 1516 1517 p->portalfront = malloc (portalbytes); 1518 memset (p->portalfront, 0, portalbytes); 1519 1520 p->portalflood = malloc (portalbytes); 1521 memset (p->portalflood, 0, portalbytes); 1522 1523 p->portalvis = malloc (portalbytes); 1524 memset (p->portalvis, 0, portalbytes); 1525 1526 for (j=0, tp = portals ; j<numportals*2 ; j++, tp++) 1527 { 1528 if (j == portalnum) 1529 continue; 1530 if (tp->removed) 1531 continue; 1532 /* 1533 if (farplanedist >= 0) 1534 { 1535 vec3_t dir; 1536 VectorSubtract(p->origin, tp->origin, dir); 1537 if (VectorLength(dir) > farplanedist - p->radius - tp->radius) 1538 continue; 1539 } 1540 */ 1541 w = tp->winding; 1542 for (k=0 ; k<w->numpoints ; k++) 1543 { 1544 d = DotProduct (w->points[k], p->plane.normal) 1545 - p->plane.dist; 1546 if (d > ON_EPSILON) 1547 break; 1548 } 1549 if (k == w->numpoints) 1550 continue; // no points on front 1551 1552 w = p->winding; 1553 for (k=0 ; k<w->numpoints ; k++) 1554 { 1555 d = DotProduct (w->points[k], tp->plane.normal) 1556 - tp->plane.dist; 1557 if (d < -ON_EPSILON) 1558 break; 1559 } 1560 if (k == w->numpoints) 1561 continue; // no points on front 1562 1563 p->portalfront[j>>3] |= (1<<(j&7)); 1564 } 1565 1566 SimpleFlood (p, p->leaf); 1567 1568 p->nummightsee = CountBits (p->portalflood, numportals*2); 1569 // _printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee); 1570 c_flood += p->nummightsee; 1571 } 1572 1573 1574 1575 1576 1577 /* 1578 =============================================================================== 1579 1580 This is a second order aproximation 1581 1582 Calculates portalvis bit vector 1583 1584 WAAAAAAY too slow. 1585 1586 =============================================================================== 1587 */ 1588 1589 /* 1590 ================== 1591 RecursiveLeafBitFlow 1592 1593 ================== 1594 */ 1595 void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee) 1596 { 1597 vportal_t *p; 1598 leaf_t *leaf; 1599 int i, j; 1600 long more; 1601 int pnum; 1602 byte newmight[MAX_PORTALS/8]; 1603 1604 leaf = &leafs[leafnum]; 1605 1606 // check all portals for flowing into other leafs 1607 for (i=0 ; i<leaf->numportals ; i++) 1608 { 1609 p = leaf->portals[i]; 1610 if (p->removed) 1611 continue; 1612 pnum = p - portals; 1613 1614 // if some previous portal can't see it, skip 1615 if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) ) 1616 continue; 1617 1618 // if this portal can see some portals we mightsee, recurse 1619 more = 0; 1620 for (j=0 ; j<portallongs ; j++) 1621 { 1622 ((long *)newmight)[j] = ((long *)mightsee)[j] 1623 & ((long *)p->portalflood)[j]; 1624 more |= ((long *)newmight)[j] & ~((long *)cansee)[j]; 1625 } 1626 1627 if (!more) 1628 continue; // can't see anything new 1629 1630 cansee[pnum>>3] |= (1<<(pnum&7)); 1631 1632 RecursiveLeafBitFlow (p->leaf, newmight, cansee); 1633 } 1634 } 1635 1636 /* 1637 ============== 1638 BetterPortalVis 1639 ============== 1640 */ 1641 void BetterPortalVis (int portalnum) 1642 { 1643 vportal_t *p; 1644 1645 p = portals+portalnum; 1646 1647 if (p->removed) 1648 return; 1649 1650 RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis); 1651 1652 // build leaf vis information 1653 p->nummightsee = CountBits (p->portalvis, numportals*2); 1654 c_vis += p->nummightsee; 1655 } 1656 1657