// WL_SCALE.C
#include "WL_DEF.H"
#pragma hdrstop
#define OP_RETF 0xcb
/*
=========================================================================
====
GLOBALS
=========================================================================
====
*/
t_compscale _seg *scaledirectory[maxSCALEHEIGHT+1];
long fullscalefarCall[maxSCALEHEIGHT+1];
int maxscale,maxscaleshl2;
/*
=========================================================================
====
LOCALS
=========================================================================
====
*/
t_compscale _seg *work;
unsigned BuildCompScale (int height, memptr
*finalspot);
int stepbytwo;
//=======================================================================
====
/*
==============
=
= BadScale
=
==============
*/
void far BadScale (void)
{
Quit ("BadScale Called!");
}
/*
==========================
=
= SetupScaling
=
==========================
*/
void SetupScaling (int maxscaleheight)
{
int i,x,y;
byte far *dest;
maxscaleheight/=2; // one scaler every two
pixels
maxscale = maxscaleheight-1;
maxscaleshl2 = maxscale 2;
//
// free up old scalers
//
for (i=1;i maxSCALEHEIGHT;i++)
{
if (scaledirectory[i])
mm_FreePtr (&(memptr)scaledirectory[i]);
if (i>=stepbytwo)
i += 2;
}
memset (scaledirectory,0,sizeof(scaledirectory));
mm_SortMem ();
//
// build the compiled scalers
//
stepbytwo = viewheight/2; // save space by double stepping
mm_GetPtr (&(memptr)work,20000);
if (mmerror)
return;
for (i=1;i =maxscaleheight;i++)
{
BuildCompscale (i*2,&(memptr)scaledirectory[i]);
if (mmerror)
{
mm_FreePtr (&(memptr)work);
return;
}
if (i>=stepbytwo)
i+= 2;
}
mm_FreePtr (&(memptr)work);
//
// compact memory and lock down scalers
//
mm_SortMem ();
for (i=1;i =maxscaleheight;i++)
{
mm_SetLock (&(memptr)scaledirectory[i],true);
fullscalefarCall[i] = (unsigned)scaledirectory[i];
fullscalefarCall[i] =16;
fullscalefarCall[i] += scaledirectory[i]->codeofs[0];
if (i>=stepbytwo)
{
scaledirectory[i+1] = scaledirectory[i];
fullscalefarCall[i+1] = fullscalefarCall[i];
scaledirectory[i+2] = scaledirectory[i];
fullscalefarCall[i+2] = fullscalefarCall[i];
i+=2;
}
}
scaledirectory[0] = scaledirectory[1];
fullscalefarCall[0] = fullscalefarCall[1];
//
// check for oversize wall drawing
//
for (i=maxscaleheight;i maxscaleHEIGHT;i++)
fullscalefarCall[i] = (long)Badscale;
}
//=======================================================================
====
/*
========================
=
= BuildCompscale
=
= Builds a compiled scaler object that will scale a 64 tall object to
= the given height (centered vertiCally on the screen)
=
= height should be even
=
= Call with
= ---------
= DS:SI Source for scale
= ES:DI Dest for scale
=
= Calling the compiled scaler only destroys AL
=
========================
*/
unsigned BuildCompscale (int height,
memptr *finalspot)
{
byte far *code;
int i;
long fix,step;
unsigned src,totalscaled,totalsize;
int startpix,endpix,toppix;
step = ((long)height<<16) / 64;
code = &work->code[0];
toppix = (viewheight-height)/2;
fix = 0;
for (src=0;src<=64;src++)
{
startpix = fix>>16;
fix += step;
endpix = fix>>16;
if (endpix>startpix)
work->width[src] = endpix-startpix;
else
work->width[src] = 0;
//
// mark the start of the code
//
work->codeofs[src] = FP_OFF(code);
//
// compile some code if the source
pixel generates any screen pixels
//
startpix+=toppix;
endpix+=toppix;
if (startpix == endpix || endpix 0 || startpix >= viewheight || src ==
64)
continue;
//
// mov al,[si+src]
//
*code++ = 0x8a;
*code++ = 0x44;
*code++ = src;
for (;startpix endpix;startpix++)
{
if (startpix >= viewheight)
break; // off the bottom of the view
area
if (startpix 0)
continue; // not into the view area
//
// mov [es:di+heightofs],al
//
*code++ = 0x26;
*code++ = 0x88;
*code++ = 0x85;
*((unsigned far *)code)++ = startpix*SCREENBWIDE;
}
}
//
// retf
//
*code++ = 0xcb;
totalsize = FP_OFF(code);
mm_GetPtr (finalspot,totalsize);
if (mmerror)
return 0;
_fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
return totalsize;
}
/*
=======================
=
= scaleLine
=
= linescale should have the high word set to the segment of the
scaler
=
=======================
*/
extern int slinex,slinewidth;
extern unsigned far
*linecmds;
extern long linescale;
extern unsigned maskword;
byte mask1,mask2,mask3;
void near scaleLine (void)
{
asm mov cx,WORD PTR [linescale+2]
asm mov es,cx
// segment of scaler
asm mov bp,WORD PTR [linecmds]
asm mov dx,SC_INDEX+1
// to set SC_MAPMASK
asm mov bx,[slinex]
asm mov di,bx
asm shr di,2 // X in
bytes
asm add di,[bufferofs]
asm and bx,3
asm shl bx,3
asm add bx,[slinewidth] // bx =
(pixel*8+pixwidth)
asm mov al,BYTE [mapmasks3-1+bx]
// -1 because pixwidth of 1 is first
asm mov ds,WORD PTR [linecmds+2]
asm or al,al
asm jz notthreebyte // scale across three bytes
asm jmp threebyte
notthreebyte:
asm mov al,BYTE PTR
ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
asm or al,al
asm jnz twobyte // scale across two bytes
//
// one byte scaling
//
asm mov al,BYTE PTR
ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
asm out dx,al // set
map mask register
scalesingle:
asm mov bx,[ds:bp]
// table location of rtl to patch
asm or bx,bx
asm jz linedone // 0
signals end of segment list
asm mov bx,[es:bx]
asm mov dl,[es:bx]
// save old value
asm mov BYTE PTR es:[bx],OP_RETF
// patch a RETF in
asm mov si,[ds:bp+4]
// table location of entry spot
asm mov ax,[es:si]
asm mov WORD PTR ss:[linescale],ax // Call here to start scaling
asm mov si,[ds:bp+2]
// corrected top of shape for this segment
asm add bp,6 // next
segment list
asm mov ax,SCREENSEG
asm mov es,ax
asm Call ss:[linescale] // scale the segment of pixels
asm mov es,cx
// segment of scaler
asm mov BYTE PTR es:[bx],dl
// unpatch the RETF
asm jmp scalesingle // do
the next segment
//
// done
//
linedone:
asm mov ax,ss
asm mov ds,ax
return;
//
// two byte scaling
//
twobyte:
asm mov ss:[mask2],al
asm mov al,BYTE PTR
ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
asm mov ss:[mask1],al
scaledouble:
asm mov bx,[ds:bp]
// table location of rtl to patch
asm or bx,bx
asm jz linedone // 0
signals end of segment list
asm mov bx,[es:bx]
asm mov cl,[es:bx]
// save old value
asm mov BYTE PTR es:[bx],OP_RETF
// patch a RETF in
asm mov si,[ds:bp+4]
// table location of entry spot
asm mov ax,[es:si]
asm mov WORD PTR ss:[linescale],ax // Call here to start scaling
asm mov si,[ds:bp+2]
// corrected top of shape for this segment
asm add bp,6 // next
segment list
asm mov ax,SCREENSEG
asm mov es,ax
asm mov al,ss:[mask1]
asm out dx,al // set
map mask register
asm Call ss:[linescale] // scale the segment of pixels
asm inc di
asm mov al,ss:[mask2]
asm out dx,al // set
map mask register
asm Call ss:[linescale] // scale the segment of pixels
asm dec di
asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
asm mov BYTE PTR es:[bx],cl
// unpatch the RETF
asm jmp scaledouble // do
the next segment
//
// three byte scaling
//
threebyte:
asm mov ss:[mask3],al
asm mov al,BYTE PTR
ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first
asm mov ss:[mask2],al
asm mov al,BYTE PTR
ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first
asm mov ss:[mask1],al
scaletriple:
asm mov bx,[ds:bp]
// table location of rtl to patch
asm or bx,bx
asm jz linedone // 0
signals end of segment list
asm mov bx,[es:bx]
asm mov cl,[es:bx]
// save old value
asm mov BYTE PTR es:[bx],OP_RETF
// patch a RETF in
asm mov si,[ds:bp+4]
// table location of entry spot
asm mov ax,[es:si]
asm mov WORD PTR ss:[linescale],ax // Call here to start scaling
asm mov si,[ds:bp+2]
// corrected top of shape for this segment
asm add bp,6 // next
segment list
asm mov ax,SCREENSEG
asm mov es,ax
asm mov al,ss:[mask1]
asm out dx,al // set
map mask register
asm Call ss:[linescale] // scale the segment of pixels
asm inc di
asm mov al,ss:[mask2]
asm out dx,al // set
map mask register
asm Call ss:[linescale] // scale the segment of pixels
asm inc di
asm mov al,ss:[mask3]
asm out dx,al // set
map mask register
asm Call ss:[linescale] // scale the segment of pixels
asm dec di
asm dec di
asm mov es,WORD PTR ss:[linescale+2] // segment of scaler
asm mov BYTE PTR es:[bx],cl
// unpatch the RETF
asm jmp scaletriple // do
the next segment
}
/*
=======================
=
= scaleShape
=
= Draws a compiled shape at [scale] pixels high
=
= each vertical line of the shape has a pointer to segment data:
= end of segment pixel*2 (0 terminates line) used to patch
rtl in scaler
= top of virtual line with segment in proper place
= start of segment pixel*2, used to jsl into compiled scaler
= repeat
=
= Setup for Call
= --------------
= GC_MODE read mode 1, write mode 2
= GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
= GC_INDEX pointing at GC_BITMASK
=
=======================
*/
static long longtemp;
void scaleShape (int xcenter, int
shapenum, unsigned height)
{
t_compshape _seg *shape;
t_compscale _seg *comptable;
unsigned scale,srcx,stopx,tempx;
int t;
unsigned far *cmdptr;
boolean leftvis,rightvis;
shape = PM_GetSpritePage (shapenum);
scale = height>>3; // low three bits
are fractional
if (!scale || scale>maxscale)
return; // too close or far away
comptable = scaledirectory[scale];
*(((unsigned *)&linescale)+1)=(unsigned)comptable;
// seg of far Call
*(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
//
// scale to the left (from pixel 31 to shape->leftpix)
//
srcx = 32;
slinex = xcenter;
stopx = shape->leftpix;
cmdptr = &shape->dataofs[31-stopx];
while ( --srcx >=stopx && slinex>0)
{
(unsigned)linecmds = *cmdptr--;
if ( !(slinewidth =
comptable->width[srcx]) )
continue;
if (slinewidth == 1)
{
slinex--;
if (slinex viewwidth)
{
if (wallheight[slinex] >=
height)
continue; // obscured by closer wall
scaleLine ();
}
continue;
}
//
// handle multi pixel lines
//
if (slinex>viewwidth)
{
slinex -= slinewidth;
slinewidth = viewwidth-slinex;
if (slinewidth 1)
continue; // still off the right side
}
else
{
if (slinewidth>slinex)
slinewidth = slinex;
slinex -= slinewidth;
}
leftvis = (wallheight[slinex] height);
rightvis = (wallheight[slinex+slinewidth-1] height);
if (leftvis)
{
if (rightvis)
scaleLine ();
else
{
while (wallheight[slinex+slinewidth-1] >= height)
slinewidth--;
scaleLine ();
}
}
else
{
if (!rightvis)
continue; // totally obscured
while (wallheight[slinex] >= height)
{
slinex++;
slinewidth--;
}
scaleLine ();
break; // the rest of the shape is gone
}
}
//
// scale to the right
//
slinex = xcenter;
stopx = shape->rightpix;
if (shape->leftpix 31)
{
srcx = 31;
cmdptr = &shape->dataofs[32-shape->leftpix];
}
else
{
srcx = shape->leftpix-1;
cmdptr = &shape->dataofs[0];
}
slinewidth = 0;
while ( ++srcx = stopx && (slinex+=slinewidth) viewwidth)
{
(unsigned)linecmds = *cmdptr++;
if ( !(slinewidth =
comptable->width[srcx]) )
continue;
if (slinewidth == 1)
{
if (slinex>=0 && wallheight[slinex]
height)
{
scaleLine ();
}
continue;
}
//
// handle multi pixel lines
//
if (slinex 0)
{
if (slinewidth = -slinex)
continue; // still off the left edge
slinewidth += slinex;
slinex = 0;
}
else
{
if (slinex + slinewidth >
viewwidth)
slinewidth = viewwidth-slinex;
}
leftvis = (wallheight[slinex] height);
rightvis = (wallheight[slinex+slinewidth-1] height);
if (leftvis)
{
if (rightvis)
{
scaleLine ();
}
else
{
while (wallheight[slinex+slinewidth-1] >= height)
slinewidth--;
scaleLine ();
break; // the rest of the shape is gone
}
}
else
{
if (rightvis)
{
while (wallheight[slinex] >= height)
{
slinex++;
slinewidth--;
}
scaleLine ();
}
else
continue; // totally obscured
}
}
}
/*
=======================
=
= SimplescaleShape
=
= NO CLIPPING, height in pixels
=
= Draws a compiled shape at [scale] pixels high
=
= each vertical line of the shape has a pointer to segment data:
= end of segment pixel*2 (0 terminates line) used to patch
rtl in scaler
= top of virtual line with segment in proper place
= start of segment pixel*2, used to jsl into compiled scaler
= repeat
=
= Setup for Call
= --------------
= GC_MODE read mode 1, write mode 2
= GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
= GC_INDEX pointing at GC_BITMASK
=
=======================
*/
void SimplescaleShape (int xcenter, int
shapenum, unsigned height)
{
t_compshape _seg *shape;
t_compscale _seg *comptable;
unsigned scale,srcx,stopx,tempx;
int t;
unsigned far *cmdptr;
boolean leftvis,rightvis;
shape = PM_GetSpritePage (shapenum);
scale = height>>1;
comptable = scaledirectory[scale];
*(((unsigned *)&linescale)+1)=(unsigned)comptable;
// seg of far Call
*(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape
//
// scale to the left (from pixel 31 to shape->leftpix)
//
srcx = 32;
slinex = xcenter;
stopx = shape->leftpix;
cmdptr = &shape->dataofs[31-stopx];
while ( --srcx >=stopx )
{
(unsigned)linecmds = *cmdptr--;
if ( !(slinewidth =
comptable->width[srcx]) )
continue;
slinex -= slinewidth;
scaleLine ();
}
//
// scale to the right
//
slinex = xcenter;
stopx = shape->rightpix;
if (shape->leftpix 31)
{
srcx = 31;
cmdptr = &shape->dataofs[32-shape->leftpix];
}
else
{
srcx = shape->leftpix-1;
cmdptr = &shape->dataofs[0];
}
slinewidth = 0;
while ( ++srcx = stopx )
{
(unsigned)linecmds = *cmdptr++;
if ( !(slinewidth =
comptable->width[srcx]) )
continue;
scaleLine ();
slinex+=slinewidth;
}
}
//
// bit mask tables for drawing scaled strips up to eight pixels
wide
//
// down here so the STUPID inline assembler doesn't get confused!
//
byte mapmasks1[4][8] = {
{1 ,3 ,7 ,15,15,15,15,15},
{2 ,6 ,14,14,14,14,14,14},
{4 ,12,12,12,12,12,12,12},
{8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };
byte mapmasks2[4][8] = {
{0 ,0 ,0 ,0 ,1 ,3 ,7 ,15},
{0 ,0 ,0 ,1 ,3 ,7 ,15,15},
{0 ,0 ,1 ,3 ,7 ,15,15,15},
{0 ,1 ,3 ,7 ,15,15,15,15} };
byte mapmasks3[4][8] = {
{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0},
{0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},
{0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},
{0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} };
unsigned wordmasks[8][8] = {
{0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,
0x00ff},
{0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,
0x807f},
{0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,
0xc03f},
{0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,
0xe01f},
{0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,
0xf00f},
{0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,
0xf807},
{0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,
0xfc03},
{0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,
0xfe01} };
int slinex,slinewidth;
unsigned far *linecmds;
long linescale;
unsigned maskword;