WL_SCALE.C (15301B)
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 _seg *scaledirectory[MAXSCALEHEIGHT+1]; 17 long fullscalefarcall[MAXSCALEHEIGHT+1]; 18 19 int maxscale,maxscaleshl2; 20 21 boolean insetupscaling; 22 23 /* 24 ============================================================================= 25 26 LOCALS 27 28 ============================================================================= 29 */ 30 31 t_compscale _seg *work; 32 unsigned BuildCompScale (int height, memptr *finalspot); 33 34 int stepbytwo; 35 36 //=========================================================================== 37 38 /* 39 ============== 40 = 41 = BadScale 42 = 43 ============== 44 */ 45 46 void far BadScale (void) 47 { 48 Quit ("BadScale called!"); 49 } 50 51 52 /* 53 ========================== 54 = 55 = SetupScaling 56 = 57 ========================== 58 */ 59 60 void SetupScaling (int maxscaleheight) 61 { 62 int i,x,y; 63 byte far *dest; 64 65 insetupscaling = true; 66 67 maxscaleheight/=2; // one scaler every two pixels 68 69 maxscale = maxscaleheight-1; 70 maxscaleshl2 = maxscale<<2; 71 72 // 73 // free up old scalers 74 // 75 for (i=1;i<MAXSCALEHEIGHT;i++) 76 { 77 if (scaledirectory[i]) 78 MM_FreePtr (&(memptr)scaledirectory[i]); 79 if (i>=stepbytwo) 80 i += 2; 81 } 82 memset (scaledirectory,0,sizeof(scaledirectory)); 83 84 MM_SortMem (); 85 86 // 87 // build the compiled scalers 88 // 89 stepbytwo = viewheight/2; // save space by double stepping 90 MM_GetPtr (&(memptr)work,20000); 91 92 for (i=1;i<=maxscaleheight;i++) 93 { 94 BuildCompScale (i*2,&(memptr)scaledirectory[i]); 95 if (i>=stepbytwo) 96 i+= 2; 97 } 98 MM_FreePtr (&(memptr)work); 99 100 // 101 // compact memory and lock down scalers 102 // 103 MM_SortMem (); 104 for (i=1;i<=maxscaleheight;i++) 105 { 106 MM_SetLock (&(memptr)scaledirectory[i],true); 107 fullscalefarcall[i] = (unsigned)scaledirectory[i]; 108 fullscalefarcall[i] <<=16; 109 fullscalefarcall[i] += scaledirectory[i]->codeofs[0]; 110 if (i>=stepbytwo) 111 { 112 scaledirectory[i+1] = scaledirectory[i]; 113 fullscalefarcall[i+1] = fullscalefarcall[i]; 114 scaledirectory[i+2] = scaledirectory[i]; 115 fullscalefarcall[i+2] = fullscalefarcall[i]; 116 i+=2; 117 } 118 } 119 scaledirectory[0] = scaledirectory[1]; 120 fullscalefarcall[0] = fullscalefarcall[1]; 121 122 // 123 // check for oversize wall drawing 124 // 125 for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++) 126 fullscalefarcall[i] = (long)BadScale; 127 128 insetupscaling = false; 129 } 130 131 //=========================================================================== 132 133 /* 134 ======================== 135 = 136 = BuildCompScale 137 = 138 = Builds a compiled scaler object that will scale a 64 tall object to 139 = the given height (centered vertically on the screen) 140 = 141 = height should be even 142 = 143 = Call with 144 = --------- 145 = DS:SI Source for scale 146 = ES:DI Dest for scale 147 = 148 = Calling the compiled scaler only destroys AL 149 = 150 ======================== 151 */ 152 153 unsigned BuildCompScale (int height, memptr *finalspot) 154 { 155 byte far *code; 156 157 int i; 158 long fix,step; 159 unsigned src,totalscaled,totalsize; 160 int startpix,endpix,toppix; 161 162 163 step = ((long)height<<16) / 64; 164 code = &work->code[0]; 165 toppix = (viewheight-height)/2; 166 fix = 0; 167 168 for (src=0;src<=64;src++) 169 { 170 startpix = fix>>16; 171 fix += step; 172 endpix = fix>>16; 173 174 if (endpix>startpix) 175 work->width[src] = endpix-startpix; 176 else 177 work->width[src] = 0; 178 179 // 180 // mark the start of the code 181 // 182 work->codeofs[src] = FP_OFF(code); 183 184 // 185 // compile some code if the source pixel generates any screen pixels 186 // 187 startpix+=toppix; 188 endpix+=toppix; 189 190 if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64) 191 continue; 192 193 // 194 // mov al,[si+src] 195 // 196 *code++ = 0x8a; 197 *code++ = 0x44; 198 *code++ = src; 199 200 for (;startpix<endpix;startpix++) 201 { 202 if (startpix >= viewheight) 203 break; // off the bottom of the view area 204 if (startpix < 0) 205 continue; // not into the view area 206 207 // 208 // mov [es:di+heightofs],al 209 // 210 *code++ = 0x26; 211 *code++ = 0x88; 212 *code++ = 0x85; 213 *((unsigned far *)code)++ = startpix*SCREENBWIDE; 214 } 215 216 } 217 218 // 219 // retf 220 // 221 *code++ = 0xcb; 222 223 totalsize = FP_OFF(code); 224 MM_GetPtr (finalspot,totalsize); 225 _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize); 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 _seg *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)=(unsigned)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 _seg *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)=(unsigned)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