9 =============================================================================
\r
13 =============================================================================
\r
16 t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1];
\r
17 long fullscalefarcall[MAXSCALEHEIGHT+1];
\r
19 int maxscale,maxscaleshl2;
\r
21 boolean insetupscaling;
\r
24 =============================================================================
\r
28 =============================================================================
\r
31 t_compscale _seg *work;
\r
32 unsigned BuildCompScale (int height, memptr *finalspot);
\r
36 //===========================================================================
\r
46 void far BadScale (void)
\r
48 Quit ("BadScale called!");
\r
53 ==========================
\r
57 ==========================
\r
60 void SetupScaling (int maxscaleheight)
\r
65 insetupscaling = true;
\r
67 maxscaleheight/=2; // one scaler every two pixels
\r
69 maxscale = maxscaleheight-1;
\r
70 maxscaleshl2 = maxscale<<2;
\r
73 // free up old scalers
\r
75 for (i=1;i<MAXSCALEHEIGHT;i++)
\r
77 if (scaledirectory[i])
\r
78 MM_FreePtr (&(memptr)scaledirectory[i]);
\r
82 memset (scaledirectory,0,sizeof(scaledirectory));
\r
87 // build the compiled scalers
\r
89 stepbytwo = viewheight/2; // save space by double stepping
\r
90 MM_GetPtr (&(memptr)work,20000);
\r
92 for (i=1;i<=maxscaleheight;i++)
\r
94 BuildCompScale (i*2,&(memptr)scaledirectory[i]);
\r
98 MM_FreePtr (&(memptr)work);
\r
101 // compact memory and lock down scalers
\r
104 for (i=1;i<=maxscaleheight;i++)
\r
106 MM_SetLock (&(memptr)scaledirectory[i],true);
\r
107 fullscalefarcall[i] = (unsigned)scaledirectory[i];
\r
108 fullscalefarcall[i] <<=16;
\r
109 fullscalefarcall[i] += scaledirectory[i]->codeofs[0];
\r
112 scaledirectory[i+1] = scaledirectory[i];
\r
113 fullscalefarcall[i+1] = fullscalefarcall[i];
\r
114 scaledirectory[i+2] = scaledirectory[i];
\r
115 fullscalefarcall[i+2] = fullscalefarcall[i];
\r
119 scaledirectory[0] = scaledirectory[1];
\r
120 fullscalefarcall[0] = fullscalefarcall[1];
\r
123 // check for oversize wall drawing
\r
125 for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++)
\r
126 fullscalefarcall[i] = (long)BadScale;
\r
128 insetupscaling = false;
\r
131 //===========================================================================
\r
134 ========================
\r
138 = Builds a compiled scaler object that will scale a 64 tall object to
\r
139 = the given height (centered vertically on the screen)
\r
141 = height should be even
\r
145 = DS:SI Source for scale
\r
146 = ES:DI Dest for scale
\r
148 = Calling the compiled scaler only destroys AL
\r
150 ========================
\r
153 unsigned BuildCompScale (int height, memptr *finalspot)
\r
159 unsigned src,totalscaled,totalsize;
\r
160 int startpix,endpix,toppix;
\r
163 step = ((long)height<<16) / 64;
\r
164 code = &work->code[0];
\r
165 toppix = (viewheight-height)/2;
\r
168 for (src=0;src<=64;src++)
\r
170 startpix = fix>>16;
\r
174 if (endpix>startpix)
\r
175 work->width[src] = endpix-startpix;
\r
177 work->width[src] = 0;
\r
180 // mark the start of the code
\r
182 work->codeofs[src] = FP_OFF(code);
\r
185 // compile some code if the source pixel generates any screen pixels
\r
190 if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64)
\r
200 for (;startpix<endpix;startpix++)
\r
202 if (startpix >= viewheight)
\r
203 break; // off the bottom of the view area
\r
205 continue; // not into the view area
\r
208 // mov [es:di+heightofs],al
\r
213 *((unsigned far *)code)++ = startpix*SCREENBWIDE;
\r
223 totalsize = FP_OFF(code);
\r
224 MM_GetPtr (finalspot,totalsize);
\r
225 _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
\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
259 asm shr di,1 // X in bytes
\r
261 asm add di,[bufferofs]
\r
270 /* end 8086 hack */
\r
271 asm add bx,[slinewidth] // bx = (pixel*8+pixwidth)
\r
272 asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first
\r
273 asm mov ds,WORD PTR [linecmds+2]
\r
275 asm jz notthreebyte // scale across three bytes
\r
278 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
280 asm jnz twobyte // scale across two bytes
\r
283 // one byte scaling
\r
285 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
286 asm out dx,al // set map mask register
\r
290 asm mov bx,[ds:bp] // table location of rtl to patch
\r
292 asm jz linedone // 0 signals end of segment list
\r
294 asm mov dl,[es:bx] // save old value
\r
295 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
296 asm mov si,[ds:bp+4] // table location of entry spot
\r
298 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
299 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
300 asm add bp,6 // next segment list
\r
302 asm mov ax,SCREENSEG
\r
304 asm call ss:[linescale] // scale the segment of pixels
\r
306 asm mov es,cx // segment of scaler
\r
307 asm mov BYTE PTR es:[bx],dl // unpatch the RETF
\r
308 asm jmp scalesingle // do the next segment
\r
320 // two byte scaling
\r
323 asm mov ss:[mask2],al
\r
324 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
325 asm mov ss:[mask1],al
\r
329 asm mov bx,[ds:bp] // table location of rtl to patch
\r
331 asm jz linedone // 0 signals end of segment list
\r
333 asm mov cl,[es:bx] // save old value
\r
334 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
335 asm mov si,[ds:bp+4] // table location of entry spot
\r
337 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
338 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
339 asm add bp,6 // next segment list
\r
341 asm mov ax,SCREENSEG
\r
343 asm mov al,ss:[mask1]
\r
344 asm out dx,al // set map mask register
\r
345 asm call ss:[linescale] // scale the segment of pixels
\r
347 asm mov al,ss:[mask2]
\r
348 asm out dx,al // set map mask register
\r
349 asm call ss:[linescale] // scale the segment of pixels
\r
352 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
353 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
354 asm jmp scaledouble // do the next segment
\r
358 // three byte scaling
\r
361 asm mov ss:[mask3],al
\r
362 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
363 asm mov ss:[mask2],al
\r
364 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
365 asm mov ss:[mask1],al
\r
369 asm mov bx,[ds:bp] // table location of rtl to patch
\r
371 asm jz linedone // 0 signals end of segment list
\r
373 asm mov cl,[es:bx] // save old value
\r
374 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
375 asm mov si,[ds:bp+4] // table location of entry spot
\r
377 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
378 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
379 asm add bp,6 // next segment list
\r
381 asm mov ax,SCREENSEG
\r
383 asm mov al,ss:[mask1]
\r
384 asm out dx,al // set map mask register
\r
385 asm call ss:[linescale] // scale the segment of pixels
\r
387 asm mov al,ss:[mask2]
\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:[mask3]
\r
392 asm out dx,al // set map mask register
\r
393 asm call ss:[linescale] // scale the segment of pixels
\r
397 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
398 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
399 asm jmp scaletriple // do the next segment
\r
406 =======================
\r
410 = Draws a compiled shape at [scale] pixels high
\r
412 = each vertical line of the shape has a pointer to segment data:
\r
413 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
414 = top of virtual line with segment in proper place
\r
415 = start of segment pixel*2, used to jsl into compiled scaler
\r
420 = GC_MODE read mode 1, write mode 2
\r
421 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
422 = GC_INDEX pointing at GC_BITMASK
\r
424 =======================
\r
427 static long longtemp;
\r
429 void ScaleShape (int xcenter, int shapenum, unsigned height)
\r
431 t_compshape _seg *shape;
\r
432 t_compscale _seg *comptable;
\r
433 unsigned scale,srcx,stopx,tempx;
\r
435 unsigned far *cmdptr;
\r
436 boolean leftvis,rightvis;
\r
439 shape = PM_GetSpritePage (shapenum);
\r
441 scale = height>>3; // low three bits are fractional
\r
442 if (!scale || scale>maxscale)
\r
443 return; // too close or far away
\r
444 comptable = scaledirectory[scale];
\r
446 *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call
\r
447 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
450 // scale to the left (from pixel 31 to shape->leftpix)
\r
454 stopx = shape->leftpix;
\r
455 cmdptr = &shape->dataofs[31-stopx];
\r
457 while ( --srcx >=stopx && slinex>0)
\r
459 (unsigned)linecmds = *cmdptr--;
\r
460 if ( !(slinewidth = comptable->width[srcx]) )
\r
463 if (slinewidth == 1)
\r
466 if (slinex<viewwidth)
\r
468 if (wallheight[slinex] >= height)
\r
469 continue; // obscured by closer wall
\r
476 // handle multi pixel lines
\r
478 if (slinex>viewwidth)
\r
480 slinex -= slinewidth;
\r
481 slinewidth = viewwidth-slinex;
\r
483 continue; // still off the right side
\r
487 if (slinewidth>slinex)
\r
488 slinewidth = slinex;
\r
489 slinex -= slinewidth;
\r
493 leftvis = (wallheight[slinex] < height);
\r
494 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
502 while (wallheight[slinex+slinewidth-1] >= height)
\r
510 continue; // totally obscured
\r
512 while (wallheight[slinex] >= height)
\r
518 break; // the rest of the shape is gone
\r
524 // scale to the right
\r
527 stopx = shape->rightpix;
\r
528 if (shape->leftpix<31)
\r
531 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
535 srcx = shape->leftpix-1;
\r
536 cmdptr = &shape->dataofs[0];
\r
540 while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth)
\r
542 (unsigned)linecmds = *cmdptr++;
\r
543 if ( !(slinewidth = comptable->width[srcx]) )
\r
546 if (slinewidth == 1)
\r
548 if (slinex>=0 && wallheight[slinex] < height)
\r
556 // handle multi pixel lines
\r
560 if (slinewidth <= -slinex)
\r
561 continue; // still off the left edge
\r
563 slinewidth += slinex;
\r
568 if (slinex + slinewidth > viewwidth)
\r
569 slinewidth = viewwidth-slinex;
\r
573 leftvis = (wallheight[slinex] < height);
\r
574 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
584 while (wallheight[slinex+slinewidth-1] >= height)
\r
587 break; // the rest of the shape is gone
\r
594 while (wallheight[slinex] >= height)
\r
602 continue; // totally obscured
\r
610 =======================
\r
614 = NO CLIPPING, height in pixels
\r
616 = Draws a compiled shape at [scale] pixels high
\r
618 = each vertical line of the shape has a pointer to segment data:
\r
619 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
620 = top of virtual line with segment in proper place
\r
621 = start of segment pixel*2, used to jsl into compiled scaler
\r
626 = GC_MODE read mode 1, write mode 2
\r
627 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
628 = GC_INDEX pointing at GC_BITMASK
\r
630 =======================
\r
633 void SimpleScaleShape (int xcenter, int shapenum, unsigned height)
\r
635 t_compshape _seg *shape;
\r
636 t_compscale _seg *comptable;
\r
637 unsigned scale,srcx,stopx,tempx;
\r
639 unsigned far *cmdptr;
\r
640 boolean leftvis,rightvis;
\r
643 shape = PM_GetSpritePage (shapenum);
\r
646 comptable = scaledirectory[scale];
\r
648 *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call
\r
649 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
652 // scale to the left (from pixel 31 to shape->leftpix)
\r
656 stopx = shape->leftpix;
\r
657 cmdptr = &shape->dataofs[31-stopx];
\r
659 while ( --srcx >=stopx )
\r
661 (unsigned)linecmds = *cmdptr--;
\r
662 if ( !(slinewidth = comptable->width[srcx]) )
\r
665 slinex -= slinewidth;
\r
671 // scale to the right
\r
674 stopx = shape->rightpix;
\r
675 if (shape->leftpix<31)
\r
678 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
682 srcx = shape->leftpix-1;
\r
683 cmdptr = &shape->dataofs[0];
\r
687 while ( ++srcx <= stopx )
\r
689 (unsigned)linecmds = *cmdptr++;
\r
690 if ( !(slinewidth = comptable->width[srcx]) )
\r
694 slinex+=slinewidth;
\r
702 // bit mask tables for drawing scaled strips up to eight pixels wide
\r
704 // down here so the STUPID inline assembler doesn't get confused!
\r
708 byte mapmasks1[4][8] = {
\r
709 {1 ,3 ,7 ,15,15,15,15,15},
\r
710 {2 ,6 ,14,14,14,14,14,14},
\r
711 {4 ,12,12,12,12,12,12,12},
\r
712 {8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };
\r
714 byte mapmasks2[4][8] = {
\r
715 {0 ,0 ,0 ,0 ,1 ,3 ,7 ,15},
\r
716 {0 ,0 ,0 ,1 ,3 ,7 ,15,15},
\r
717 {0 ,0 ,1 ,3 ,7 ,15,15,15},
\r
718 {0 ,1 ,3 ,7 ,15,15,15,15} };
\r
720 byte mapmasks3[4][8] = {
\r
721 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0},
\r
722 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},
\r
723 {0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},
\r
724 {0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} };
\r
727 unsigned wordmasks[8][8] = {
\r
728 {0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff},
\r
729 {0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f},
\r
730 {0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f},
\r
731 {0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f},
\r
732 {0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f},
\r
733 {0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807},
\r
734 {0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03},
\r
735 {0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} };
\r
737 int slinex,slinewidth;
\r
738 unsigned far *linecmds;
\r