CONTIGSC.C (15367B)
1 // WL_SCALE.C 2 3 #include "WL_DEF.H" 4 #pragma hdrstop 5 6 #define OP_RETF 0xcb 7 8 /* 9 ============================================================================= 10 11 GLOBALS 12 13 ============================================================================= 14 */ 15 16 t_compscale far *scaledirectory[MAXSCALEHEIGHT+1]; 17 long fullscalefarcall[MAXSCALEHEIGHT+1]; 18 19 int maxscale,maxscaleshl2; 20 21 byte far *scalermemory; 22 byte _seg *endscalermemory; 23 long freescalermemory; 24 25 26 /* 27 ============================================================================= 28 29 LOCALS 30 31 ============================================================================= 32 */ 33 34 unsigned BuildCompScale (int height, byte far *code); 35 36 int stepbytwo; 37 38 //=========================================================================== 39 40 /* 41 ============== 42 = 43 = BadScale 44 = 45 ============== 46 */ 47 48 void far BadScale (void) 49 { 50 Quit ("BadScale called!"); 51 } 52 53 54 /* 55 ========================== 56 = 57 = SetupScaling 58 = 59 ========================== 60 */ 61 62 long SetupScaling (int maxscaleheight) 63 { 64 int i,x,y; 65 byte far *dest; 66 unsigned seg,ofs; 67 long size; 68 69 70 maxscaleheight/=2; // one scaler every two pixels 71 72 maxscale = maxscaleheight-1; 73 maxscaleshl2 = maxscale<<2; 74 75 dest = scalermemory; 76 77 // 78 // build the compiled scalers 79 // 80 stepbytwo = viewheight/2; // save space by double stepping 81 82 for (i=1;i<=maxscaleheight;i++) 83 { 84 seg = FP_SEG(dest); 85 ofs = (FP_OFF(dest)+15)&~15; 86 dest = MK_FP(seg+ofs/16,0); 87 88 scaledirectory[i] = (t_compscale far *)dest; 89 size = BuildCompScale (i*2,dest); 90 dest += size; 91 92 if ((byte huge *)dest-(byte huge *)scalermemory > MAXSCALERMEMORY) 93 Quit ("Compiled scalars exceeded allocated space!"); 94 95 if (i>=stepbytwo) 96 i+= 2; 97 } 98 99 // 100 // get far call addresses 101 // 102 for (i=1;i<=maxscaleheight;i++) 103 { 104 fullscalefarcall[i] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0]; 105 if (i>=stepbytwo) 106 { 107 scaledirectory[i+1] = scaledirectory[i]; 108 fullscalefarcall[i+1] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0]; 109 scaledirectory[i+2] = scaledirectory[i]; 110 fullscalefarcall[i+2] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0]; 111 i+=2; 112 } 113 } 114 scaledirectory[0] = scaledirectory[1]; 115 fullscalefarcall[0] = fullscalefarcall[1]; 116 117 // 118 // check for oversize wall drawing 119 // 120 for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++) 121 fullscalefarcall[i] = (long)BadScale; 122 123 seg = FP_SEG(dest); 124 ofs = (FP_OFF(dest)+15)&~15; 125 endscalermemory = (void _seg *)(seg+ofs/16); 126 size = (byte huge *)dest-(byte huge *)scalermemory; 127 freescalermemory = MAXSCALERMEMORY-16-size; 128 129 return size; 130 } 131 132 //=========================================================================== 133 134 /* 135 ======================== 136 = 137 = BuildCompScale 138 = 139 = Builds a compiled scaler object that will scale a 64 tall object to 140 = the given height (centered vertically on the screen) 141 = 142 = height should be even 143 = 144 = Call with 145 = --------- 146 = DS:SI Source for scale 147 = ES:DI Dest for scale 148 = 149 = Calling the compiled scaler only destroys AL 150 = 151 ======================== 152 */ 153 154 unsigned BuildCompScale (int height, byte far *code) 155 { 156 t_compscale far *work; 157 158 int i; 159 long fix,step; 160 unsigned src,totalscaled,totalsize; 161 int startpix,endpix,toppix; 162 163 work = (t_compscale far *)code; 164 165 step = ((long)height<<16) / 64; 166 code = &work->code[0]; 167 toppix = (viewheight-height)/2; 168 fix = 0; 169 170 for (src=0;src<=64;src++) 171 { 172 startpix = fix>>16; 173 fix += step; 174 endpix = fix>>16; 175 176 if (endpix>startpix) 177 work->width[src] = endpix-startpix; 178 else 179 work->width[src] = 0; 180 181 // 182 // mark the start of the code 183 // 184 work->codeofs[src] = FP_OFF(code); 185 186 // 187 // compile some code if the source pixel generates any screen pixels 188 // 189 startpix+=toppix; 190 endpix+=toppix; 191 192 if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64) 193 continue; 194 195 // 196 // mov al,[si+src] 197 // 198 *code++ = 0x8a; 199 *code++ = 0x44; 200 *code++ = src; 201 202 for (;startpix<endpix;startpix++) 203 { 204 if (startpix >= viewheight) 205 break; // off the bottom of the view area 206 if (startpix < 0) 207 continue; // not into the view area 208 209 // 210 // mov [es:di+heightofs],al 211 // 212 *code++ = 0x26; 213 *code++ = 0x88; 214 *code++ = 0x85; 215 *((unsigned far *)code)++ = startpix*SCREENBWIDE; 216 } 217 218 } 219 220 // 221 // retf 222 // 223 *code++ = 0xcb; 224 225 totalsize = FP_OFF(code); 226 227 return totalsize; 228 } 229 230 231 /* 232 ======================= 233 = 234 = ScaleLine 235 = 236 = linescale should have the high word set to the segment of the scaler 237 = 238 ======================= 239 */ 240 241 extern int slinex,slinewidth; 242 extern unsigned far *linecmds; 243 extern long linescale; 244 extern unsigned maskword; 245 246 byte mask1,mask2,mask3; 247 248 249 void near ScaleLine (void) 250 { 251 asm mov cx,WORD PTR [linescale+2] 252 asm mov es,cx // segment of scaler 253 254 asm mov bp,WORD PTR [linecmds] 255 asm mov dx,SC_INDEX+1 // to set SC_MAPMASK 256 257 asm mov bx,[slinex] 258 asm mov di,bx 259 asm shr di,2 // X in bytes 260 asm add di,[bufferofs] 261 asm and bx,3 262 asm shl bx,3 263 asm add bx,[slinewidth] // bx = (pixel*8+pixwidth) 264 asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first 265 asm mov ds,WORD PTR [linecmds+2] 266 asm or al,al 267 asm jz notthreebyte // scale across three bytes 268 asm jmp threebyte 269 notthreebyte: 270 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first 271 asm or al,al 272 asm jnz twobyte // scale across two bytes 273 274 // 275 // one byte scaling 276 // 277 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first 278 asm out dx,al // set map mask register 279 280 scalesingle: 281 282 asm mov bx,[ds:bp] // table location of rtl to patch 283 asm or bx,bx 284 asm jz linedone // 0 signals end of segment list 285 asm mov bx,[es:bx] 286 asm mov dl,[es:bx] // save old value 287 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in 288 asm mov si,[ds:bp+4] // table location of entry spot 289 asm mov ax,[es:si] 290 asm mov WORD PTR ss:[linescale],ax // call here to start scaling 291 asm mov si,[ds:bp+2] // corrected top of shape for this segment 292 asm add bp,6 // next segment list 293 294 asm mov ax,SCREENSEG 295 asm mov es,ax 296 asm call ss:[linescale] // scale the segment of pixels 297 298 asm mov es,cx // segment of scaler 299 asm mov BYTE PTR es:[bx],dl // unpatch the RETF 300 asm jmp scalesingle // do the next segment 301 302 303 // 304 // done 305 // 306 linedone: 307 asm mov ax,ss 308 asm mov ds,ax 309 return; 310 311 // 312 // two byte scaling 313 // 314 twobyte: 315 asm mov ss:[mask2],al 316 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first 317 asm mov ss:[mask1],al 318 319 scaledouble: 320 321 asm mov bx,[ds:bp] // table location of rtl to patch 322 asm or bx,bx 323 asm jz linedone // 0 signals end of segment list 324 asm mov bx,[es:bx] 325 asm mov cl,[es:bx] // save old value 326 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in 327 asm mov si,[ds:bp+4] // table location of entry spot 328 asm mov ax,[es:si] 329 asm mov WORD PTR ss:[linescale],ax // call here to start scaling 330 asm mov si,[ds:bp+2] // corrected top of shape for this segment 331 asm add bp,6 // next segment list 332 333 asm mov ax,SCREENSEG 334 asm mov es,ax 335 asm mov al,ss:[mask1] 336 asm out dx,al // set map mask register 337 asm call ss:[linescale] // scale the segment of pixels 338 asm inc di 339 asm mov al,ss:[mask2] 340 asm out dx,al // set map mask register 341 asm call ss:[linescale] // scale the segment of pixels 342 asm dec di 343 344 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler 345 asm mov BYTE PTR es:[bx],cl // unpatch the RETF 346 asm jmp scaledouble // do the next segment 347 348 349 // 350 // three byte scaling 351 // 352 threebyte: 353 asm mov ss:[mask3],al 354 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first 355 asm mov ss:[mask2],al 356 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first 357 asm mov ss:[mask1],al 358 359 scaletriple: 360 361 asm mov bx,[ds:bp] // table location of rtl to patch 362 asm or bx,bx 363 asm jz linedone // 0 signals end of segment list 364 asm mov bx,[es:bx] 365 asm mov cl,[es:bx] // save old value 366 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in 367 asm mov si,[ds:bp+4] // table location of entry spot 368 asm mov ax,[es:si] 369 asm mov WORD PTR ss:[linescale],ax // call here to start scaling 370 asm mov si,[ds:bp+2] // corrected top of shape for this segment 371 asm add bp,6 // next segment list 372 373 asm mov ax,SCREENSEG 374 asm mov es,ax 375 asm mov al,ss:[mask1] 376 asm out dx,al // set map mask register 377 asm call ss:[linescale] // scale the segment of pixels 378 asm inc di 379 asm mov al,ss:[mask2] 380 asm out dx,al // set map mask register 381 asm call ss:[linescale] // scale the segment of pixels 382 asm inc di 383 asm mov al,ss:[mask3] 384 asm out dx,al // set map mask register 385 asm call ss:[linescale] // scale the segment of pixels 386 asm dec di 387 asm dec di 388 389 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler 390 asm mov BYTE PTR es:[bx],cl // unpatch the RETF 391 asm jmp scaletriple // do the next segment 392 393 394 } 395 396 397 /* 398 ======================= 399 = 400 = ScaleShape 401 = 402 = Draws a compiled shape at [scale] pixels high 403 = 404 = each vertical line of the shape has a pointer to segment data: 405 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler 406 = top of virtual line with segment in proper place 407 = start of segment pixel*2, used to jsl into compiled scaler 408 = <repeat> 409 = 410 = Setup for call 411 = -------------- 412 = GC_MODE read mode 1, write mode 2 413 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff 414 = GC_INDEX pointing at GC_BITMASK 415 = 416 ======================= 417 */ 418 419 static long longtemp; 420 421 void ScaleShape (int xcenter, int shapenum, unsigned height) 422 { 423 t_compshape _seg *shape; 424 t_compscale far *comptable; 425 unsigned scale,srcx,stopx,tempx; 426 int t; 427 unsigned far *cmdptr; 428 boolean leftvis,rightvis; 429 430 431 shape = PM_GetSpritePage (shapenum); 432 433 scale = height>>3; // low three bits are fractional 434 if (!scale || scale>maxscale) 435 return; // too close or far away 436 comptable = scaledirectory[scale]; 437 438 *(((unsigned *)&linescale)+1)=FP_SEG(comptable); // seg of far call 439 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape 440 441 // 442 // scale to the left (from pixel 31 to shape->leftpix) 443 // 444 srcx = 32; 445 slinex = xcenter; 446 stopx = shape->leftpix; 447 cmdptr = &shape->dataofs[31-stopx]; 448 449 while ( --srcx >=stopx && slinex>0) 450 { 451 (unsigned)linecmds = *cmdptr--; 452 if ( !(slinewidth = comptable->width[srcx]) ) 453 continue; 454 455 if (slinewidth == 1) 456 { 457 slinex--; 458 if (slinex<viewwidth) 459 { 460 if (wallheight[slinex] >= height) 461 continue; // obscured by closer wall 462 ScaleLine (); 463 } 464 continue; 465 } 466 467 // 468 // handle multi pixel lines 469 // 470 if (slinex>viewwidth) 471 { 472 slinex -= slinewidth; 473 slinewidth = viewwidth-slinex; 474 if (slinewidth<1) 475 continue; // still off the right side 476 } 477 else 478 { 479 if (slinewidth>slinex) 480 slinewidth = slinex; 481 slinex -= slinewidth; 482 } 483 484 485 leftvis = (wallheight[slinex] < height); 486 rightvis = (wallheight[slinex+slinewidth-1] < height); 487 488 if (leftvis) 489 { 490 if (rightvis) 491 ScaleLine (); 492 else 493 { 494 while (wallheight[slinex+slinewidth-1] >= height) 495 slinewidth--; 496 ScaleLine (); 497 } 498 } 499 else 500 { 501 if (!rightvis) 502 continue; // totally obscured 503 504 while (wallheight[slinex] >= height) 505 { 506 slinex++; 507 slinewidth--; 508 } 509 ScaleLine (); 510 break; // the rest of the shape is gone 511 } 512 } 513 514 515 // 516 // scale to the right 517 // 518 slinex = xcenter; 519 stopx = shape->rightpix; 520 if (shape->leftpix<31) 521 { 522 srcx = 31; 523 cmdptr = &shape->dataofs[32-shape->leftpix]; 524 } 525 else 526 { 527 srcx = shape->leftpix-1; 528 cmdptr = &shape->dataofs[0]; 529 } 530 slinewidth = 0; 531 532 while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth) 533 { 534 (unsigned)linecmds = *cmdptr++; 535 if ( !(slinewidth = comptable->width[srcx]) ) 536 continue; 537 538 if (slinewidth == 1) 539 { 540 if (slinex>=0 && wallheight[slinex] < height) 541 { 542 ScaleLine (); 543 } 544 continue; 545 } 546 547 // 548 // handle multi pixel lines 549 // 550 if (slinex<0) 551 { 552 if (slinewidth <= -slinex) 553 continue; // still off the left edge 554 555 slinewidth += slinex; 556 slinex = 0; 557 } 558 else 559 { 560 if (slinex + slinewidth > viewwidth) 561 slinewidth = viewwidth-slinex; 562 } 563 564 565 leftvis = (wallheight[slinex] < height); 566 rightvis = (wallheight[slinex+slinewidth-1] < height); 567 568 if (leftvis) 569 { 570 if (rightvis) 571 { 572 ScaleLine (); 573 } 574 else 575 { 576 while (wallheight[slinex+slinewidth-1] >= height) 577 slinewidth--; 578 ScaleLine (); 579 break; // the rest of the shape is gone 580 } 581 } 582 else 583 { 584 if (rightvis) 585 { 586 while (wallheight[slinex] >= height) 587 { 588 slinex++; 589 slinewidth--; 590 } 591 ScaleLine (); 592 } 593 else 594 continue; // totally obscured 595 } 596 } 597 } 598 599 600 601 /* 602 ======================= 603 = 604 = SimpleScaleShape 605 = 606 = NO CLIPPING, height in pixels 607 = 608 = Draws a compiled shape at [scale] pixels high 609 = 610 = each vertical line of the shape has a pointer to segment data: 611 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler 612 = top of virtual line with segment in proper place 613 = start of segment pixel*2, used to jsl into compiled scaler 614 = <repeat> 615 = 616 = Setup for call 617 = -------------- 618 = GC_MODE read mode 1, write mode 2 619 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff 620 = GC_INDEX pointing at GC_BITMASK 621 = 622 ======================= 623 */ 624 625 void SimpleScaleShape (int xcenter, int shapenum, unsigned height) 626 { 627 t_compshape _seg *shape; 628 t_compscale far *comptable; 629 unsigned scale,srcx,stopx,tempx; 630 int t; 631 unsigned far *cmdptr; 632 boolean leftvis,rightvis; 633 634 635 shape = PM_GetSpritePage (shapenum); 636 637 scale = height>>1; 638 comptable = scaledirectory[scale]; 639 640 *(((unsigned *)&linescale)+1)=FP_SEG(comptable); // seg of far call 641 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape 642 643 // 644 // scale to the left (from pixel 31 to shape->leftpix) 645 // 646 srcx = 32; 647 slinex = xcenter; 648 stopx = shape->leftpix; 649 cmdptr = &shape->dataofs[31-stopx]; 650 651 while ( --srcx >=stopx ) 652 { 653 (unsigned)linecmds = *cmdptr--; 654 if ( !(slinewidth = comptable->width[srcx]) ) 655 continue; 656 657 slinex -= slinewidth; 658 ScaleLine (); 659 } 660 661 662 // 663 // scale to the right 664 // 665 slinex = xcenter; 666 stopx = shape->rightpix; 667 if (shape->leftpix<31) 668 { 669 srcx = 31; 670 cmdptr = &shape->dataofs[32-shape->leftpix]; 671 } 672 else 673 { 674 srcx = shape->leftpix-1; 675 cmdptr = &shape->dataofs[0]; 676 } 677 slinewidth = 0; 678 679 while ( ++srcx <= stopx ) 680 { 681 (unsigned)linecmds = *cmdptr++; 682 if ( !(slinewidth = comptable->width[srcx]) ) 683 continue; 684 685 ScaleLine (); 686 slinex+=slinewidth; 687 } 688 } 689 690 691 692 693 // 694 // bit mask tables for drawing scaled strips up to eight pixels wide 695 // 696 // down here so the STUPID inline assembler doesn't get confused! 697 // 698 699 700 byte mapmasks1[4][8] = { 701 {1 ,3 ,7 ,15,15,15,15,15}, 702 {2 ,6 ,14,14,14,14,14,14}, 703 {4 ,12,12,12,12,12,12,12}, 704 {8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} }; 705 706 byte mapmasks2[4][8] = { 707 {0 ,0 ,0 ,0 ,1 ,3 ,7 ,15}, 708 {0 ,0 ,0 ,1 ,3 ,7 ,15,15}, 709 {0 ,0 ,1 ,3 ,7 ,15,15,15}, 710 {0 ,1 ,3 ,7 ,15,15,15,15} }; 711 712 byte mapmasks3[4][8] = { 713 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0}, 714 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,1}, 715 {0 ,0 ,0 ,0 ,0 ,0 ,1 ,3}, 716 {0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} }; 717 718 719 unsigned wordmasks[8][8] = { 720 {0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff}, 721 {0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f}, 722 {0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f}, 723 {0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f}, 724 {0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f}, 725 {0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807}, 726 {0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03}, 727 {0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} }; 728 729 int slinex,slinewidth; 730 unsigned far *linecmds; 731 long linescale; 732 unsigned maskword; 733