WL_DRAW.C (26558B)
1 // WL_DRAW.C 2 3 #include "WL_DEF.H" 4 #include <DOS.H> 5 #pragma hdrstop 6 7 //#define DEBUGWALLS 8 //#define DEBUGTICS 9 10 /* 11 ============================================================================= 12 13 LOCAL CONSTANTS 14 15 ============================================================================= 16 */ 17 18 // the door is the last picture before the sprites 19 #define DOORWALL (PMSpriteStart-8) 20 21 #define ACTORSIZE 0x4000 22 23 /* 24 ============================================================================= 25 26 GLOBAL VARIABLES 27 28 ============================================================================= 29 */ 30 31 32 #ifdef DEBUGWALLS 33 unsigned screenloc[3]= {0,0,0}; 34 #else 35 unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START}; 36 #endif 37 unsigned freelatch = FREESTART; 38 39 long lasttimecount; 40 long frameon; 41 42 unsigned wallheight[MAXVIEWWIDTH]; 43 44 fixed tileglobal = TILEGLOBAL; 45 fixed mindist = MINDIST; 46 47 48 // 49 // math tables 50 // 51 int pixelangle[MAXVIEWWIDTH]; 52 long far finetangent[FINEANGLES/4]; 53 fixed far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4); 54 55 // 56 // refresh variables 57 // 58 fixed viewx,viewy; // the focal point 59 int viewangle; 60 fixed viewsin,viewcos; 61 62 63 64 fixed FixedByFrac (fixed a, fixed b); 65 void TransformActor (objtype *ob); 66 void BuildTables (void); 67 void ClearScreen (void); 68 int CalcRotate (objtype *ob); 69 void DrawScaleds (void); 70 void CalcTics (void); 71 void FixOfs (void); 72 void ThreeDRefresh (void); 73 74 75 76 // 77 // wall optimization variables 78 // 79 int lastside; // true for vertical 80 long lastintercept; 81 int lasttilehit; 82 83 84 // 85 // ray tracing variables 86 // 87 int focaltx,focalty,viewtx,viewty; 88 89 int midangle,angle; 90 unsigned xpartial,ypartial; 91 unsigned xpartialup,xpartialdown,ypartialup,ypartialdown; 92 unsigned xinttile,yinttile; 93 94 unsigned tilehit; 95 unsigned pixx; 96 97 int xtile,ytile; 98 int xtilestep,ytilestep; 99 long xintercept,yintercept; 100 long xstep,ystep; 101 102 int horizwall[MAXWALLTILES],vertwall[MAXWALLTILES]; 103 104 105 /* 106 ============================================================================= 107 108 LOCAL VARIABLES 109 110 ============================================================================= 111 */ 112 113 114 void AsmRefresh (void); // in WL_DR_A.ASM 115 116 /* 117 ============================================================================ 118 119 3 - D DEFINITIONS 120 121 ============================================================================ 122 */ 123 124 125 //========================================================================== 126 127 128 /* 129 ======================== 130 = 131 = FixedByFrac 132 = 133 = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit 134 = fraction, passed as a signed magnitude 32 bit number 135 = 136 ======================== 137 */ 138 139 #pragma warn -rvl // I stick the return value in with ASMs 140 141 fixed FixedByFrac (fixed a, fixed b) 142 { 143 // 144 // setup 145 // 146 asm mov si,[WORD PTR b+2] // sign of result = sign of fraction 147 148 asm mov ax,[WORD PTR a] 149 asm mov cx,[WORD PTR a+2] 150 151 asm or cx,cx 152 asm jns aok: // negative? 153 asm neg cx 154 asm neg ax 155 asm sbb cx,0 156 asm xor si,0x8000 // toggle sign of result 157 aok: 158 159 // 160 // multiply cx:ax by bx 161 // 162 asm mov bx,[WORD PTR b] 163 asm mul bx // fraction*fraction 164 asm mov di,dx // di is low word of result 165 asm mov ax,cx // 166 asm mul bx // units*fraction 167 asm add ax,di 168 asm adc dx,0 169 170 // 171 // put result dx:ax in 2's complement 172 // 173 asm test si,0x8000 // is the result negative? 174 asm jz ansok: 175 asm neg dx 176 asm neg ax 177 asm sbb dx,0 178 179 ansok:; 180 181 } 182 183 #pragma warn +rvl 184 185 //========================================================================== 186 187 /* 188 ======================== 189 = 190 = TransformActor 191 = 192 = Takes paramaters: 193 = gx,gy : globalx/globaly of point 194 = 195 = globals: 196 = viewx,viewy : point of view 197 = viewcos,viewsin : sin/cos of viewangle 198 = scale : conversion from global value to screen value 199 = 200 = sets: 201 = screenx,transx,transy,screenheight: projected edge location and size 202 = 203 ======================== 204 */ 205 206 207 // 208 // transform actor 209 // 210 void TransformActor (objtype *ob) 211 { 212 int ratio; 213 fixed gx,gy,gxt,gyt,nx,ny; 214 long temp; 215 216 // 217 // translate point to view centered coordinates 218 // 219 gx = ob->x-viewx; 220 gy = ob->y-viewy; 221 222 // 223 // calculate newx 224 // 225 gxt = FixedByFrac(gx,viewcos); 226 gyt = FixedByFrac(gy,viewsin); 227 nx = gxt-gyt-ACTORSIZE; // fudge the shape forward a bit, because 228 // the midpoint could put parts of the shape 229 // into an adjacent wall 230 231 // 232 // calculate newy 233 // 234 gxt = FixedByFrac(gx,viewsin); 235 gyt = FixedByFrac(gy,viewcos); 236 ny = gyt+gxt; 237 238 // 239 // calculate perspective ratio 240 // 241 ob->transx = nx; 242 ob->transy = ny; 243 244 if (nx<mindist) // too close, don't overflow the divide 245 { 246 ob->viewheight = 0; 247 return; 248 } 249 250 ob->viewx = centerx + ny*scale/nx; // DEBUG: use assembly divide 251 252 // 253 // calculate height (heightnumerator/(nx>>8)) 254 // 255 asm mov ax,[WORD PTR heightnumerator] 256 asm mov dx,[WORD PTR heightnumerator+2] 257 asm idiv [WORD PTR nx+1] // nx>>8 258 asm mov [WORD PTR temp],ax 259 asm mov [WORD PTR temp+2],dx 260 261 ob->viewheight = temp; 262 } 263 264 //========================================================================== 265 266 /* 267 ======================== 268 = 269 = TransformTile 270 = 271 = Takes paramaters: 272 = tx,ty : tile the object is centered in 273 = 274 = globals: 275 = viewx,viewy : point of view 276 = viewcos,viewsin : sin/cos of viewangle 277 = scale : conversion from global value to screen value 278 = 279 = sets: 280 = screenx,transx,transy,screenheight: projected edge location and size 281 = 282 = Returns true if the tile is withing getting distance 283 = 284 ======================== 285 */ 286 287 boolean TransformTile (int tx, int ty, int *dispx, int *dispheight) 288 { 289 int ratio; 290 fixed gx,gy,gxt,gyt,nx,ny; 291 long temp; 292 293 // 294 // translate point to view centered coordinates 295 // 296 gx = ((long)tx<<TILESHIFT)+0x8000-viewx; 297 gy = ((long)ty<<TILESHIFT)+0x8000-viewy; 298 299 // 300 // calculate newx 301 // 302 gxt = FixedByFrac(gx,viewcos); 303 gyt = FixedByFrac(gy,viewsin); 304 nx = gxt-gyt-0x2000; // 0x2000 is size of object 305 306 // 307 // calculate newy 308 // 309 gxt = FixedByFrac(gx,viewsin); 310 gyt = FixedByFrac(gy,viewcos); 311 ny = gyt+gxt; 312 313 314 // 315 // calculate perspective ratio 316 // 317 if (nx<mindist) // too close, don't overflow the divide 318 { 319 *dispheight = 0; 320 return false; 321 } 322 323 *dispx = centerx + ny*scale/nx; // DEBUG: use assembly divide 324 325 // 326 // calculate height (heightnumerator/(nx>>8)) 327 // 328 asm mov ax,[WORD PTR heightnumerator] 329 asm mov dx,[WORD PTR heightnumerator+2] 330 asm idiv [WORD PTR nx+1] // nx>>8 331 asm mov [WORD PTR temp],ax 332 asm mov [WORD PTR temp+2],dx 333 334 *dispheight = temp; 335 336 // 337 // see if it should be grabbed 338 // 339 if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2) 340 return true; 341 else 342 return false; 343 } 344 345 //========================================================================== 346 347 /* 348 ==================== 349 = 350 = CalcHeight 351 = 352 = Calculates the height of xintercept,yintercept from viewx,viewy 353 = 354 ==================== 355 */ 356 357 #pragma warn -rvl // I stick the return value in with ASMs 358 359 int CalcHeight (void) 360 { 361 int transheight; 362 int ratio; 363 fixed gxt,gyt,nx,ny; 364 long gx,gy; 365 366 gx = xintercept-viewx; 367 gxt = FixedByFrac(gx,viewcos); 368 369 gy = yintercept-viewy; 370 gyt = FixedByFrac(gy,viewsin); 371 372 nx = gxt-gyt; 373 374 // 375 // calculate perspective ratio (heightnumerator/(nx>>8)) 376 // 377 if (nx<mindist) 378 nx=mindist; // don't let divide overflow 379 380 asm mov ax,[WORD PTR heightnumerator] 381 asm mov dx,[WORD PTR heightnumerator+2] 382 asm idiv [WORD PTR nx+1] // nx>>8 383 } 384 385 386 //========================================================================== 387 388 /* 389 =================== 390 = 391 = ScalePost 392 = 393 =================== 394 */ 395 396 long postsource; 397 unsigned postx; 398 unsigned postwidth; 399 400 void near ScalePost (void) // VGA version 401 { 402 asm mov ax,SCREENSEG 403 asm mov es,ax 404 405 asm mov bx,[postx] 406 asm shl bx,1 407 asm mov bp,WORD PTR [wallheight+bx] // fractional height (low 3 bits frac) 408 asm and bp,0xfff8 // bp = heightscaler*4 409 asm shr bp,1 410 asm cmp bp,[maxscaleshl2] 411 asm jle heightok 412 asm mov bp,[maxscaleshl2] 413 heightok: 414 asm add bp,OFFSET fullscalefarcall 415 // 416 // scale a byte wide strip of wall 417 // 418 asm mov bx,[postx] 419 asm mov di,bx 420 asm shr di,2 // X in bytes 421 asm add di,[bufferofs] 422 423 asm and bx,3 424 asm shl bx,3 // bx = pixel*8+pixwidth 425 asm add bx,[postwidth] 426 427 asm mov al,BYTE PTR [mapmasks1-1+bx] // -1 because no widths of 0 428 asm mov dx,SC_INDEX+1 429 asm out dx,al // set bit mask register 430 asm lds si,DWORD PTR [postsource] 431 asm call DWORD PTR [bp] // scale the line of pixels 432 433 asm mov al,BYTE PTR [ss:mapmasks2-1+bx] // -1 because no widths of 0 434 asm or al,al 435 asm jz nomore 436 437 // 438 // draw a second byte for vertical strips that cross two bytes 439 // 440 asm inc di 441 asm out dx,al // set bit mask register 442 asm call DWORD PTR [bp] // scale the line of pixels 443 444 asm mov al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0 445 asm or al,al 446 asm jz nomore 447 // 448 // draw a third byte for vertical strips that cross three bytes 449 // 450 asm inc di 451 asm out dx,al // set bit mask register 452 asm call DWORD PTR [bp] // scale the line of pixels 453 454 455 nomore: 456 asm mov ax,ss 457 asm mov ds,ax 458 } 459 460 void FarScalePost (void) // just so other files can call 461 { 462 ScalePost (); 463 } 464 465 466 /* 467 ==================== 468 = 469 = HitVertWall 470 = 471 = tilehit bit 7 is 0, because it's not a door tile 472 = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic 473 = 474 ==================== 475 */ 476 477 void HitVertWall (void) 478 { 479 int wallpic; 480 unsigned texture; 481 482 texture = (yintercept>>4)&0xfc0; 483 if (xtilestep == -1) 484 { 485 texture = 0xfc0-texture; 486 xintercept += TILEGLOBAL; 487 } 488 wallheight[pixx] = CalcHeight(); 489 490 if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit) 491 { 492 // in the same wall type as last time, so check for optimized draw 493 if (texture == (unsigned)postsource) 494 { 495 // wide scale 496 postwidth++; 497 wallheight[pixx] = wallheight[pixx-1]; 498 return; 499 } 500 else 501 { 502 ScalePost (); 503 (unsigned)postsource = texture; 504 postwidth = 1; 505 postx = pixx; 506 } 507 } 508 else 509 { 510 // new wall 511 if (lastside != -1) // if not the first scaled post 512 ScalePost (); 513 514 lastside = true; 515 lastintercept = xtile; 516 517 lasttilehit = tilehit; 518 postx = pixx; 519 postwidth = 1; 520 521 if (tilehit & 0x40) 522 { // check for adjacent doors 523 ytile = yintercept>>TILESHIFT; 524 if ( tilemap[xtile-xtilestep][ytile]&0x80 ) 525 wallpic = DOORWALL+3; 526 else 527 wallpic = vertwall[tilehit & ~0x40]; 528 } 529 else 530 wallpic = vertwall[tilehit]; 531 532 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); 533 (unsigned)postsource = texture; 534 535 } 536 } 537 538 539 /* 540 ==================== 541 = 542 = HitHorizWall 543 = 544 = tilehit bit 7 is 0, because it's not a door tile 545 = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic 546 = 547 ==================== 548 */ 549 550 void HitHorizWall (void) 551 { 552 int wallpic; 553 unsigned texture; 554 555 texture = (xintercept>>4)&0xfc0; 556 if (ytilestep == -1) 557 yintercept += TILEGLOBAL; 558 else 559 texture = 0xfc0-texture; 560 wallheight[pixx] = CalcHeight(); 561 562 if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit) 563 { 564 // in the same wall type as last time, so check for optimized draw 565 if (texture == (unsigned)postsource) 566 { 567 // wide scale 568 postwidth++; 569 wallheight[pixx] = wallheight[pixx-1]; 570 return; 571 } 572 else 573 { 574 ScalePost (); 575 (unsigned)postsource = texture; 576 postwidth = 1; 577 postx = pixx; 578 } 579 } 580 else 581 { 582 // new wall 583 if (lastside != -1) // if not the first scaled post 584 ScalePost (); 585 586 lastside = 0; 587 lastintercept = ytile; 588 589 lasttilehit = tilehit; 590 postx = pixx; 591 postwidth = 1; 592 593 if (tilehit & 0x40) 594 { // check for adjacent doors 595 xtile = xintercept>>TILESHIFT; 596 if ( tilemap[xtile][ytile-ytilestep]&0x80 ) 597 wallpic = DOORWALL+2; 598 else 599 wallpic = horizwall[tilehit & ~0x40]; 600 } 601 else 602 wallpic = horizwall[tilehit]; 603 604 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); 605 (unsigned)postsource = texture; 606 } 607 608 } 609 610 //========================================================================== 611 612 /* 613 ==================== 614 = 615 = HitHorizDoor 616 = 617 ==================== 618 */ 619 620 void HitHorizDoor (void) 621 { 622 unsigned texture,doorpage,doornum; 623 624 doornum = tilehit&0x7f; 625 texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0; 626 627 wallheight[pixx] = CalcHeight(); 628 629 if (lasttilehit == tilehit) 630 { 631 // in the same door as last time, so check for optimized draw 632 if (texture == (unsigned)postsource) 633 { 634 // wide scale 635 postwidth++; 636 wallheight[pixx] = wallheight[pixx-1]; 637 return; 638 } 639 else 640 { 641 ScalePost (); 642 (unsigned)postsource = texture; 643 postwidth = 1; 644 postx = pixx; 645 } 646 } 647 else 648 { 649 if (lastside != -1) // if not the first scaled post 650 ScalePost (); // draw last post 651 // first pixel in this door 652 lastside = 2; 653 lasttilehit = tilehit; 654 postx = pixx; 655 postwidth = 1; 656 657 switch (doorobjlist[doornum].lock) 658 { 659 case dr_normal: 660 doorpage = DOORWALL; 661 break; 662 case dr_lock1: 663 case dr_lock2: 664 case dr_lock3: 665 case dr_lock4: 666 doorpage = DOORWALL+6; 667 break; 668 case dr_elevator: 669 doorpage = DOORWALL+4; 670 break; 671 } 672 673 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage); 674 (unsigned)postsource = texture; 675 } 676 } 677 678 //========================================================================== 679 680 /* 681 ==================== 682 = 683 = HitVertDoor 684 = 685 ==================== 686 */ 687 688 void HitVertDoor (void) 689 { 690 unsigned texture,doorpage,doornum; 691 692 doornum = tilehit&0x7f; 693 texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0; 694 695 wallheight[pixx] = CalcHeight(); 696 697 if (lasttilehit == tilehit) 698 { 699 // in the same door as last time, so check for optimized draw 700 if (texture == (unsigned)postsource) 701 { 702 // wide scale 703 postwidth++; 704 wallheight[pixx] = wallheight[pixx-1]; 705 return; 706 } 707 else 708 { 709 ScalePost (); 710 (unsigned)postsource = texture; 711 postwidth = 1; 712 postx = pixx; 713 } 714 } 715 else 716 { 717 if (lastside != -1) // if not the first scaled post 718 ScalePost (); // draw last post 719 // first pixel in this door 720 lastside = 2; 721 lasttilehit = tilehit; 722 postx = pixx; 723 postwidth = 1; 724 725 switch (doorobjlist[doornum].lock) 726 { 727 case dr_normal: 728 doorpage = DOORWALL; 729 break; 730 case dr_lock1: 731 case dr_lock2: 732 case dr_lock3: 733 case dr_lock4: 734 doorpage = DOORWALL+6; 735 break; 736 case dr_elevator: 737 doorpage = DOORWALL+4; 738 break; 739 } 740 741 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1); 742 (unsigned)postsource = texture; 743 } 744 } 745 746 //========================================================================== 747 748 749 /* 750 ==================== 751 = 752 = HitHorizPWall 753 = 754 = A pushable wall in action has been hit 755 = 756 ==================== 757 */ 758 759 void HitHorizPWall (void) 760 { 761 int wallpic; 762 unsigned texture,offset; 763 764 texture = (xintercept>>4)&0xfc0; 765 offset = pwallpos<<10; 766 if (ytilestep == -1) 767 yintercept += TILEGLOBAL-offset; 768 else 769 { 770 texture = 0xfc0-texture; 771 yintercept += offset; 772 } 773 774 wallheight[pixx] = CalcHeight(); 775 776 if (lasttilehit == tilehit) 777 { 778 // in the same wall type as last time, so check for optimized draw 779 if (texture == (unsigned)postsource) 780 { 781 // wide scale 782 postwidth++; 783 wallheight[pixx] = wallheight[pixx-1]; 784 return; 785 } 786 else 787 { 788 ScalePost (); 789 (unsigned)postsource = texture; 790 postwidth = 1; 791 postx = pixx; 792 } 793 } 794 else 795 { 796 // new wall 797 if (lastside != -1) // if not the first scaled post 798 ScalePost (); 799 800 lasttilehit = tilehit; 801 postx = pixx; 802 postwidth = 1; 803 804 wallpic = horizwall[tilehit&63]; 805 806 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); 807 (unsigned)postsource = texture; 808 } 809 810 } 811 812 813 /* 814 ==================== 815 = 816 = HitVertPWall 817 = 818 = A pushable wall in action has been hit 819 = 820 ==================== 821 */ 822 823 void HitVertPWall (void) 824 { 825 int wallpic; 826 unsigned texture,offset; 827 828 texture = (yintercept>>4)&0xfc0; 829 offset = pwallpos<<10; 830 if (xtilestep == -1) 831 { 832 xintercept += TILEGLOBAL-offset; 833 texture = 0xfc0-texture; 834 } 835 else 836 xintercept += offset; 837 838 wallheight[pixx] = CalcHeight(); 839 840 if (lasttilehit == tilehit) 841 { 842 // in the same wall type as last time, so check for optimized draw 843 if (texture == (unsigned)postsource) 844 { 845 // wide scale 846 postwidth++; 847 wallheight[pixx] = wallheight[pixx-1]; 848 return; 849 } 850 else 851 { 852 ScalePost (); 853 (unsigned)postsource = texture; 854 postwidth = 1; 855 postx = pixx; 856 } 857 } 858 else 859 { 860 // new wall 861 if (lastside != -1) // if not the first scaled post 862 ScalePost (); 863 864 lasttilehit = tilehit; 865 postx = pixx; 866 postwidth = 1; 867 868 wallpic = vertwall[tilehit&63]; 869 870 *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); 871 (unsigned)postsource = texture; 872 } 873 874 } 875 876 //========================================================================== 877 878 //========================================================================== 879 880 #if 0 881 /* 882 ===================== 883 = 884 = ClearScreen 885 = 886 ===================== 887 */ 888 889 void ClearScreen (void) 890 { 891 unsigned floor=egaFloor[gamestate.episode*10+mapon], 892 ceiling=egaCeiling[gamestate.episode*10+mapon]; 893 894 // 895 // clear the screen 896 // 897 asm mov dx,GC_INDEX 898 asm mov ax,GC_MODE + 256*2 // read mode 0, write mode 2 899 asm out dx,ax 900 asm mov ax,GC_BITMASK + 255*256 901 asm out dx,ax 902 903 asm mov dx,40 904 asm mov ax,[viewwidth] 905 asm shr ax,3 906 asm sub dx,ax // dx = 40-viewwidth/8 907 908 asm mov bx,[viewwidth] 909 asm shr bx,4 // bl = viewwidth/16 910 asm mov bh,BYTE PTR [viewheight] 911 asm shr bh,1 // half height 912 913 asm mov ax,[ceiling] 914 asm mov es,[screenseg] 915 asm mov di,[bufferofs] 916 917 toploop: 918 asm mov cl,bl 919 asm rep stosw 920 asm add di,dx 921 asm dec bh 922 asm jnz toploop 923 924 asm mov bh,BYTE PTR [viewheight] 925 asm shr bh,1 // half height 926 asm mov ax,[floor] 927 928 bottomloop: 929 asm mov cl,bl 930 asm rep stosw 931 asm add di,dx 932 asm dec bh 933 asm jnz bottomloop 934 935 936 asm mov dx,GC_INDEX 937 asm mov ax,GC_MODE + 256*10 // read mode 1, write mode 2 938 asm out dx,ax 939 asm mov al,GC_BITMASK 940 asm out dx,al 941 942 } 943 #endif 944 //========================================================================== 945 946 unsigned vgaCeiling[]= 947 { 948 #ifndef SPEAR 949 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf, 950 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d, 951 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898, 952 953 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd, 954 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d, 955 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd 956 #else 957 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f, 958 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc 959 #endif 960 }; 961 962 /* 963 ===================== 964 = 965 = VGAClearScreen 966 = 967 ===================== 968 */ 969 970 void VGAClearScreen (void) 971 { 972 unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon]; 973 974 // 975 // clear the screen 976 // 977 asm mov dx,SC_INDEX 978 asm mov ax,SC_MAPMASK+15*256 // write through all planes 979 asm out dx,ax 980 981 asm mov dx,80 982 asm mov ax,[viewwidth] 983 asm shr ax,2 984 asm sub dx,ax // dx = 40-viewwidth/2 985 986 asm mov bx,[viewwidth] 987 asm shr bx,3 // bl = viewwidth/8 988 asm mov bh,BYTE PTR [viewheight] 989 asm shr bh,1 // half height 990 991 asm mov es,[screenseg] 992 asm mov di,[bufferofs] 993 asm mov ax,[ceiling] 994 995 toploop: 996 asm mov cl,bl 997 asm rep stosw 998 asm add di,dx 999 asm dec bh 1000 asm jnz toploop 1001 1002 asm mov bh,BYTE PTR [viewheight] 1003 asm shr bh,1 // half height 1004 asm mov ax,0x1919 1005 1006 bottomloop: 1007 asm mov cl,bl 1008 asm rep stosw 1009 asm add di,dx 1010 asm dec bh 1011 asm jnz bottomloop 1012 } 1013 1014 //========================================================================== 1015 1016 /* 1017 ===================== 1018 = 1019 = CalcRotate 1020 = 1021 ===================== 1022 */ 1023 1024 int CalcRotate (objtype *ob) 1025 { 1026 int angle,viewangle; 1027 1028 // this isn't exactly correct, as it should vary by a trig value, 1029 // but it is close enough with only eight rotations 1030 1031 viewangle = player->angle + (centerx - ob->viewx)/8; 1032 1033 if (ob->obclass == rocketobj || ob->obclass == hrocketobj) 1034 angle = (viewangle-180)- ob->angle; 1035 else 1036 angle = (viewangle-180)- dirangle[ob->dir]; 1037 1038 angle+=ANGLES/16; 1039 while (angle>=ANGLES) 1040 angle-=ANGLES; 1041 while (angle<0) 1042 angle+=ANGLES; 1043 1044 if (ob->state->rotate == 2) // 2 rotation pain frame 1045 return 4*(angle/(ANGLES/2)); // seperated by 3 (art layout...) 1046 1047 return angle/(ANGLES/8); 1048 } 1049 1050 1051 /* 1052 ===================== 1053 = 1054 = DrawScaleds 1055 = 1056 = Draws all objects that are visable 1057 = 1058 ===================== 1059 */ 1060 1061 #define MAXVISABLE 50 1062 1063 typedef struct 1064 { 1065 int viewx, 1066 viewheight, 1067 shapenum; 1068 } visobj_t; 1069 1070 visobj_t vislist[MAXVISABLE],*visptr,*visstep,*farthest; 1071 1072 void DrawScaleds (void) 1073 { 1074 int i,j,least,numvisable,height; 1075 memptr shape; 1076 byte *tilespot,*visspot; 1077 int shapenum; 1078 unsigned spotloc; 1079 1080 statobj_t *statptr; 1081 objtype *obj; 1082 1083 visptr = &vislist[0]; 1084 1085 // 1086 // place static objects 1087 // 1088 for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++) 1089 { 1090 if ((visptr->shapenum = statptr->shapenum) == -1) 1091 continue; // object has been deleted 1092 1093 if (!*statptr->visspot) 1094 continue; // not visable 1095 1096 if (TransformTile (statptr->tilex,statptr->tiley 1097 ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS) 1098 { 1099 GetBonus (statptr); 1100 continue; 1101 } 1102 1103 if (!visptr->viewheight) 1104 continue; // to close to the object 1105 1106 if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow 1107 visptr++; 1108 } 1109 1110 // 1111 // place active objects 1112 // 1113 for (obj = player->next;obj;obj=obj->next) 1114 { 1115 if (!(visptr->shapenum = obj->state->shapenum)) 1116 continue; // no shape 1117 1118 spotloc = (obj->tilex<<6)+obj->tiley; // optimize: keep in struct? 1119 visspot = &spotvis[0][0]+spotloc; 1120 tilespot = &tilemap[0][0]+spotloc; 1121 1122 // 1123 // could be in any of the nine surrounding tiles 1124 // 1125 if (*visspot 1126 || ( *(visspot-1) && !*(tilespot-1) ) 1127 || ( *(visspot+1) && !*(tilespot+1) ) 1128 || ( *(visspot-65) && !*(tilespot-65) ) 1129 || ( *(visspot-64) && !*(tilespot-64) ) 1130 || ( *(visspot-63) && !*(tilespot-63) ) 1131 || ( *(visspot+65) && !*(tilespot+65) ) 1132 || ( *(visspot+64) && !*(tilespot+64) ) 1133 || ( *(visspot+63) && !*(tilespot+63) ) ) 1134 { 1135 obj->active = true; 1136 TransformActor (obj); 1137 if (!obj->viewheight) 1138 continue; // too close or far away 1139 1140 visptr->viewx = obj->viewx; 1141 visptr->viewheight = obj->viewheight; 1142 if (visptr->shapenum == -1) 1143 visptr->shapenum = obj->temp1; // special shape 1144 1145 if (obj->state->rotate) 1146 visptr->shapenum += CalcRotate (obj); 1147 1148 if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow 1149 visptr++; 1150 obj->flags |= FL_VISABLE; 1151 } 1152 else 1153 obj->flags &= ~FL_VISABLE; 1154 } 1155 1156 // 1157 // draw from back to front 1158 // 1159 numvisable = visptr-&vislist[0]; 1160 1161 if (!numvisable) 1162 return; // no visable objects 1163 1164 for (i = 0; i<numvisable; i++) 1165 { 1166 least = 32000; 1167 for (visstep=&vislist[0] ; visstep<visptr ; visstep++) 1168 { 1169 height = visstep->viewheight; 1170 if (height < least) 1171 { 1172 least = height; 1173 farthest = visstep; 1174 } 1175 } 1176 // 1177 // draw farthest 1178 // 1179 ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight); 1180 1181 farthest->viewheight = 32000; 1182 } 1183 1184 } 1185 1186 //========================================================================== 1187 1188 /* 1189 ============== 1190 = 1191 = DrawPlayerWeapon 1192 = 1193 = Draw the player's hands 1194 = 1195 ============== 1196 */ 1197 1198 int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY 1199 ,SPR_MACHINEGUNREADY,SPR_CHAINREADY}; 1200 1201 void DrawPlayerWeapon (void) 1202 { 1203 int shapenum; 1204 1205 #ifndef SPEAR 1206 if (gamestate.victoryflag) 1207 { 1208 if (player->state == &s_deathcam && (TimeCount&32) ) 1209 SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1); 1210 return; 1211 } 1212 #endif 1213 1214 if (gamestate.weapon != -1) 1215 { 1216 shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe; 1217 SimpleScaleShape(viewwidth/2,shapenum,viewheight+1); 1218 } 1219 1220 if (demorecord || demoplayback) 1221 SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1); 1222 } 1223 1224 1225 //========================================================================== 1226 1227 1228 /* 1229 ===================== 1230 = 1231 = CalcTics 1232 = 1233 ===================== 1234 */ 1235 1236 void CalcTics (void) 1237 { 1238 long newtime,oldtimecount; 1239 1240 // 1241 // calculate tics since last refresh for adaptive timing 1242 // 1243 if (lasttimecount > TimeCount) 1244 TimeCount = lasttimecount; // if the game was paused a LONG time 1245 1246 do 1247 { 1248 newtime = TimeCount; 1249 tics = newtime-lasttimecount; 1250 } while (!tics); // make sure at least one tic passes 1251 1252 lasttimecount = newtime; 1253 1254 #ifdef FILEPROFILE 1255 strcpy (scratch,"\tTics:"); 1256 itoa (tics,str,10); 1257 strcat (scratch,str); 1258 strcat (scratch,"\n"); 1259 write (profilehandle,scratch,strlen(scratch)); 1260 #endif 1261 1262 if (tics>MAXTICS) 1263 { 1264 TimeCount -= (tics-MAXTICS); 1265 tics = MAXTICS; 1266 } 1267 } 1268 1269 1270 //========================================================================== 1271 1272 1273 /* 1274 ======================== 1275 = 1276 = FixOfs 1277 = 1278 ======================== 1279 */ 1280 1281 void FixOfs (void) 1282 { 1283 VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight); 1284 } 1285 1286 1287 //========================================================================== 1288 1289 1290 /* 1291 ==================== 1292 = 1293 = WallRefresh 1294 = 1295 ==================== 1296 */ 1297 1298 void WallRefresh (void) 1299 { 1300 // 1301 // set up variables for this view 1302 // 1303 viewangle = player->angle; 1304 midangle = viewangle*(FINEANGLES/ANGLES); 1305 viewsin = sintable[viewangle]; 1306 viewcos = costable[viewangle]; 1307 viewx = player->x - FixedByFrac(focallength,viewcos); 1308 viewy = player->y + FixedByFrac(focallength,viewsin); 1309 1310 focaltx = viewx>>TILESHIFT; 1311 focalty = viewy>>TILESHIFT; 1312 1313 viewtx = player->x >> TILESHIFT; 1314 viewty = player->y >> TILESHIFT; 1315 1316 xpartialdown = viewx&(TILEGLOBAL-1); 1317 xpartialup = TILEGLOBAL-xpartialdown; 1318 ypartialdown = viewy&(TILEGLOBAL-1); 1319 ypartialup = TILEGLOBAL-ypartialdown; 1320 1321 lastside = -1; // the first pixel is on a new wall 1322 AsmRefresh (); 1323 ScalePost (); // no more optimization on last post 1324 } 1325 1326 //========================================================================== 1327 1328 /* 1329 ======================== 1330 = 1331 = ThreeDRefresh 1332 = 1333 ======================== 1334 */ 1335 1336 void ThreeDRefresh (void) 1337 { 1338 int tracedir; 1339 1340 // this wouldn't need to be done except for my debugger/video wierdness 1341 outportb (SC_INDEX,SC_MAPMASK); 1342 1343 // 1344 // clear out the traced array 1345 // 1346 asm mov ax,ds 1347 asm mov es,ax 1348 asm mov di,OFFSET spotvis 1349 asm xor ax,ax 1350 asm mov cx,2048 // 64*64 / 2 1351 asm rep stosw 1352 1353 bufferofs += screenofs; 1354 1355 // 1356 // follow the walls from there to the right, drawwing as we go 1357 // 1358 VGAClearScreen (); 1359 1360 WallRefresh (); 1361 1362 // 1363 // draw all the scaled images 1364 // 1365 DrawScaleds(); // draw scaled stuff 1366 DrawPlayerWeapon (); // draw player's hands 1367 1368 // 1369 // show screen and time last cycle 1370 // 1371 if (fizzlein) 1372 { 1373 FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false); 1374 fizzlein = false; 1375 1376 lasttimecount = TimeCount = 0; // don't make a big tic count 1377 1378 } 1379 1380 bufferofs -= screenofs; 1381 displayofs = bufferofs; 1382 1383 asm cli 1384 asm mov cx,[displayofs] 1385 asm mov dx,3d4h // CRTC address register 1386 asm mov al,0ch // start address high register 1387 asm out dx,al 1388 asm inc dx 1389 asm mov al,ch 1390 asm out dx,al // set the high byte 1391 asm sti 1392 1393 bufferofs += SCREENSIZE; 1394 if (bufferofs > PAGE3START) 1395 bufferofs = PAGE1START; 1396 1397 frameon++; 1398 PM_NextFrame(); 1399 } 1400 1401 1402 //=========================================================================== 1403