9 =============================================================================
\r
13 =============================================================================
\r
16 t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1];
\r
17 long fullscalefarcall[MAXSCALEHEIGHT+1];
\r
19 int maxscale,maxscaleshl2;
\r
22 =============================================================================
\r
26 =============================================================================
\r
29 t_compscale _seg *work;
\r
30 unsigned BuildCompScale (int height, memptr *finalspot);
\r
34 //===========================================================================
\r
44 void far BadScale (void)
\r
46 Quit ("BadScale called!");
\r
51 ==========================
\r
55 ==========================
\r
58 void SetupScaling (int maxscaleheight)
\r
63 maxscaleheight/=2; // one scaler every two pixels
\r
65 maxscale = maxscaleheight-1;
\r
66 maxscaleshl2 = maxscale<<2;
\r
69 // free up old scalers
\r
71 for (i=1;i<MAXSCALEHEIGHT;i++)
\r
73 if (scaledirectory[i])
\r
74 MM_FreePtr (&(memptr)scaledirectory[i]);
\r
78 memset (scaledirectory,0,sizeof(scaledirectory));
\r
83 // build the compiled scalers
\r
85 stepbytwo = viewheight/2; // save space by double stepping
\r
86 MM_GetPtr (&(memptr)work,20000);
\r
90 for (i=1;i<=maxscaleheight;i++)
\r
92 BuildCompScale (i*2,&(memptr)scaledirectory[i]);
\r
95 MM_FreePtr (&(memptr)work);
\r
101 MM_FreePtr (&(memptr)work);
\r
104 // compact memory and lock down scalers
\r
107 for (i=1;i<=maxscaleheight;i++)
\r
109 MM_SetLock (&(memptr)scaledirectory[i],true);
\r
110 fullscalefarcall[i] = (unsigned)scaledirectory[i];
\r
111 fullscalefarcall[i] <<=16;
\r
112 fullscalefarcall[i] += scaledirectory[i]->codeofs[0];
\r
115 scaledirectory[i+1] = scaledirectory[i];
\r
116 fullscalefarcall[i+1] = fullscalefarcall[i];
\r
117 scaledirectory[i+2] = scaledirectory[i];
\r
118 fullscalefarcall[i+2] = fullscalefarcall[i];
\r
122 scaledirectory[0] = scaledirectory[1];
\r
123 fullscalefarcall[0] = fullscalefarcall[1];
\r
126 // check for oversize wall drawing
\r
128 for (i=maxscaleheight;i<MAXSCALEHEIGHT;i++)
\r
129 fullscalefarcall[i] = (long)BadScale;
\r
133 //===========================================================================
\r
136 ========================
\r
140 = Builds a compiled scaler object that will scale a 64 tall object to
\r
141 = the given height (centered vertically on the screen)
\r
143 = height should be even
\r
147 = DS:SI Source for scale
\r
148 = ES:DI Dest for scale
\r
150 = Calling the compiled scaler only destroys AL
\r
152 ========================
\r
155 unsigned BuildCompScale (int height, memptr *finalspot)
\r
161 unsigned src,totalscaled,totalsize;
\r
162 int startpix,endpix,toppix;
\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
226 MM_GetPtr (finalspot,totalsize);
\r
229 _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
\r
236 =======================
\r
240 = linescale should have the high word set to the segment of the scaler
\r
242 =======================
\r
245 extern int slinex,slinewidth;
\r
246 extern unsigned far *linecmds;
\r
247 extern long linescale;
\r
248 extern unsigned maskword;
\r
250 byte mask1,mask2,mask3;
\r
253 void near ScaleLine (void)
\r
255 asm mov cx,WORD PTR [linescale+2]
\r
256 asm mov es,cx // segment of scaler
\r
258 asm mov bp,WORD PTR [linecmds]
\r
259 asm mov dx,SC_INDEX+1 // to set SC_MAPMASK
\r
261 asm mov bx,[slinex]
\r
263 asm shr di,1 // X in bytes
\r
265 asm add di,[bufferofs]
\r
268 asm add bx,[slinewidth] // bx = (pixel*8+pixwidth)
\r
269 asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first
\r
270 asm mov ds,WORD PTR [linecmds+2]
\r
272 asm jz notthreebyte // scale across three bytes
\r
275 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
277 asm jnz twobyte // scale across two bytes
\r
280 // one byte scaling
\r
282 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
283 asm out dx,al // set map mask register
\r
287 asm mov bx,[ds:bp] // table location of rtl to patch
\r
289 asm jz linedone // 0 signals end of segment list
\r
291 asm mov dl,[es:bx] // save old value
\r
292 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
293 asm mov si,[ds:bp+4] // table location of entry spot
\r
295 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
296 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
297 asm add bp,6 // next segment list
\r
299 asm mov ax,SCREENSEG
\r
301 asm call ss:[linescale] // scale the segment of pixels
\r
303 asm mov es,cx // segment of scaler
\r
304 asm mov BYTE PTR es:[bx],dl // unpatch the RETF
\r
305 asm jmp scalesingle // do the next segment
\r
317 // two byte scaling
\r
320 asm mov ss:[mask2],al
\r
321 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
322 asm mov ss:[mask1],al
\r
326 asm mov bx,[ds:bp] // table location of rtl to patch
\r
328 asm jz linedone // 0 signals end of segment list
\r
330 asm mov cl,[es:bx] // save old value
\r
331 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
332 asm mov si,[ds:bp+4] // table location of entry spot
\r
334 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
335 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
336 asm add bp,6 // next segment list
\r
338 asm mov ax,SCREENSEG
\r
340 asm mov al,ss:[mask1]
\r
341 asm out dx,al // set map mask register
\r
342 asm call ss:[linescale] // scale the segment of pixels
\r
344 asm mov al,ss:[mask2]
\r
345 asm out dx,al // set map mask register
\r
346 asm call ss:[linescale] // scale the segment of pixels
\r
349 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
350 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
351 asm jmp scaledouble // do the next segment
\r
355 // three byte scaling
\r
358 asm mov ss:[mask3],al
\r
359 asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
\r
360 asm mov ss:[mask2],al
\r
361 asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
\r
362 asm mov ss:[mask1],al
\r
366 asm mov bx,[ds:bp] // table location of rtl to patch
\r
368 asm jz linedone // 0 signals end of segment list
\r
370 asm mov cl,[es:bx] // save old value
\r
371 asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in
\r
372 asm mov si,[ds:bp+4] // table location of entry spot
\r
374 asm mov WORD PTR ss:[linescale],ax // call here to start scaling
\r
375 asm mov si,[ds:bp+2] // corrected top of shape for this segment
\r
376 asm add bp,6 // next segment list
\r
378 asm mov ax,SCREENSEG
\r
380 asm mov al,ss:[mask1]
\r
381 asm out dx,al // set map mask register
\r
382 asm call ss:[linescale] // scale the segment of pixels
\r
384 asm mov al,ss:[mask2]
\r
385 asm out dx,al // set map mask register
\r
386 asm call ss:[linescale] // scale the segment of pixels
\r
388 asm mov al,ss:[mask3]
\r
389 asm out dx,al // set map mask register
\r
390 asm call ss:[linescale] // scale the segment of pixels
\r
394 asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
\r
395 asm mov BYTE PTR es:[bx],cl // unpatch the RETF
\r
396 asm jmp scaletriple // do the next segment
\r
403 =======================
\r
407 = Draws a compiled shape at [scale] pixels high
\r
409 = each vertical line of the shape has a pointer to segment data:
\r
410 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
411 = top of virtual line with segment in proper place
\r
412 = start of segment pixel*2, used to jsl into compiled scaler
\r
417 = GC_MODE read mode 1, write mode 2
\r
418 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
419 = GC_INDEX pointing at GC_BITMASK
\r
421 =======================
\r
424 static long longtemp;
\r
426 void ScaleShape (int xcenter, int shapenum, unsigned height)
\r
428 t_compshape _seg *shape;
\r
429 t_compscale _seg *comptable;
\r
430 unsigned scale,srcx,stopx,tempx;
\r
432 unsigned far *cmdptr;
\r
433 boolean leftvis,rightvis;
\r
436 shape = PM_GetSpritePage (shapenum);
\r
438 scale = height>>3; // low three bits are fractional
\r
439 if (!scale || scale>maxscale)
\r
440 return; // too close or far away
\r
441 comptable = scaledirectory[scale];
\r
443 *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call
\r
444 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
447 // scale to the left (from pixel 31 to shape->leftpix)
\r
451 stopx = shape->leftpix;
\r
452 cmdptr = &shape->dataofs[31-stopx];
\r
454 while ( --srcx >=stopx && slinex>0)
\r
456 (unsigned)linecmds = *cmdptr--;
\r
457 if ( !(slinewidth = comptable->width[srcx]) )
\r
460 if (slinewidth == 1)
\r
463 if (slinex<viewwidth)
\r
465 if (wallheight[slinex] >= height)
\r
466 continue; // obscured by closer wall
\r
473 // handle multi pixel lines
\r
475 if (slinex>viewwidth)
\r
477 slinex -= slinewidth;
\r
478 slinewidth = viewwidth-slinex;
\r
480 continue; // still off the right side
\r
484 if (slinewidth>slinex)
\r
485 slinewidth = slinex;
\r
486 slinex -= slinewidth;
\r
490 leftvis = (wallheight[slinex] < height);
\r
491 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
499 while (wallheight[slinex+slinewidth-1] >= height)
\r
507 continue; // totally obscured
\r
509 while (wallheight[slinex] >= height)
\r
515 break; // the rest of the shape is gone
\r
521 // scale to the right
\r
524 stopx = shape->rightpix;
\r
525 if (shape->leftpix<31)
\r
528 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
532 srcx = shape->leftpix-1;
\r
533 cmdptr = &shape->dataofs[0];
\r
537 while ( ++srcx <= stopx && (slinex+=slinewidth)<viewwidth)
\r
539 (unsigned)linecmds = *cmdptr++;
\r
540 if ( !(slinewidth = comptable->width[srcx]) )
\r
543 if (slinewidth == 1)
\r
545 if (slinex>=0 && wallheight[slinex] < height)
\r
553 // handle multi pixel lines
\r
557 if (slinewidth <= -slinex)
\r
558 continue; // still off the left edge
\r
560 slinewidth += slinex;
\r
565 if (slinex + slinewidth > viewwidth)
\r
566 slinewidth = viewwidth-slinex;
\r
570 leftvis = (wallheight[slinex] < height);
\r
571 rightvis = (wallheight[slinex+slinewidth-1] < height);
\r
581 while (wallheight[slinex+slinewidth-1] >= height)
\r
584 break; // the rest of the shape is gone
\r
591 while (wallheight[slinex] >= height)
\r
599 continue; // totally obscured
\r
607 =======================
\r
611 = NO CLIPPING, height in pixels
\r
613 = Draws a compiled shape at [scale] pixels high
\r
615 = each vertical line of the shape has a pointer to segment data:
\r
616 = end of segment pixel*2 (0 terminates line) used to patch rtl in scaler
\r
617 = top of virtual line with segment in proper place
\r
618 = start of segment pixel*2, used to jsl into compiled scaler
\r
623 = GC_MODE read mode 1, write mode 2
\r
624 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
625 = GC_INDEX pointing at GC_BITMASK
\r
627 =======================
\r
630 void SimpleScaleShape (int xcenter, int shapenum, unsigned height)
\r
632 t_compshape _seg *shape;
\r
633 t_compscale _seg *comptable;
\r
634 unsigned scale,srcx,stopx,tempx;
\r
636 unsigned far *cmdptr;
\r
637 boolean leftvis,rightvis;
\r
640 shape = PM_GetSpritePage (shapenum);
\r
643 comptable = scaledirectory[scale];
\r
645 *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call
\r
646 *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
\r
649 // scale to the left (from pixel 31 to shape->leftpix)
\r
653 stopx = shape->leftpix;
\r
654 cmdptr = &shape->dataofs[31-stopx];
\r
656 while ( --srcx >=stopx )
\r
658 (unsigned)linecmds = *cmdptr--;
\r
659 if ( !(slinewidth = comptable->width[srcx]) )
\r
662 slinex -= slinewidth;
\r
668 // scale to the right
\r
671 stopx = shape->rightpix;
\r
672 if (shape->leftpix<31)
\r
675 cmdptr = &shape->dataofs[32-shape->leftpix];
\r
679 srcx = shape->leftpix-1;
\r
680 cmdptr = &shape->dataofs[0];
\r
684 while ( ++srcx <= stopx )
\r
686 (unsigned)linecmds = *cmdptr++;
\r
687 if ( !(slinewidth = comptable->width[srcx]) )
\r
691 slinex+=slinewidth;
\r
699 // bit mask tables for drawing scaled strips up to eight pixels wide
\r
701 // down here so the STUPID inline assembler doesn't get confused!
\r
705 byte mapmasks1[4][8] = {
\r
706 {1 ,3 ,7 ,15,15,15,15,15},
\r
707 {2 ,6 ,14,14,14,14,14,14},
\r
708 {4 ,12,12,12,12,12,12,12},
\r
709 {8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };
\r
711 byte mapmasks2[4][8] = {
\r
712 {0 ,0 ,0 ,0 ,1 ,3 ,7 ,15},
\r
713 {0 ,0 ,0 ,1 ,3 ,7 ,15,15},
\r
714 {0 ,0 ,1 ,3 ,7 ,15,15,15},
\r
715 {0 ,1 ,3 ,7 ,15,15,15,15} };
\r
717 byte mapmasks3[4][8] = {
\r
718 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0},
\r
719 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},
\r
720 {0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},
\r
721 {0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} };
\r
724 unsigned wordmasks[8][8] = {
\r
725 {0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff},
\r
726 {0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f},
\r
727 {0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f},
\r
728 {0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f},
\r
729 {0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f},
\r
730 {0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807},
\r
731 {0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03},
\r
732 {0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} };
\r
734 int slinex,slinewidth;
\r
735 unsigned far *linecmds;
\r