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