9 =============================================================================
\r
13 =============================================================================
\r
16 t_compscale far *scaledirectory[MAXSCALEHEIGHT+1];
\r
17 long fullscalefarcall[MAXSCALEHEIGHT+1];
\r
19 int maxscale,maxscaleshl2;
\r
21 byte far *scalermemory;
\r
22 byte _seg *endscalermemory;
\r
23 long freescalermemory;
\r
27 =============================================================================
\r
31 =============================================================================
\r
34 unsigned BuildCompScale (int height, byte far *code);
\r
38 //===========================================================================
\r
48 void far BadScale (void)
\r
50 Quit ("BadScale called!");
\r
55 ==========================
\r
59 ==========================
\r
62 long SetupScaling (int maxscaleheight)
\r
70 maxscaleheight/=2; // one scaler every two pixels
\r
72 maxscale = maxscaleheight-1;
\r
73 maxscaleshl2 = maxscale<<2;
\r
75 dest = scalermemory;
\r
78 // build the compiled scalers
\r
80 stepbytwo = viewheight/2; // save space by double stepping
\r
82 for (i=1;i<=maxscaleheight;i++)
\r
85 ofs = (FP_OFF(dest)+15)&~15;
\r
86 dest = MK_FP(seg+ofs/16,0);
\r
88 scaledirectory[i] = (t_compscale far *)dest;
\r
89 size = BuildCompScale (i*2,dest);
\r
92 if ((byte huge *)dest-(byte huge *)scalermemory > MAXSCALERMEMORY)
\r
93 Quit ("Compiled scalars exceeded allocated space!");
\r
100 // get far call addresses
\r
102 for (i=1;i<=maxscaleheight;i++)
\r
104 fullscalefarcall[i] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0];
\r
107 scaledirectory[i+1] = scaledirectory[i];
\r
108 fullscalefarcall[i+1] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0];
\r
109 scaledirectory[i+2] = scaledirectory[i];
\r
110 fullscalefarcall[i+2] = (long)scaledirectory[i] + scaledirectory[i]->codeofs[0];
\r
114 scaledirectory[0] = scaledirectory[1];
\r
115 fullscalefarcall[0] = fullscalefarcall[1];
\r
118 // check for oversize wall drawing
\r
120 for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++)
\r
121 fullscalefarcall[i] = (long)BadScale;
\r
123 seg = FP_SEG(dest);
\r
124 ofs = (FP_OFF(dest)+15)&~15;
\r
125 endscalermemory = (void _seg *)(seg+ofs/16);
\r
126 size = (byte huge *)dest-(byte huge *)scalermemory;
\r
127 freescalermemory = MAXSCALERMEMORY-16-size;
\r
132 //===========================================================================
\r
135 ========================
\r
139 = Builds a compiled scaler object that will scale a 64 tall object to
\r
140 = the given height (centered vertically on the screen)
\r
142 = height should be even
\r
146 = DS:SI Source for scale
\r
147 = ES:DI Dest for scale
\r
149 = Calling the compiled scaler only destroys AL
\r
151 ========================
\r
154 unsigned BuildCompScale (int height, byte far *code)
\r
156 t_compscale far *work;
\r
160 unsigned src,totalscaled,totalsize;
\r
161 int startpix,endpix,toppix;
\r
163 work = (t_compscale far *)code;
\r
165 step = ((long)height<<16) / 64;
\r
166 code = &work->code[0];
\r
167 toppix = (viewheight-height)/2;
\r
170 for (src=0;src<=64;src++)
\r
172 startpix = fix>>16;
\r
176 if (endpix>startpix)
\r
177 work->width[src] = endpix-startpix;
\r
179 work->width[src] = 0;
\r
182 // mark the start of the code
\r
184 work->codeofs[src] = FP_OFF(code);
\r
187 // compile some code if the source pixel generates any screen pixels
\r
192 if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64)
\r
202 for (;startpix<endpix;startpix++)
\r
204 if (startpix >= viewheight)
\r
205 break; // off the bottom of the view area
\r
207 continue; // not into the view area
\r
210 // mov [es:di+heightofs],al
\r
215 *((unsigned far *)code)++ = startpix*SCREENBWIDE;
\r
225 totalsize = FP_OFF(code);
\r
232 =======================
\r
236 = linescale should have the high word set to the segment of the scaler
\r
238 =======================
\r
241 extern int slinex,slinewidth;
\r
242 extern unsigned far *linecmds;
\r
243 extern long linescale;
\r
244 extern unsigned maskword;
\r
246 byte mask1,mask2,mask3;
\r
249 void near ScaleLine (void)
\r
251 asm mov cx,WORD PTR [linescale+2]
\r
252 asm mov es,cx // segment of scaler
\r
254 asm mov bp,WORD PTR [linecmds]
\r
255 asm mov dx,SC_INDEX+1 // to set SC_MAPMASK
\r
257 asm mov bx,[slinex]
\r
260 asm shr di,2 // X in bytes
\r
262 asm shr di,1 // X in bytes
\r
264 /* end 8086 hack */
\r
265 asm add di,[bufferofs]
\r
274 /* end 8086 hack */
\r
275 asm add bx,[slinewidth] // bx = (pixel*8+pixwidth)
\r
276 asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first
\r
277 asm mov ds,WORD PTR [linecmds+2]
\r
279 asm jz notthreebyte // scale across three bytes
\r
282 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
284 asm jnz twobyte // scale across two bytes
\r
287 // one byte scaling
\r
289 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
290 asm out dx,al // set map mask register
\r
294 asm mov bx,[ds:bp] // table location of rtl to patch
\r
296 asm jz linedone // 0 signals end of segment list
\r
298 asm mov dl,[es:bx] // save old value
\r
299 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
300 asm mov si,[ds:bp+4] // table location of entry spot
\r
302 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
303 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
304 asm add bp,6 // next segment list
\r
306 asm mov ax,SCREENSEG
\r
308 asm call ss:[linescale] // scale the segment of pixels
\r
310 asm mov es,cx // segment of scaler
\r
311 asm mov BYTE PTR es:[bx],dl // unpatch the RETF
\r
312 asm jmp scalesingle // do the next segment
\r
324 // two byte scaling
\r
327 asm mov ss:[mask2],al
\r
328 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
329 asm mov ss:[mask1],al
\r
333 asm mov bx,[ds:bp] // table location of rtl to patch
\r
335 asm jz linedone // 0 signals end of segment list
\r
337 asm mov cl,[es:bx] // save old value
\r
338 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
339 asm mov si,[ds:bp+4] // table location of entry spot
\r
341 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
342 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
343 asm add bp,6 // next segment list
\r
345 asm mov ax,SCREENSEG
\r
347 asm mov al,ss:[mask1]
\r
348 asm out dx,al // set map mask register
\r
349 asm call ss:[linescale] // scale the segment of pixels
\r
351 asm mov al,ss:[mask2]
\r
352 asm out dx,al // set map mask register
\r
353 asm call ss:[linescale] // scale the segment of pixels
\r
356 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
357 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
358 asm jmp scaledouble // do the next segment
\r
362 // three byte scaling
\r
365 asm mov ss:[mask3],al
\r
366 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
367 asm mov ss:[mask2],al
\r
368 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
369 asm mov ss:[mask1],al
\r
373 asm mov bx,[ds:bp] // table location of rtl to patch
\r
375 asm jz linedone // 0 signals end of segment list
\r
377 asm mov cl,[es:bx] // save old value
\r
378 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
379 asm mov si,[ds:bp+4] // table location of entry spot
\r
381 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
382 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
383 asm add bp,6 // next segment list
\r
385 asm mov ax,SCREENSEG
\r
387 asm mov al,ss:[mask1]
\r
388 asm out dx,al // set map mask register
\r
389 asm call ss:[linescale] // scale the segment of pixels
\r
391 asm mov al,ss:[mask2]
\r
392 asm out dx,al // set map mask register
\r
393 asm call ss:[linescale] // scale the segment of pixels
\r
395 asm mov al,ss:[mask3]
\r
396 asm out dx,al // set map mask register
\r
397 asm call ss:[linescale] // scale the segment of pixels
\r
401 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
402 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
403 asm jmp scaletriple // do the next segment
\r
410 =======================
\r
414 = Draws a compiled shape at [scale] pixels high
\r
416 = each vertical line of the shape has a pointer to segment data:
\r
417 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
418 = top of virtual line with segment in proper place
\r
419 = start of segment pixel*2, used to jsl into compiled scaler
\r
424 = GC_MODE read mode 1, write mode 2
\r
425 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
426 = GC_INDEX pointing at GC_BITMASK
\r
428 =======================
\r
431 static long longtemp;
\r
433 void ScaleShape (int xcenter, int shapenum, unsigned height)
\r
435 t_compshape _seg *shape;
\r
436 t_compscale far *comptable;
\r
437 unsigned scale,srcx,stopx,tempx;
\r
439 unsigned far *cmdptr;
\r
440 boolean leftvis,rightvis;
\r
443 shape = PM_GetSpritePage (shapenum);
\r
445 scale = height>>3; // low three bits are fractional
\r
446 if (!scale || scale>maxscale)
\r
447 return; // too close or far away
\r
448 comptable = scaledirectory[scale];
\r
450 *(((unsigned *)&linescale)+1)=FP_SEG(comptable); // seg of far call
\r
451 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
454 // scale to the left (from pixel 31 to shape->leftpix)
\r
458 stopx = shape->leftpix;
\r
459 cmdptr = &shape->dataofs[31-stopx];
\r
461 while ( --srcx >=stopx && slinex>0)
\r
463 (unsigned)linecmds = *cmdptr--;
\r
464 if ( !(slinewidth = comptable->width[srcx]) )
\r
467 if (slinewidth == 1)
\r
470 if (slinex<viewwidth)
\r
472 if (wallheight[slinex] >= height)
\r
473 continue; // obscured by closer wall
\r
480 // handle multi pixel lines
\r
482 if (slinex>viewwidth)
\r
484 slinex -= slinewidth;
\r
485 slinewidth = viewwidth-slinex;
\r
487 continue; // still off the right side
\r
491 if (slinewidth>slinex)
\r
492 slinewidth = slinex;
\r
493 slinex -= slinewidth;
\r
497 leftvis = (wallheight[slinex] < height);
\r
498 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
506 while (wallheight[slinex+slinewidth-1] >= height)
\r
514 continue; // totally obscured
\r
516 while (wallheight[slinex] >= height)
\r
522 break; // the rest of the shape is gone
\r
528 // scale to the right
\r
531 stopx = shape->rightpix;
\r
532 if (shape->leftpix<31)
\r
535 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
539 srcx = shape->leftpix-1;
\r
540 cmdptr = &shape->dataofs[0];
\r
544 while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth)
\r
546 (unsigned)linecmds = *cmdptr++;
\r
547 if ( !(slinewidth = comptable->width[srcx]) )
\r
550 if (slinewidth == 1)
\r
552 if (slinex>=0 && wallheight[slinex] < height)
\r
560 // handle multi pixel lines
\r
564 if (slinewidth <= -slinex)
\r
565 continue; // still off the left edge
\r
567 slinewidth += slinex;
\r
572 if (slinex + slinewidth > viewwidth)
\r
573 slinewidth = viewwidth-slinex;
\r
577 leftvis = (wallheight[slinex] < height);
\r
578 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
588 while (wallheight[slinex+slinewidth-1] >= height)
\r
591 break; // the rest of the shape is gone
\r
598 while (wallheight[slinex] >= height)
\r
606 continue; // totally obscured
\r
614 =======================
\r
618 = NO CLIPPING, height in pixels
\r
620 = Draws a compiled shape at [scale] pixels high
\r
622 = each vertical line of the shape has a pointer to segment data:
\r
623 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
624 = top of virtual line with segment in proper place
\r
625 = start of segment pixel*2, used to jsl into compiled scaler
\r
630 = GC_MODE read mode 1, write mode 2
\r
631 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
632 = GC_INDEX pointing at GC_BITMASK
\r
634 =======================
\r
637 void SimpleScaleShape (int xcenter, int shapenum, unsigned height)
\r
639 t_compshape _seg *shape;
\r
640 t_compscale far *comptable;
\r
641 unsigned scale,srcx,stopx,tempx;
\r
643 unsigned far *cmdptr;
\r
644 boolean leftvis,rightvis;
\r
647 shape = PM_GetSpritePage (shapenum);
\r
650 comptable = scaledirectory[scale];
\r
652 *(((unsigned *)&linescale)+1)=FP_SEG(comptable); // seg of far call
\r
653 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
656 // scale to the left (from pixel 31 to shape->leftpix)
\r
660 stopx = shape->leftpix;
\r
661 cmdptr = &shape->dataofs[31-stopx];
\r
663 while ( --srcx >=stopx )
\r
665 (unsigned)linecmds = *cmdptr--;
\r
666 if ( !(slinewidth = comptable->width[srcx]) )
\r
669 slinex -= slinewidth;
\r
675 // scale to the right
\r
678 stopx = shape->rightpix;
\r
679 if (shape->leftpix<31)
\r
682 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
686 srcx = shape->leftpix-1;
\r
687 cmdptr = &shape->dataofs[0];
\r
691 while ( ++srcx <= stopx )
\r
693 (unsigned)linecmds = *cmdptr++;
\r
694 if ( !(slinewidth = comptable->width[srcx]) )
\r
698 slinex+=slinewidth;
\r
706 // bit mask tables for drawing scaled strips up to eight pixels wide
\r
708 // down here so the STUPID inline assembler doesn't get confused!
\r
712 byte mapmasks1[4][8] = {
\r
713 {1 ,3 ,7 ,15,15,15,15,15},
\r
714 {2 ,6 ,14,14,14,14,14,14},
\r
715 {4 ,12,12,12,12,12,12,12},
\r
716 {8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };
\r
718 byte mapmasks2[4][8] = {
\r
719 {0 ,0 ,0 ,0 ,1 ,3 ,7 ,15},
\r
720 {0 ,0 ,0 ,1 ,3 ,7 ,15,15},
\r
721 {0 ,0 ,1 ,3 ,7 ,15,15,15},
\r
722 {0 ,1 ,3 ,7 ,15,15,15,15} };
\r
724 byte mapmasks3[4][8] = {
\r
725 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0},
\r
726 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},
\r
727 {0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},
\r
728 {0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} };
\r
731 unsigned wordmasks[8][8] = {
\r
732 {0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff},
\r
733 {0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f},
\r
734 {0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f},
\r
735 {0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f},
\r
736 {0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f},
\r
737 {0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807},
\r
738 {0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03},
\r
739 {0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} };
\r
741 int slinex,slinewidth;
\r
742 unsigned far *linecmds;
\r