p_maputl.c (12042B)
1 #include <stdlib.h> 2 3 #include "m_bbox.h" 4 #include "doomdef.h" 5 #include "p_local.h" 6 #include "r_state.h" 7 8 fixed_t 9 P_AproxDistance 10 ( fixed_t dx, 11 fixed_t dy ) 12 { 13 dx = abs(dx); 14 dy = abs(dy); 15 if (dx < dy) 16 return dx+dy-(dx>>1); 17 return dx+dy-(dy>>1); 18 } 19 20 21 22 23 24 25 int 26 P_PointOnLineSide 27 ( fixed_t x, 28 fixed_t y, 29 line_t* line ) 30 { 31 fixed_t dx; 32 fixed_t dy; 33 fixed_t left; 34 fixed_t right; 35 36 if (!line->dx) 37 { 38 if (x <= line->v1->x) 39 return line->dy > 0; 40 41 return line->dy < 0; 42 } 43 if (!line->dy) 44 { 45 if (y <= line->v1->y) 46 return line->dx < 0; 47 48 return line->dx > 0; 49 } 50 51 dx = (x - line->v1->x); 52 dy = (y - line->v1->y); 53 54 left = FixedMul ( line->dy>>FRACBITS , dx ); 55 right = FixedMul ( dy , line->dx>>FRACBITS ); 56 57 if (right < left) 58 return 0; 59 return 1; 60 } 61 62 63 64 65 66 67 68 69 int 70 P_BoxOnLineSide(fixed_t* tmbox, line_t* ld) 71 { 72 int p1, p2; 73 74 switch (ld->slopetype) { 75 case ST_HORIZONTAL: 76 p1 = tmbox[BOXTOP] > ld->v1->y; 77 p2 = tmbox[BOXBOTTOM] > ld->v1->y; 78 if (ld->dx < 0) { 79 p1 ^= 1; 80 p2 ^= 1; 81 } 82 break; 83 case ST_VERTICAL: 84 p1 = tmbox[BOXRIGHT] < ld->v1->x; 85 p2 = tmbox[BOXLEFT] < ld->v1->x; 86 if (ld->dy < 0) { 87 p1 ^= 1; 88 p2 ^= 1; 89 } 90 break; 91 case ST_POSITIVE: 92 p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld); 93 p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld); 94 break; 95 case ST_NEGATIVE: 96 p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld); 97 p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld); 98 break; 99 default: 100 p1 = p2 = 0; 101 } 102 if (p1 == p2) 103 return p1; 104 return -1; 105 } 106 107 int 108 P_PointOnDivlineSide 109 ( fixed_t x, 110 fixed_t y, 111 divline_t* line ) 112 { 113 fixed_t dx; 114 fixed_t dy; 115 fixed_t left; 116 fixed_t right; 117 118 if (!line->dx) 119 { 120 if (x <= line->x) 121 return line->dy > 0; 122 123 return line->dy < 0; 124 } 125 if (!line->dy) 126 { 127 if (y <= line->y) 128 return line->dx < 0; 129 130 return line->dx > 0; 131 } 132 133 dx = (x - line->x); 134 dy = (y - line->y); 135 136 137 if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 ) 138 { 139 if ( (line->dy ^ dx) & 0x80000000 ) 140 return 1; 141 return 0; 142 } 143 144 left = FixedMul ( line->dy>>8, dx>>8 ); 145 right = FixedMul ( dy>>8 , line->dx>>8 ); 146 147 if (right < left) 148 return 0; 149 return 1; 150 } 151 152 153 154 155 156 157 void 158 P_MakeDivline 159 ( line_t* li, 160 divline_t* dl ) 161 { 162 dl->x = li->v1->x; 163 dl->y = li->v1->y; 164 dl->dx = li->dx; 165 dl->dy = li->dy; 166 } 167 168 169 170 171 172 173 174 175 176 177 fixed_t 178 P_InterceptVector 179 ( divline_t* v2, 180 divline_t* v1 ) 181 { 182 #if 1 183 fixed_t frac; 184 fixed_t num; 185 fixed_t den; 186 187 den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy); 188 189 if (den == 0) 190 return 0; 191 192 193 num = 194 FixedMul ( (v1->x - v2->x)>>8 ,v1->dy ) 195 +FixedMul ( (v2->y - v1->y)>>8, v1->dx ); 196 197 frac = FixedDiv (num , den); 198 199 return frac; 200 #else 201 float frac; 202 float num; 203 float den; 204 float v1x; 205 float v1y; 206 float v1dx; 207 float v1dy; 208 float v2x; 209 float v2y; 210 float v2dx; 211 float v2dy; 212 213 v1x = (float)v1->x/FRACUNIT; 214 v1y = (float)v1->y/FRACUNIT; 215 v1dx = (float)v1->dx/FRACUNIT; 216 v1dy = (float)v1->dy/FRACUNIT; 217 v2x = (float)v2->x/FRACUNIT; 218 v2y = (float)v2->y/FRACUNIT; 219 v2dx = (float)v2->dx/FRACUNIT; 220 v2dy = (float)v2->dy/FRACUNIT; 221 222 den = v1dy*v2dx - v1dx*v2dy; 223 224 if (den == 0) 225 return 0; 226 227 num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; 228 frac = num / den; 229 230 return frac*FRACUNIT; 231 #endif 232 } 233 234 235 236 237 238 239 240 241 fixed_t opentop; 242 fixed_t openbottom; 243 fixed_t openrange; 244 fixed_t lowfloor; 245 246 247 void P_LineOpening (line_t* linedef) 248 { 249 sector_t* front; 250 sector_t* back; 251 252 if (linedef->sidenum[1] == -1) 253 { 254 255 openrange = 0; 256 return; 257 } 258 259 front = linedef->frontsector; 260 back = linedef->backsector; 261 262 if (front->ceilingheight < back->ceilingheight) 263 opentop = front->ceilingheight; 264 else 265 opentop = back->ceilingheight; 266 267 if (front->floorheight > back->floorheight) 268 { 269 openbottom = front->floorheight; 270 lowfloor = back->floorheight; 271 } 272 else 273 { 274 openbottom = back->floorheight; 275 lowfloor = front->floorheight; 276 } 277 278 openrange = opentop - openbottom; 279 } 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 void P_UnsetThingPosition (mobj_t* thing) 295 { 296 int blockx; 297 int blocky; 298 299 if ( ! (thing->flags & MF_NOSECTOR) ) 300 { 301 302 303 if (thing->snext) 304 thing->snext->sprev = thing->sprev; 305 306 if (thing->sprev) 307 thing->sprev->snext = thing->snext; 308 else 309 thing->subsector->sector->thinglist = thing->snext; 310 } 311 312 if ( ! (thing->flags & MF_NOBLOCKMAP) ) 313 { 314 315 316 if (thing->bnext) 317 thing->bnext->bprev = thing->bprev; 318 319 if (thing->bprev) 320 thing->bprev->bnext = thing->bnext; 321 else 322 { 323 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; 324 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; 325 326 if (blockx>=0 && blockx < bmapwidth 327 && blocky>=0 && blocky <bmapheight) 328 { 329 blocklinks[blocky*bmapwidth+blockx] = thing->bnext; 330 } 331 } 332 } 333 } 334 335 336 337 338 339 340 341 342 void 343 P_SetThingPosition (mobj_t* thing) 344 { 345 subsector_t* ss; 346 sector_t* sec; 347 int blockx; 348 int blocky; 349 mobj_t** link; 350 351 352 353 ss = R_PointInSubsector (thing->x,thing->y); 354 thing->subsector = ss; 355 356 if ( ! (thing->flags & MF_NOSECTOR) ) 357 { 358 359 sec = ss->sector; 360 361 thing->sprev = NULL; 362 thing->snext = sec->thinglist; 363 364 if (sec->thinglist) 365 sec->thinglist->sprev = thing; 366 367 sec->thinglist = thing; 368 } 369 370 371 372 if ( ! (thing->flags & MF_NOBLOCKMAP) ) 373 { 374 375 blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; 376 blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; 377 378 if (blockx>=0 379 && blockx < bmapwidth 380 && blocky>=0 381 && blocky < bmapheight) 382 { 383 link = &blocklinks[blocky*bmapwidth+blockx]; 384 thing->bprev = NULL; 385 thing->bnext = *link; 386 if (*link) 387 (*link)->bprev = thing; 388 389 *link = thing; 390 } 391 else 392 { 393 394 thing->bnext = thing->bprev = NULL; 395 } 396 } 397 } 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 boolean 419 P_BlockLinesIterator 420 ( int x, 421 int y, 422 boolean(*func)(line_t*) ) 423 { 424 int offset; 425 short* list; 426 line_t* ld; 427 428 if (x<0 429 || y<0 430 || x>=bmapwidth 431 || y>=bmapheight) 432 { 433 return true; 434 } 435 436 offset = y*bmapwidth+x; 437 438 offset = *(blockmap+offset); 439 440 for ( list = blockmaplump+offset ; *list != -1 ; list++) 441 { 442 ld = &lines[*list]; 443 444 if (ld->validcount == validcount) 445 continue; 446 447 ld->validcount = validcount; 448 449 if ( !func(ld) ) 450 return false; 451 } 452 return true; 453 } 454 455 456 457 458 459 boolean 460 P_BlockThingsIterator 461 ( int x, 462 int y, 463 boolean(*func)(mobj_t*) ) 464 { 465 mobj_t* mobj; 466 467 if ( x<0 468 || y<0 469 || x>=bmapwidth 470 || y>=bmapheight) 471 { 472 return true; 473 } 474 475 476 for (mobj = blocklinks[y*bmapwidth+x] ; 477 mobj ; 478 mobj = mobj->bnext) 479 { 480 if (!func( mobj ) ) 481 return false; 482 } 483 return true; 484 } 485 486 487 488 489 490 491 intercept_t intercepts[INT_MAXERCEPTS]; 492 intercept_t* intercept_p; 493 494 divline_t trace; 495 boolean earlyout; 496 int ptflags; 497 498 499 500 501 502 503 504 505 506 507 508 boolean 509 PIT_AddLineIntercepts (line_t* ld) 510 { 511 int s1; 512 int s2; 513 fixed_t frac; 514 divline_t dl; 515 516 517 if ( trace.dx > FRACUNIT*16 518 || trace.dy > FRACUNIT*16 519 || trace.dx < -FRACUNIT*16 520 || trace.dy < -FRACUNIT*16) 521 { 522 s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); 523 s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); 524 } 525 else 526 { 527 s1 = P_PointOnLineSide (trace.x, trace.y, ld); 528 s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); 529 } 530 531 if (s1 == s2) 532 return true; 533 534 535 P_MakeDivline (ld, &dl); 536 frac = P_InterceptVector (&trace, &dl); 537 538 if (frac < 0) 539 return true; 540 541 542 if (earlyout 543 && frac < FRACUNIT 544 && !ld->backsector) 545 { 546 return false; 547 } 548 549 550 intercept_p->frac = frac; 551 intercept_p->isaline = true; 552 intercept_p->d.line = ld; 553 intercept_p++; 554 555 return true; 556 } 557 558 559 560 561 562 563 boolean PIT_AddThingIntercepts (mobj_t* thing) 564 { 565 fixed_t x1; 566 fixed_t y1; 567 fixed_t x2; 568 fixed_t y2; 569 570 int s1; 571 int s2; 572 573 boolean tracepositive; 574 575 divline_t dl; 576 577 fixed_t frac; 578 579 tracepositive = (trace.dx ^ trace.dy)>0; 580 581 582 if (tracepositive) 583 { 584 x1 = thing->x - thing->radius; 585 y1 = thing->y + thing->radius; 586 587 x2 = thing->x + thing->radius; 588 y2 = thing->y - thing->radius; 589 } 590 else 591 { 592 x1 = thing->x - thing->radius; 593 y1 = thing->y - thing->radius; 594 595 x2 = thing->x + thing->radius; 596 y2 = thing->y + thing->radius; 597 } 598 599 s1 = P_PointOnDivlineSide (x1, y1, &trace); 600 s2 = P_PointOnDivlineSide (x2, y2, &trace); 601 602 if (s1 == s2) 603 return true; 604 605 dl.x = x1; 606 dl.y = y1; 607 dl.dx = x2-x1; 608 dl.dy = y2-y1; 609 610 frac = P_InterceptVector (&trace, &dl); 611 612 if (frac < 0) 613 return true; 614 615 intercept_p->frac = frac; 616 intercept_p->isaline = false; 617 intercept_p->d.thing = thing; 618 intercept_p++; 619 620 return true; 621 } 622 623 624 625 626 627 628 629 boolean 630 P_TraverseIntercepts 631 ( traverser_t func, 632 fixed_t maxfrac ) 633 { 634 int count; 635 fixed_t dist; 636 intercept_t* scan; 637 intercept_t* in; 638 639 count = intercept_p - intercepts; 640 641 in = 0; 642 643 while (count--) 644 { 645 dist = INT_MAX; 646 for (scan = intercepts ; scan<intercept_p ; scan++) 647 { 648 if (scan->frac < dist) 649 { 650 dist = scan->frac; 651 in = scan; 652 } 653 } 654 655 if (dist > maxfrac) 656 return true; 657 658 #if 0 659 { 660 661 in = scan = intercepts; 662 for ( scan = intercepts ; scan<intercept_p ; scan++) 663 if (scan->frac > maxfrac) 664 *in++ = *scan; 665 intercept_p = in; 666 return false; 667 } 668 #endif 669 670 if ( !func (in) ) 671 return false; 672 673 in->frac = INT_MAX; 674 } 675 676 return true; 677 } 678 679 680 681 682 683 684 685 686 687 688 689 boolean 690 P_PathTraverse 691 ( fixed_t x1, 692 fixed_t y1, 693 fixed_t x2, 694 fixed_t y2, 695 int flags, 696 boolean (*trav) (intercept_t *)) 697 { 698 fixed_t xt1; 699 fixed_t yt1; 700 fixed_t xt2; 701 fixed_t yt2; 702 703 fixed_t xstep; 704 fixed_t ystep; 705 706 fixed_t partial; 707 708 fixed_t xintercept; 709 fixed_t yintercept; 710 711 int mapx; 712 int mapy; 713 714 int mapxstep; 715 int mapystep; 716 717 int count; 718 719 earlyout = flags & PT_EARLYOUT; 720 721 validcount++; 722 intercept_p = intercepts; 723 724 if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) 725 x1 += FRACUNIT; 726 727 if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) 728 y1 += FRACUNIT; 729 730 trace.x = x1; 731 trace.y = y1; 732 trace.dx = x2 - x1; 733 trace.dy = y2 - y1; 734 735 x1 -= bmaporgx; 736 y1 -= bmaporgy; 737 xt1 = x1>>MAPBLOCKSHIFT; 738 yt1 = y1>>MAPBLOCKSHIFT; 739 740 x2 -= bmaporgx; 741 y2 -= bmaporgy; 742 xt2 = x2>>MAPBLOCKSHIFT; 743 yt2 = y2>>MAPBLOCKSHIFT; 744 745 if (xt2 > xt1) 746 { 747 mapxstep = 1; 748 partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); 749 ystep = FixedDiv (y2-y1,abs(x2-x1)); 750 } 751 else if (xt2 < xt1) 752 { 753 mapxstep = -1; 754 partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); 755 ystep = FixedDiv (y2-y1,abs(x2-x1)); 756 } 757 else 758 { 759 mapxstep = 0; 760 partial = FRACUNIT; 761 ystep = 256*FRACUNIT; 762 } 763 764 yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep); 765 766 767 if (yt2 > yt1) 768 { 769 mapystep = 1; 770 partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); 771 xstep = FixedDiv (x2-x1,abs(y2-y1)); 772 } 773 else if (yt2 < yt1) 774 { 775 mapystep = -1; 776 partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); 777 xstep = FixedDiv (x2-x1,abs(y2-y1)); 778 } 779 else 780 { 781 mapystep = 0; 782 partial = FRACUNIT; 783 xstep = 256*FRACUNIT; 784 } 785 xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); 786 787 788 789 790 mapx = xt1; 791 mapy = yt1; 792 793 for (count = 0 ; count < 64 ; count++) 794 { 795 if (flags & PT_ADDLINES) 796 { 797 if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts)) 798 return false; 799 } 800 801 if (flags & PT_ADDTHINGS) 802 { 803 if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts)) 804 return false; 805 } 806 807 if (mapx == xt2 808 && mapy == yt2) 809 { 810 break; 811 } 812 813 if ( (yintercept >> FRACBITS) == mapy) 814 { 815 yintercept += ystep; 816 mapx += mapxstep; 817 } 818 else if ( (xintercept >> FRACBITS) == mapx) 819 { 820 xintercept += xstep; 821 mapy += mapystep; 822 } 823 824 } 825 826 return P_TraverseIntercepts ( trav, FRACUNIT ); 827 } 828 829 830