vis.c (25165B)
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 // vis.c 23 24 #include "vis.h" 25 #include "threads.h" 26 #include "stdlib.h" 27 #ifdef _WIN32 28 #include "../libs/pakstuff.h" 29 #endif 30 31 32 #define VIS_HEADER_SIZE 8 33 34 extern char outbase[32]; 35 36 int numportals; 37 int portalclusters; 38 int numfaces; 39 40 char inbase[32]; 41 42 vportal_t *portals; 43 leaf_t *leafs; 44 45 vportal_t *faces; 46 leaf_t *faceleafs; 47 48 int c_portaltest, c_portalpass, c_portalcheck; 49 50 int leafbytes; // (portalclusters+63)>>3 51 int leaflongs; 52 53 int portalbytes, portallongs; 54 55 qboolean fastvis; 56 qboolean noPassageVis; 57 qboolean passageVisOnly; 58 qboolean mergevis; 59 qboolean nosort; 60 qboolean saveprt; 61 62 int testlevel = 2; 63 64 int totalvis; 65 66 vportal_t *sorted_portals[MAX_MAP_PORTALS*2]; 67 68 void PassageMemory(void); 69 70 71 //============================================================================= 72 73 void PlaneFromWinding (winding_t *w, plane_t *plane) 74 { 75 vec3_t v1, v2; 76 77 // calc plane 78 VectorSubtract (w->points[2], w->points[1], v1); 79 VectorSubtract (w->points[0], w->points[1], v2); 80 CrossProduct (v2, v1, plane->normal); 81 VectorNormalize (plane->normal, plane->normal); 82 plane->dist = DotProduct (w->points[0], plane->normal); 83 } 84 85 86 /* 87 ================== 88 NewWinding 89 ================== 90 */ 91 winding_t *NewWinding (int points) 92 { 93 winding_t *w; 94 int size; 95 96 if (points > MAX_POINTS_ON_WINDING) 97 Error ("NewWinding: %i points", points); 98 99 size = (int)((winding_t *)0)->points[points]; 100 w = malloc (size); 101 memset (w, 0, size); 102 103 return w; 104 } 105 106 107 108 void prl(leaf_t *l) 109 { 110 int i; 111 vportal_t *p; 112 plane_t pl; 113 114 for (i=0 ; i<l->numportals ; i++) 115 { 116 p = l->portals[i]; 117 pl = p->plane; 118 _printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); 119 } 120 } 121 122 123 //============================================================================= 124 125 /* 126 ============= 127 SortPortals 128 129 Sorts the portals from the least complex, so the later ones can reuse 130 the earlier information. 131 ============= 132 */ 133 int PComp (const void *a, const void *b) 134 { 135 if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee) 136 return 0; 137 if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee) 138 return -1; 139 return 1; 140 } 141 void SortPortals (void) 142 { 143 int i; 144 145 for (i=0 ; i<numportals*2 ; i++) 146 sorted_portals[i] = &portals[i]; 147 148 if (nosort) 149 return; 150 qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp); 151 } 152 153 154 /* 155 ============== 156 LeafVectorFromPortalVector 157 ============== 158 */ 159 int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits) 160 { 161 int i, j, leafnum; 162 vportal_t *p; 163 int c_leafs; 164 165 166 for (i=0 ; i<numportals*2 ; i++) 167 { 168 if (portalbits[i>>3] & (1<<(i&7)) ) 169 { 170 p = portals+i; 171 leafbits[p->leaf>>3] |= (1<<(p->leaf&7)); 172 } 173 } 174 175 for (j = 0; j < portalclusters; j++) 176 { 177 leafnum = j; 178 while (leafs[leafnum].merged >= 0) 179 leafnum = leafs[leafnum].merged; 180 //if the merged leaf is visible then the original leaf is visible 181 if (leafbits[leafnum>>3] & (1<<(leafnum&7))) 182 { 183 leafbits[j>>3] |= (1<<(j&7)); 184 } 185 } 186 187 c_leafs = CountBits (leafbits, portalclusters); 188 189 return c_leafs; 190 } 191 192 193 /* 194 =============== 195 ClusterMerge 196 197 Merges the portal visibility for a leaf 198 =============== 199 */ 200 void ClusterMerge (int leafnum) 201 { 202 leaf_t *leaf; 203 byte portalvector[MAX_PORTALS/8]; 204 byte uncompressed[MAX_MAP_LEAFS/8]; 205 int i, j; 206 int numvis, mergedleafnum; 207 vportal_t *p; 208 int pnum; 209 210 // OR together all the portalvis bits 211 212 mergedleafnum = leafnum; 213 while(leafs[mergedleafnum].merged >= 0) 214 mergedleafnum = leafs[mergedleafnum].merged; 215 216 memset (portalvector, 0, portalbytes); 217 leaf = &leafs[mergedleafnum]; 218 for (i = 0; i < leaf->numportals; i++) 219 { 220 p = leaf->portals[i]; 221 if (p->removed) 222 continue; 223 224 if (p->status != stat_done) 225 Error ("portal not done"); 226 for (j=0 ; j<portallongs ; j++) 227 ((long *)portalvector)[j] |= ((long *)p->portalvis)[j]; 228 pnum = p - portals; 229 portalvector[pnum>>3] |= 1<<(pnum&7); 230 } 231 232 memset (uncompressed, 0, leafbytes); 233 234 uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7)); 235 // convert portal bits to leaf bits 236 numvis = LeafVectorFromPortalVector (portalvector, uncompressed); 237 238 // if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) 239 // _printf ("WARNING: Leaf portals saw into leaf\n"); 240 241 // uncompressed[leafnum>>3] |= (1<<(leafnum&7)); 242 243 numvis++; // count the leaf itself 244 245 totalvis += numvis; 246 247 qprintf ("cluster %4i : %4i visible\n", leafnum, numvis); 248 249 memcpy (visBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes); 250 } 251 252 /* 253 ================== 254 CalcPortalVis 255 ================== 256 */ 257 void CalcPortalVis (void) 258 { 259 #ifdef MREDEBUG 260 _printf("%6d portals out of %d", 0, numportals*2); 261 //get rid of the counter 262 RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow); 263 #else 264 RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow); 265 #endif 266 267 } 268 269 /* 270 ================== 271 CalcPassageVis 272 ================== 273 */ 274 void CalcPassageVis(void) 275 { 276 PassageMemory(); 277 278 #ifdef MREDEBUG 279 _printf("%6d portals out of %d", 0, numportals*2); 280 RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages); 281 _printf("\n"); 282 _printf("%6d portals out of %d", 0, numportals*2); 283 RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow); 284 _printf("\n"); 285 #else 286 RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages); 287 RunThreadsOnIndividual (numportals*2, qtrue, PassageFlow); 288 #endif 289 } 290 291 /* 292 ================== 293 CalcPassagePortalVis 294 ================== 295 */ 296 void CalcPassagePortalVis(void) 297 { 298 PassageMemory(); 299 300 #ifdef MREDEBUG 301 _printf("%6d portals out of %d", 0, numportals*2); 302 RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages); 303 _printf("\n"); 304 _printf("%6d portals out of %d", 0, numportals*2); 305 RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow); 306 _printf("\n"); 307 #else 308 RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages); 309 RunThreadsOnIndividual (numportals*2, qtrue, PassagePortalFlow); 310 #endif 311 } 312 313 /* 314 ================== 315 CalcFastVis 316 ================== 317 */ 318 void CalcFastVis(void) 319 { 320 int i; 321 322 // fastvis just uses mightsee for a very loose bound 323 for (i=0 ; i<numportals*2 ; i++) 324 { 325 portals[i].portalvis = portals[i].portalflood; 326 portals[i].status = stat_done; 327 } 328 } 329 330 /* 331 ================== 332 CalcVis 333 ================== 334 */ 335 void CalcVis (void) 336 { 337 int i; 338 339 RunThreadsOnIndividual (numportals*2, qtrue, BasePortalVis); 340 341 // RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis); 342 343 SortPortals (); 344 345 if (fastvis) { 346 CalcFastVis(); 347 } 348 else if ( noPassageVis ) { 349 CalcPortalVis(); 350 } 351 else if ( passageVisOnly ) { 352 CalcPassageVis(); 353 } 354 else { 355 CalcPassagePortalVis(); 356 } 357 // 358 // assemble the leaf vis lists by oring and compressing the portal lists 359 // 360 _printf("creating leaf vis...\n"); 361 for (i=0 ; i<portalclusters ; i++) 362 ClusterMerge (i); 363 364 _printf( "Total visible clusters: %i\n", totalvis ); 365 _printf( "Average clusters visible: %i\n", totalvis / portalclusters ); 366 } 367 368 /* 369 ================== 370 SetPortalSphere 371 ================== 372 */ 373 void SetPortalSphere (vportal_t *p) 374 { 375 int i; 376 vec3_t total, dist; 377 winding_t *w; 378 float r, bestr; 379 380 w = p->winding; 381 VectorCopy (vec3_origin, total); 382 for (i=0 ; i<w->numpoints ; i++) 383 { 384 VectorAdd (total, w->points[i], total); 385 } 386 387 for (i=0 ; i<3 ; i++) 388 total[i] /= w->numpoints; 389 390 bestr = 0; 391 for (i=0 ; i<w->numpoints ; i++) 392 { 393 VectorSubtract (w->points[i], total, dist); 394 r = VectorLength (dist); 395 if (r > bestr) 396 bestr = r; 397 } 398 VectorCopy (total, p->origin); 399 p->radius = bestr; 400 } 401 402 /* 403 ============= 404 Winding_PlanesConcave 405 ============= 406 */ 407 #define WCONVEX_EPSILON 0.2 408 409 int Winding_PlanesConcave(winding_t *w1, winding_t *w2, 410 vec3_t normal1, vec3_t normal2, 411 float dist1, float dist2) 412 { 413 int i; 414 415 if (!w1 || !w2) return qfalse; 416 417 // check if one of the points of winding 1 is at the front of the plane of winding 2 418 for (i = 0; i < w1->numpoints; i++) 419 { 420 if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue; 421 } 422 // check if one of the points of winding 2 is at the front of the plane of winding 1 423 for (i = 0; i < w2->numpoints; i++) 424 { 425 if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue; 426 } 427 428 return qfalse; 429 } 430 431 /* 432 ============ 433 TryMergeLeaves 434 ============ 435 */ 436 int TryMergeLeaves(int l1num, int l2num) 437 { 438 int i, j, k, n, numportals; 439 plane_t plane1, plane2; 440 leaf_t *l1, *l2; 441 vportal_t *p1, *p2; 442 vportal_t *portals[MAX_PORTALS_ON_LEAF]; 443 444 for (k = 0; k < 2; k++) 445 { 446 if (k) l1 = &leafs[l1num]; 447 else l1 = &faceleafs[l1num]; 448 for (i = 0; i < l1->numportals; i++) 449 { 450 p1 = l1->portals[i]; 451 if (p1->leaf == l2num) continue; 452 for (n = 0; n < 2; n++) 453 { 454 if (n) l2 = &leafs[l2num]; 455 else l2 = &faceleafs[l2num]; 456 for (j = 0; j < l2->numportals; j++) 457 { 458 p2 = l2->portals[j]; 459 if (p2->leaf == l1num) continue; 460 // 461 plane1 = p1->plane; 462 plane2 = p2->plane; 463 if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist)) 464 return qfalse; 465 } 466 } 467 } 468 } 469 for (k = 0; k < 2; k++) 470 { 471 if (k) 472 { 473 l1 = &leafs[l1num]; 474 l2 = &leafs[l2num]; 475 } 476 else 477 { 478 l1 = &faceleafs[l1num]; 479 l2 = &faceleafs[l2num]; 480 } 481 numportals = 0; 482 //the leaves can be merged now 483 for (i = 0; i < l1->numportals; i++) 484 { 485 p1 = l1->portals[i]; 486 if (p1->leaf == l2num) 487 { 488 p1->removed = qtrue; 489 continue; 490 } 491 portals[numportals++] = p1; 492 } 493 for (j = 0; j < l2->numportals; j++) 494 { 495 p2 = l2->portals[j]; 496 if (p2->leaf == l1num) 497 { 498 p2->removed = qtrue; 499 continue; 500 } 501 portals[numportals++] = p2; 502 } 503 for (i = 0; i < numportals; i++) 504 { 505 l2->portals[i] = portals[i]; 506 } 507 l2->numportals = numportals; 508 l1->merged = l2num; 509 } 510 return qtrue; 511 } 512 513 /* 514 ============ 515 UpdatePortals 516 ============ 517 */ 518 void UpdatePortals(void) 519 { 520 int i; 521 vportal_t *p; 522 523 for (i = 0; i < numportals * 2; i++) 524 { 525 p = &portals[i]; 526 if (p->removed) 527 continue; 528 while(leafs[p->leaf].merged >= 0) 529 p->leaf = leafs[p->leaf].merged; 530 } 531 } 532 533 /* 534 ============ 535 MergeLeaves 536 537 try to merge leaves but don't merge through hint splitters 538 ============ 539 */ 540 void MergeLeaves(void) 541 { 542 int i, j, nummerges, totalnummerges; 543 leaf_t *leaf; 544 vportal_t *p; 545 546 totalnummerges = 0; 547 do 548 { 549 nummerges = 0; 550 for (i = 0; i < portalclusters; i++) 551 { 552 leaf = &leafs[i]; 553 //if this leaf is merged already 554 if (leaf->merged >= 0) 555 continue; 556 // 557 for (j = 0; j < leaf->numportals; j++) 558 { 559 p = leaf->portals[j]; 560 // 561 if (p->removed) 562 continue; 563 //never merge through hint portals 564 if (p->hint) 565 continue; 566 if (TryMergeLeaves(i, p->leaf)) 567 { 568 UpdatePortals(); 569 nummerges++; 570 break; 571 } 572 } 573 } 574 totalnummerges += nummerges; 575 } while (nummerges); 576 _printf("%6d leaves merged\n", totalnummerges); 577 } 578 579 /* 580 ============ 581 TryMergeWinding 582 ============ 583 */ 584 #define CONTINUOUS_EPSILON 0.005 585 586 winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal) 587 { 588 vec_t *p1, *p2, *p3, *p4, *back; 589 winding_t *newf; 590 int i, j, k, l; 591 vec3_t normal, delta; 592 vec_t dot; 593 qboolean keep1, keep2; 594 595 596 // 597 // find a common edge 598 // 599 p1 = p2 = NULL; // stop compiler warning 600 j = 0; // 601 602 for (i = 0; i < f1->numpoints; i++) 603 { 604 p1 = f1->points[i]; 605 p2 = f1->points[(i+1) % f1->numpoints]; 606 for (j = 0; j < f2->numpoints; j++) 607 { 608 p3 = f2->points[j]; 609 p4 = f2->points[(j+1) % f2->numpoints]; 610 for (k = 0; k < 3; k++) 611 { 612 if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME 613 break; 614 if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME 615 break; 616 } //end for 617 if (k==3) 618 break; 619 } //end for 620 if (j < f2->numpoints) 621 break; 622 } //end for 623 624 if (i == f1->numpoints) 625 return NULL; // no matching edges 626 627 // 628 // check slope of connected lines 629 // if the slopes are colinear, the point can be removed 630 // 631 back = f1->points[(i+f1->numpoints-1)%f1->numpoints]; 632 VectorSubtract (p1, back, delta); 633 CrossProduct (planenormal, delta, normal); 634 VectorNormalize (normal, normal); 635 636 back = f2->points[(j+2)%f2->numpoints]; 637 VectorSubtract (back, p1, delta); 638 dot = DotProduct (delta, normal); 639 if (dot > CONTINUOUS_EPSILON) 640 return NULL; // not a convex polygon 641 keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); 642 643 back = f1->points[(i+2)%f1->numpoints]; 644 VectorSubtract (back, p2, delta); 645 CrossProduct (planenormal, delta, normal); 646 VectorNormalize (normal, normal); 647 648 back = f2->points[(j+f2->numpoints-1)%f2->numpoints]; 649 VectorSubtract (back, p2, delta); 650 dot = DotProduct (delta, normal); 651 if (dot > CONTINUOUS_EPSILON) 652 return NULL; // not a convex polygon 653 keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); 654 655 // 656 // build the new polygon 657 // 658 newf = NewWinding (f1->numpoints + f2->numpoints); 659 660 // copy first polygon 661 for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) 662 { 663 if (k==(i+1)%f1->numpoints && !keep2) 664 continue; 665 666 VectorCopy (f1->points[k], newf->points[newf->numpoints]); 667 newf->numpoints++; 668 } 669 670 // copy second polygon 671 for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) 672 { 673 if (l==(j+1)%f2->numpoints && !keep1) 674 continue; 675 VectorCopy (f2->points[l], newf->points[newf->numpoints]); 676 newf->numpoints++; 677 } 678 679 return newf; 680 } 681 682 /* 683 ============ 684 MergeLeafPortals 685 ============ 686 */ 687 void MergeLeafPortals(void) 688 { 689 int i, j, k, nummerges, hintsmerged; 690 leaf_t *leaf; 691 vportal_t *p1, *p2; 692 winding_t *w; 693 694 nummerges = 0; 695 hintsmerged = 0; 696 for (i = 0; i < portalclusters; i++) 697 { 698 leaf = &leafs[i]; 699 if (leaf->merged >= 0) continue; 700 for (j = 0; j < leaf->numportals; j++) 701 { 702 p1 = leaf->portals[j]; 703 if (p1->removed) 704 continue; 705 for (k = j+1; k < leaf->numportals; k++) 706 { 707 p2 = leaf->portals[k]; 708 if (p2->removed) 709 continue; 710 if (p1->leaf == p2->leaf) 711 { 712 w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal); 713 if (w) 714 { 715 FreeWinding(p1->winding); 716 p1->winding = w; 717 if (p1->hint && p2->hint) 718 hintsmerged++; 719 p1->hint |= p2->hint; 720 SetPortalSphere(p1); 721 p2->removed = qtrue; 722 nummerges++; 723 i--; 724 break; 725 } 726 } 727 } 728 if (k < leaf->numportals) 729 break; 730 } 731 } 732 _printf("%6d portals merged\n", nummerges); 733 _printf("%6d hint portals merged\n", hintsmerged); 734 } 735 736 737 /* 738 ============ 739 WritePortals 740 ============ 741 */ 742 int CountActivePortals(void) 743 { 744 int num, hints, j; 745 vportal_t *p; 746 747 num = 0; 748 hints = 0; 749 for (j = 0; j < numportals * 2; j++) 750 { 751 p = portals + j; 752 if (p->removed) 753 continue; 754 if (p->hint) 755 hints++; 756 num++; 757 } 758 _printf("%6d active portals\n", num); 759 _printf("%6d hint portals\n", hints); 760 return num; 761 } 762 763 /* 764 ============ 765 WritePortals 766 ============ 767 */ 768 void WriteFloat (FILE *f, vec_t v); 769 770 void WritePortals(char *filename) 771 { 772 int i, j, num; 773 FILE *pf; 774 vportal_t *p; 775 winding_t *w; 776 777 // write the file 778 pf = fopen (filename, "w"); 779 if (!pf) 780 Error ("Error opening %s", filename); 781 782 num = 0; 783 for (j = 0; j < numportals * 2; j++) 784 { 785 p = portals + j; 786 if (p->removed) 787 continue; 788 // if (!p->hint) 789 // continue; 790 num++; 791 } 792 793 fprintf (pf, "%s\n", PORTALFILE); 794 fprintf (pf, "%i\n", 0); 795 fprintf (pf, "%i\n", num);// + numfaces); 796 fprintf (pf, "%i\n", 0); 797 798 for (j = 0; j < numportals * 2; j++) 799 { 800 p = portals + j; 801 if (p->removed) 802 continue; 803 // if (!p->hint) 804 // continue; 805 w = p->winding; 806 fprintf (pf,"%i %i %i ",w->numpoints, 0, 0); 807 fprintf (pf, "%d ", p->hint); 808 for (i=0 ; i<w->numpoints ; i++) 809 { 810 fprintf (pf,"("); 811 WriteFloat (pf, w->points[i][0]); 812 WriteFloat (pf, w->points[i][1]); 813 WriteFloat (pf, w->points[i][2]); 814 fprintf (pf,") "); 815 } 816 fprintf (pf,"\n"); 817 } 818 819 /* 820 for (j = 0; j < numfaces; j++) 821 { 822 p = faces + j; 823 w = p->winding; 824 fprintf (pf,"%i %i %i ",w->numpoints, 0, 0); 825 fprintf (pf, "0 "); 826 for (i=0 ; i<w->numpoints ; i++) 827 { 828 fprintf (pf,"("); 829 WriteFloat (pf, w->points[i][0]); 830 WriteFloat (pf, w->points[i][1]); 831 WriteFloat (pf, w->points[i][2]); 832 fprintf (pf,") "); 833 } 834 fprintf (pf,"\n"); 835 }*/ 836 837 fclose (pf); 838 } 839 840 /* 841 ============ 842 LoadPortals 843 ============ 844 */ 845 void LoadPortals (char *name) 846 { 847 int i, j, hint; 848 vportal_t *p; 849 leaf_t *l; 850 char magic[80]; 851 FILE *f; 852 int numpoints; 853 winding_t *w; 854 int leafnums[2]; 855 plane_t plane; 856 857 if (!strcmp(name,"-")) 858 f = stdin; 859 else 860 { 861 f = fopen(name, "r"); 862 if (!f) 863 Error ("LoadPortals: couldn't read %s\n",name); 864 } 865 866 if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4) 867 Error ("LoadPortals: failed to read header"); 868 if (strcmp(magic,PORTALFILE)) 869 Error ("LoadPortals: not a portal file"); 870 871 _printf ("%6i portalclusters\n", portalclusters); 872 _printf ("%6i numportals\n", numportals); 873 _printf ("%6i numfaces\n", numfaces); 874 875 // these counts should take advantage of 64 bit systems automatically 876 leafbytes = ((portalclusters+63)&~63)>>3; 877 leaflongs = leafbytes/sizeof(long); 878 879 portalbytes = ((numportals*2+63)&~63)>>3; 880 portallongs = portalbytes/sizeof(long); 881 882 // each file portal is split into two memory portals 883 portals = malloc(2*numportals*sizeof(vportal_t)); 884 memset (portals, 0, 2*numportals*sizeof(vportal_t)); 885 886 leafs = malloc(portalclusters*sizeof(leaf_t)); 887 memset (leafs, 0, portalclusters*sizeof(leaf_t)); 888 889 for (i = 0; i < portalclusters; i++) 890 leafs[i].merged = -1; 891 892 numVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes; 893 894 ((int *)visBytes)[0] = portalclusters; 895 ((int *)visBytes)[1] = leafbytes; 896 897 for (i=0, p=portals ; i<numportals ; i++) 898 { 899 if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3) 900 Error ("LoadPortals: reading portal %i", i); 901 if (numpoints > MAX_POINTS_ON_WINDING) 902 Error ("LoadPortals: portal %i has too many points", i); 903 if ( (unsigned)leafnums[0] > portalclusters 904 || (unsigned)leafnums[1] > portalclusters) 905 Error ("LoadPortals: reading portal %i", i); 906 if (fscanf (f, "%i ", &hint) != 1) 907 Error ("LoadPortals: reading hint state"); 908 909 w = p->winding = NewWinding (numpoints); 910 w->numpoints = numpoints; 911 912 for (j=0 ; j<numpoints ; j++) 913 { 914 double v[3]; 915 int k; 916 917 // scanf into double, then assign to vec_t 918 // so we don't care what size vec_t is 919 if (fscanf (f, "(%lf %lf %lf ) " 920 , &v[0], &v[1], &v[2]) != 3) 921 Error ("LoadPortals: reading portal %i", i); 922 for (k=0 ; k<3 ; k++) 923 w->points[j][k] = v[k]; 924 } 925 fscanf (f, "\n"); 926 927 // calc plane 928 PlaneFromWinding (w, &plane); 929 930 // create forward portal 931 l = &leafs[leafnums[0]]; 932 if (l->numportals == MAX_PORTALS_ON_LEAF) 933 Error ("Leaf with too many portals"); 934 l->portals[l->numportals] = p; 935 l->numportals++; 936 937 p->num = i+1; 938 p->hint = hint; 939 p->winding = w; 940 VectorSubtract (vec3_origin, plane.normal, p->plane.normal); 941 p->plane.dist = -plane.dist; 942 p->leaf = leafnums[1]; 943 SetPortalSphere (p); 944 p++; 945 946 // create backwards portal 947 l = &leafs[leafnums[1]]; 948 if (l->numportals == MAX_PORTALS_ON_LEAF) 949 Error ("Leaf with too many portals"); 950 l->portals[l->numportals] = p; 951 l->numportals++; 952 953 p->num = i+1; 954 p->hint = hint; 955 p->winding = NewWinding(w->numpoints); 956 p->winding->numpoints = w->numpoints; 957 for (j=0 ; j<w->numpoints ; j++) 958 { 959 VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); 960 } 961 962 p->plane = plane; 963 p->leaf = leafnums[0]; 964 SetPortalSphere (p); 965 p++; 966 967 } 968 969 faces = malloc(2*numfaces*sizeof(vportal_t)); 970 memset (faces, 0, 2*numfaces*sizeof(vportal_t)); 971 972 faceleafs = malloc(portalclusters*sizeof(leaf_t)); 973 memset(faceleafs, 0, portalclusters*sizeof(leaf_t)); 974 975 for (i = 0, p = faces; i < numfaces; i++) 976 { 977 if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2) 978 Error ("LoadPortals: reading portal %i", i); 979 980 w = p->winding = NewWinding (numpoints); 981 w->numpoints = numpoints; 982 983 for (j=0 ; j<numpoints ; j++) 984 { 985 double v[3]; 986 int k; 987 988 // scanf into double, then assign to vec_t 989 // so we don't care what size vec_t is 990 if (fscanf (f, "(%lf %lf %lf ) " 991 , &v[0], &v[1], &v[2]) != 3) 992 Error ("LoadPortals: reading portal %i", i); 993 for (k=0 ; k<3 ; k++) 994 w->points[j][k] = v[k]; 995 } 996 fscanf (f, "\n"); 997 998 // calc plane 999 PlaneFromWinding (w, &plane); 1000 1001 l = &faceleafs[leafnums[0]]; 1002 l->merged = -1; 1003 if (l->numportals == MAX_PORTALS_ON_LEAF) 1004 Error ("Leaf with too many faces"); 1005 l->portals[l->numportals] = p; 1006 l->numportals++; 1007 1008 p->num = i+1; 1009 p->winding = w; 1010 // normal pointing out of the leaf 1011 VectorSubtract (vec3_origin, plane.normal, p->plane.normal); 1012 p->plane.dist = -plane.dist; 1013 p->leaf = -1; 1014 SetPortalSphere (p); 1015 p++; 1016 } 1017 1018 fclose (f); 1019 } 1020 1021 1022 /* 1023 ================ 1024 CalcPHS 1025 1026 Calculate the PHS (Potentially Hearable Set) 1027 by ORing together all the PVS visible from a leaf 1028 ================ 1029 */ 1030 void CalcPHS (void) 1031 { 1032 int i, j, k, l, index; 1033 int bitbyte; 1034 long *dest, *src; 1035 byte *scan; 1036 int count; 1037 byte uncompressed[MAX_MAP_LEAFS/8]; 1038 1039 _printf ("Building PHS...\n"); 1040 1041 count = 0; 1042 for (i=0 ; i<portalclusters ; i++) 1043 { 1044 scan = visBytes + i*leafbytes; 1045 memcpy (uncompressed, scan, leafbytes); 1046 for (j=0 ; j<leafbytes ; j++) 1047 { 1048 bitbyte = scan[j]; 1049 if (!bitbyte) 1050 continue; 1051 for (k=0 ; k<8 ; k++) 1052 { 1053 if (! (bitbyte & (1<<k)) ) 1054 continue; 1055 // OR this pvs row into the phs 1056 index = ((j<<3)+k); 1057 if (index >= portalclusters) 1058 Error ("Bad bit in PVS"); // pad bits should be 0 1059 src = (long *)(visBytes + index*leafbytes); 1060 dest = (long *)uncompressed; 1061 for (l=0 ; l<leaflongs ; l++) 1062 ((long *)uncompressed)[l] |= src[l]; 1063 } 1064 } 1065 for (j=0 ; j<portalclusters ; j++) 1066 if (uncompressed[j>>3] & (1<<(j&7)) ) 1067 count++; 1068 1069 // FIXME: copy it off 1070 } 1071 1072 _printf ("Average clusters hearable: %i\n", count/portalclusters); 1073 } 1074 1075 /* 1076 =========== 1077 VisMain 1078 =========== 1079 */ 1080 int VisMain (int argc, char **argv) 1081 { 1082 char portalfile[1024]; 1083 char name[1024]; 1084 int i; 1085 double start, end; 1086 1087 _printf ("---- vis ----\n"); 1088 1089 verbose = qfalse; 1090 for (i=1 ; i<argc ; i++) { 1091 if (!strcmp(argv[i],"-threads")) { 1092 numthreads = atoi (argv[i+1]); 1093 i++; 1094 } else if (!strcmp(argv[i],"-threads")) { 1095 numthreads = atoi (argv[i+1]); 1096 i++; 1097 } else if (!strcmp(argv[i], "-fast")) { 1098 _printf ("fastvis = true\n"); 1099 fastvis = qtrue; 1100 } else if (!strcmp(argv[i], "-merge")) { 1101 _printf ("merge = true\n"); 1102 mergevis = qtrue; 1103 } else if (!strcmp(argv[i], "-nopassage")) { 1104 _printf ("nopassage = true\n"); 1105 noPassageVis = qtrue; 1106 } else if (!strcmp(argv[i], "-passageOnly")) { 1107 _printf("passageOnly = true\n"); 1108 passageVisOnly = qtrue; 1109 } else if (!strcmp(argv[i], "-level")) { 1110 testlevel = atoi(argv[i+1]); 1111 _printf ("testlevel = %i\n", testlevel); 1112 i++; 1113 } else if (!strcmp(argv[i], "-v")) { 1114 _printf ("verbose = true\n"); 1115 verbose = qtrue; 1116 } else if (!strcmp (argv[i],"-nosort")) { 1117 _printf ("nosort = true\n"); 1118 nosort = qtrue; 1119 } else if (!strcmp (argv[i],"-saveprt")) { 1120 _printf ("saveprt = true\n"); 1121 saveprt = qtrue; 1122 } else if (!strcmp (argv[i],"-tmpin")) { 1123 strcpy (inbase, "/tmp"); 1124 } else if (!strcmp (argv[i],"-tmpout")) { 1125 strcpy (outbase, "/tmp"); 1126 } else if (argv[i][0] == '-') { 1127 Error ("Unknown option \"%s\"", argv[i]); 1128 } else { 1129 break; 1130 } 1131 } 1132 1133 if (i != argc - 1) 1134 Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile"); 1135 1136 #ifdef MREDEBUG 1137 start = clock(); 1138 #else 1139 start = I_FloatTime (); 1140 #endif 1141 1142 ThreadSetDefault (); 1143 1144 SetQdirFromPath (argv[i]); 1145 1146 #ifdef _WIN32 1147 InitPakFile(gamedir, NULL); 1148 #endif 1149 1150 // load the bsp 1151 sprintf (name, "%s%s", inbase, ExpandArg(argv[i])); 1152 StripExtension (name); 1153 strcat (name, ".bsp"); 1154 _printf ("reading %s\n", name); 1155 LoadBSPFile (name); 1156 1157 // load the portal file 1158 sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i])); 1159 StripExtension (portalfile); 1160 strcat (portalfile, ".prt"); 1161 _printf ("reading %s\n", portalfile); 1162 LoadPortals (portalfile); 1163 1164 if (mergevis) 1165 { 1166 MergeLeaves(); 1167 MergeLeafPortals(); 1168 } 1169 1170 CountActivePortals(); 1171 // WritePortals("maps/hints.prs"); 1172 1173 _printf ("visdatasize:%i\n", numVisBytes); 1174 1175 CalcVis (); 1176 1177 // CalcPHS (); 1178 1179 // delete the prt file 1180 if ( !saveprt ) { 1181 remove( portalfile ); 1182 } 1183 1184 // write the bsp file 1185 _printf ("writing %s\n", name); 1186 WriteBSPFile (name); 1187 1188 #ifdef MREDEBUG 1189 end = clock(); 1190 _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK); 1191 #else 1192 end = I_FloatTime (); 1193 _printf ("%5.2f seconds elapsed\n", end-start); 1194 #endif 1195 return 0; 1196 } 1197