--- /dev/null
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_SCALE.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+//const unsigned viewheight = 144;\r
+const unsigned screenbwide = 40;\r
+const byte BACKGROUNDPIX = 5;\r
+\r
+unsigned shapesize[NUMSCALEPICS];\r
+t_compscale _seg *scaledirectory[NUMSCALEPICS];\r
+t_compshape _seg *shapedirectory[NUMSCALEPICS];\r
+memptr walldirectory[NUMSCALEWALLS];\r
+\r
+/*\r
+===========================\r
+=\r
+= DeplanePic\r
+=\r
+= Takes a raw bit map of width bytes by height and creates a scaleable shape\r
+=\r
+= Returns the length of the shape in bytes\r
+=\r
+= Fills in spotvis (a convenient 64*64 array) with the color values\r
+=\r
+===========================\r
+*/\r
+\r
+void DeplanePic (int picnum)\r
+{\r
+ byte far *plane0,far *plane1,far *plane2,far *plane3;\r
+ byte by0,by1,by2,by3;\r
+ unsigned x,y,b,color,shift,width,height;\r
+ byte *dest;\r
+\r
+//\r
+// convert ega pixels to byte color values in a temp buffer\r
+//\r
+ width = pictable[picnum-STARTPICS].width;\r
+ height = pictable[picnum-STARTPICS].height;\r
+\r
+ if (width>8 || height!=64)\r
+ Quit ("DePlanePic: Bad size shape");\r
+\r
+ memset (spotvis,BACKGROUNDPIX,sizeof(spotvis));\r
+\r
+ plane0 = (byte _seg *)grsegs[picnum];\r
+ plane1 = plane0 + width*height;\r
+ plane2 = plane1 + width*height;\r
+ plane3 = plane2 + width*height;\r
+\r
+ for (y=0;y<height;y++)\r
+ {\r
+ dest = &spotvis[y][0];\r
+ for (x=0;x<width;x++)\r
+ {\r
+ by0 = *plane0++;\r
+ by1 = *plane1++;\r
+ by2 = *plane2++;\r
+ by3 = *plane3++;\r
+\r
+ for (b=0;b<8;b++)\r
+ {\r
+ shift=8-b;\r
+\r
+ color = 0;\r
+ asm mov cl,[BYTE PTR shift]\r
+ asm mov al,[BYTE PTR by3]\r
+ asm rcr al,cl;\r
+ asm rcl [BYTE PTR color],1;\r
+\r
+ asm mov cl,[BYTE PTR shift]\r
+ asm mov al,[BYTE PTR by2]\r
+ asm rcr al,cl;\r
+ asm rcl [BYTE PTR color],1;\r
+\r
+ asm mov cl,[BYTE PTR shift]\r
+ asm mov al,[BYTE PTR by1]\r
+ asm rcr al,cl;\r
+ asm rcl [BYTE PTR color],1;\r
+\r
+ asm mov cl,[BYTE PTR shift]\r
+ asm mov al,[BYTE PTR by0]\r
+ asm rcr al,cl;\r
+ asm rcl [BYTE PTR color],1;\r
+\r
+ *dest++ = color;\r
+ } // B\r
+ } // X\r
+ } // Y\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
+ t_compscale _seg *work;\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
+ MM_GetPtr (&(memptr)work,20000);\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
+ work->start[src] = startpix;\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
+ // and [es:di+heightofs],al\r
+ //\r
+ *code++ = 0x26;\r
+ *code++ = 0x20;\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
+ _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);\r
+ MM_FreePtr (&(memptr)work);\r
+\r
+ return totalsize;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= BuildCompShape\r
+=\r
+= typedef struct\r
+= {\r
+= unsigned width;\r
+= unsigned codeofs[64];\r
+= } t_compshape;\r
+=\r
+= Width is the number of compiled line draws in the shape. The shape\r
+= drawing code will assume that the midpoint of the shape is in the\r
+= middle of the width.\r
+=\r
+= The non background pixel data will start at codeofs[width], so codeofs\r
+= greater than width will be invalid.\r
+=\r
+= Each code offset will draw one vertical line of the shape, consisting\r
+= of 0 or more segments of scaled pixels.\r
+=\r
+= The scaled shapes use ss:0-4 as a scratch variable for the far call to\r
+= the compiled scaler, so zero it back out after the shape is scaled, or\r
+= a "null pointer assignment" will result upon termination.\r
+=\r
+= Setup for a call to a compiled shape\r
+= -----------------------------------\r
+= ax toast\r
+= bx toast\r
+= cx toast\r
+= dx segment of compiled shape\r
+= si toast\r
+= di byte at top of view area to draw the line in\r
+= bp 0\r
+= ss:2 and ds the segment of the compiled scaler to use\r
+= es screenseg\r
+=\r
+= Upon return, ds IS NOT SET to the data segment. Do:\r
+= mov ax,ss\r
+= mov ds,ax\r
+=\r
+=\r
+= GC_BITMASK set to the pixels to be drawn in the row of bytes under DI\r
+= GC_MODE read mode 1, write mode 2\r
+= GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff\r
+=\r
+=\r
+= Code generated for each segment\r
+= -------------------------------\r
+= mov bx,[(segend+1)*2]\r
+= mov cx,[bx]\r
+= mov [BYTE PTR bx],0xc8 // far return\r
+= mov ax,[segstart*2]\r
+= mov [ss:0],ax // entry point into the compiled scaler\r
+= mov ds,dx // (mov ds,cs) the data is after the compiled code\r
+= mov si,ofs data\r
+= call [bp] // scale some pixels\r
+= mov ds,[bp+2]\r
+= mov [bx],cx // un patch return\r
+=\r
+= Code generated after all segments on a line\r
+= -------------------------------------------\r
+= retf\r
+=\r
+========================\r
+*/\r
+\r
+unsigned BuildCompShape (t_compshape _seg **finalspot)\r
+{\r
+ t_compshape _seg *work;\r
+ byte far *code;\r
+ int firstline,lastline,x,y;\r
+ unsigned firstpix,lastpix,width;\r
+ unsigned totalsize,pixelofs;\r
+ unsigned buff;\r
+\r
+\r
+// MM_GetPtr (&(memptr)work,20000);\r
+ EGAWRITEMODE(0);\r
+ EGAREADMAP(0); // use ega screen memory for temp buffer\r
+ EGAMAPMASK(1);\r
+ buff = screenloc[1];\r
+ work = (t_compshape _seg *)(0xa000+(buff+15)/16);\r
+\r
+//\r
+// find the width of the shape\r
+//\r
+ firstline = -1;\r
+ x=0;\r
+ do\r
+ {\r
+ for (y=0;y<64;y++)\r
+ if (spotvis[y][x] != BACKGROUNDPIX)\r
+ {\r
+ firstline = x;\r
+ break;\r
+ }\r
+ if (++x == 64)\r
+ Quit ("BuildCompShape: No shape data!");\r
+ } while (firstline == -1);\r
+\r
+ lastline = -1;\r
+ x=63;\r
+ do\r
+ {\r
+ for (y=0;y<64;y++)\r
+ if (spotvis[y][x] != BACKGROUNDPIX)\r
+ {\r
+ lastline = x;\r
+ break;\r
+ }\r
+ x--;\r
+ } while (lastline == -1);\r
+\r
+ width = lastline-firstline+1;\r
+\r
+ work->width = width;\r
+ code = (byte far *)&work->codeofs[width];\r
+\r
+//\r
+// copy all non background pixels to the work space\r
+//\r
+ pixelofs = FP_OFF(code);\r
+\r
+ for (x=firstline;x<=lastline;x++)\r
+ for (y=0;y<64;y++)\r
+ if (spotvis[y][x] != BACKGROUNDPIX)\r
+ *code++ = spotvis[y][x];\r
+\r
+//\r
+// start compiling the vertical lines\r
+//\r
+ for (x=firstline;x<=lastline;x++)\r
+ {\r
+ work->codeofs[x-firstline] = FP_OFF(code);\r
+\r
+ y=0;\r
+ do\r
+ {\r
+ //\r
+ // scan past black background pixels\r
+ //\r
+ while (spotvis[y][x] == BACKGROUNDPIX && y<64)\r
+ y++;\r
+\r
+ if (y>63) // no more segments\r
+ break;\r
+\r
+ firstpix = y+1; // +1 because width is before codeofs\r
+\r
+ //\r
+ // scan past scalable pixels\r
+ //\r
+ while (spotvis[y][x] != BACKGROUNDPIX && y<64)\r
+ y++;\r
+\r
+ if (y>63)\r
+ lastpix = 65;\r
+ else\r
+ lastpix = y+1; // actually one pixel past the last displayed\r
+\r
+ //\r
+ // compile the scale call\r
+ //\r
+ *code++ = 0x8b; // mov bx,[lastpix*2]\r
+ *code++ = 0x1e;\r
+ *((unsigned far *)code)++ = lastpix*2;\r
+\r
+ *code++ = 0x8b; // mov cx,[bx]\r
+ *code++ = 0x0f;\r
+\r
+ *code++ = 0xc6; // move [BYTE bx],0xcb\r
+ *code++ = 0x07;\r
+ *code++ = 0xcb;\r
+\r
+ *code++ = 0xa1; // mov ax,[firstpix*2] /*************\r
+ *((unsigned far *)code)++ = firstpix*2;\r
+\r
+ *code++ = 0x36; // mov [ss:0],ax\r
+ *code++ = 0xa3;\r
+ *code++ = 0x00;\r
+ *code++ = 0x00;\r
+\r
+ *code++ = 0x8e; // mov ds,dx (mov ds,cs)\r
+ *code++ = 0xda;\r
+\r
+ *code++ = 0xbe; // mov si,OFFSET pixelofs-firstpixel\r
+ *((unsigned far *)code)++ = pixelofs-firstpix;\r
+\r
+ *code++ = 0xff; // call [DWORD bp]\r
+ *code++ = 0x5e;\r
+ *code++ = 0x00;\r
+\r
+ *code++ = 0x8e; // mov ds,[bp+2]\r
+ *code++ = 0x5e;\r
+ *code++ = 0x02;\r
+\r
+ *code++ = 0x89; // mov [bx],cx\r
+ *code++ = 0x0f;\r
+\r
+ pixelofs += (lastpix-firstpix);\r
+ } while (y<63);\r
+\r
+ //\r
+ // retf\r
+ //\r
+ *code++ = 0xcb;\r
+ }\r
+\r
+\r
+//\r
+// copy the final shape to a properly sized buffer\r
+//\r
+ totalsize = FP_OFF(code);\r
+\r
+ if (totalsize >= (PAGELEN*2))\r
+ Quit("BuildCompShape(): Shape is too complex!");\r
+\r
+ MM_GetPtr ((memptr *)finalspot,totalsize);\r
+ _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);\r
+// MM_FreePtr (&(memptr)work);\r
+\r
+ return totalsize;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ScaleShape\r
+=\r
+= Draws a compiled shape at [scale] pixels high\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, t_compshape _seg *compshape, unsigned scale)\r
+{\r
+ #define MAX_OBJ_SCALE (MAXSCALE)\r
+\r
+\r
+ t_compscale _seg *comptable;\r
+ unsigned width,scalewidth;\r
+ int x,pixel,lastpixel,pixwidth,min;\r
+ unsigned far *codehandle, far *widthptr;\r
+ unsigned badcodeptr;\r
+ int rightclip;\r
+\r
+ if (!compshape)\r
+ Quit ("ScaleShape: NULL compshape ptr!");\r
+\r
+ scale = (scale+1)/2;\r
+ if (!scale)\r
+ return; // too far away\r
+ if (scale>MAX_OBJ_SCALE)\r
+ scale = MAX_OBJ_SCALE;\r
+ comptable = scaledirectory[scale];\r
+\r
+ width = compshape->width;\r
+ scalewidth = comptable->start[width];\r
+\r
+ pixel = xcenter - scalewidth/2;\r
+ lastpixel = pixel+scalewidth-1;\r
+ if (pixel >= VIEWWIDTH || lastpixel < 0)\r
+ return; // totally off screen\r
+\r
+//\r
+// scan backwards from the right edge until pixels are visable\r
+// rightclip is the first NON VISABLE pixel\r
+//\r
+ if (lastpixel>=VIEWWIDTH-1)\r
+ rightclip = VIEWWIDTH-1;\r
+ else\r
+ rightclip = lastpixel;\r
+\r
+ if (zbuffer[rightclip]>scale)\r
+ {\r
+ if (pixel>0)\r
+ min = pixel;\r
+ else\r
+ min = 0;\r
+ do\r
+ {\r
+ if (--rightclip < min)\r
+ return; // totally covered or before 0\r
+ if (zbuffer[rightclip]<=scale)\r
+ break;\r
+ } while (1);\r
+ }\r
+ rightclip++;\r
+\r
+//\r
+// scan from the left until it is on screen, leaving\r
+// [pixel],[pixwidth],[codehandle],and [widthptr] set correctly\r
+//\r
+ *(((unsigned *)&longtemp)+1) = (unsigned)compshape; // seg of shape\r
+ codehandle = &compshape->codeofs[0];\r
+ badcodeptr = compshape->codeofs[width];\r
+ widthptr = &comptable->width[0];\r
+ asm mov ax,[comptable]\r
+ asm mov WORD PTR [2],ax // ds:0-4 is used as a far call pointer\r
+ // by the compiled shapes\r
+ pixwidth = *widthptr; // scaled width of this pixel\r
+ while (!pixwidth)\r
+ {\r
+ pixwidth = *++widthptr; // find the first visable pixel\r
+ codehandle++;\r
+ }\r
+\r
+ if (pixel<0)\r
+ {\r
+ do\r
+ {\r
+ if (pixel+pixwidth>0)\r
+ {\r
+ pixwidth += pixel;\r
+ pixel = 0;\r
+ break;\r
+ }\r
+ do\r
+ {\r
+ pixwidth = *++widthptr;\r
+ codehandle++;\r
+ } while (!pixwidth);\r
+ pixel+=pixwidth;\r
+ } while (1);\r
+ }\r
+\r
+//\r
+// scan until it is visable, leaving\r
+// [pixel],[pixwidth],[codehandle],and [widthptr] set correctly\r
+//\r
+ do\r
+ {\r
+ if (zbuffer[pixel] <= scale)\r
+ break; // start drawing here\r
+ pixel++;\r
+ if (!--pixwidth)\r
+ {\r
+ do\r
+ {\r
+ pixwidth = *++widthptr;\r
+ codehandle++;\r
+ } while (!pixwidth);\r
+ }\r
+ } while (1);\r
+\r
+ if (pixel+pixwidth>rightclip)\r
+ pixwidth = rightclip-pixel;\r
+//\r
+// draw lines\r
+//\r
+ do // while (1)\r
+ {\r
+ //\r
+ // scale a vertical segment [pixwidth] pixels wide at [pixel]\r
+ //\r
+ (unsigned)longtemp = *codehandle; // offset of compiled code\r
+ if ((unsigned)longtemp == badcodeptr)\r
+ Quit ("ScaleShape: codehandle past end!");\r
+\r
+ asm mov bx,[pixel]\r
+ asm mov di,bx\r
+ asm shr di,1\r
+ asm shr di,1\r
+ asm shr di,1 // X in bytes\r
+ asm add di,[bufferofs]\r
+ asm and bx,7\r
+ asm shl bx,1\r
+ asm shl bx,1\r
+ asm shl bx,1\r
+ asm add bx,[pixwidth] // bx = pixel*8+pixwidth-1\r
+ asm dec bx\r
+ asm push bx\r
+ asm mov al,BYTE PTR [bitmasks1+bx]\r
+ asm mov dx,GC_INDEX+1\r
+ asm out dx,al // set bit mask register\r
+\r
+ asm mov es,[screenseg]\r
+ asm push si\r
+ asm push di\r
+ asm push bp\r
+ asm xor bp,bp\r
+ asm mov dx,[WORD PTR longtemp+2]\r
+ asm mov ds,[2]\r
+ asm call ss:[DWORD PTR longtemp] // scale the line of pixels\r
+ asm mov ax,ss\r
+ asm mov ds,ax\r
+ asm pop bp\r
+ asm pop di\r
+ asm pop si\r
+\r
+ asm pop bx\r
+ asm mov al,BYTE PTR [bitmasks2+bx]\r
+ asm or al,al\r
+ asm jz nosecond\r
+\r
+ //\r
+ // draw a second byte for vertical strips that cross two bytes\r
+ //\r
+ asm inc di\r
+ asm mov dx,GC_INDEX+1\r
+ asm out dx,al // set bit mask register\r
+ asm push si\r
+ asm push di\r
+ asm push bp\r
+ asm xor bp,bp\r
+ asm mov dx,[WORD PTR longtemp+2]\r
+ asm mov ds,[2]\r
+ asm call ss:[DWORD PTR longtemp] // scale the line of pixels\r
+ asm mov ax,ss\r
+ asm mov ds,ax\r
+ asm pop bp\r
+ asm pop di\r
+ asm pop si\r
+\r
+\r
+ //\r
+ // advance to the next drawn line\r
+ //\r
+nosecond:;\r
+ if ( (pixel+=pixwidth) == rightclip )\r
+ {\r
+ asm mov WORD PTR [0],0\r
+ asm mov WORD PTR [2],0\r
+ return; // all done!\r
+ }\r
+\r
+ do\r
+ {\r
+ pixwidth = *++widthptr;\r
+ codehandle++;\r
+ } while (!pixwidth);\r
+\r
+ if (pixel+pixwidth > rightclip)\r
+ pixwidth = rightclip-pixel;\r
+\r
+ } while (1);\r
+\r
+}\r
+\r
+//\r
+// bit mask tables for drawing scaled strips up to eight pixels wide\r
+//\r
+\r
+byte bitmasks1[8][8] = {\r
+{0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff},\r
+{0x40,0x60,0x70,0x78,0x7c,0x7e,0x7f,0x7f},\r
+{0x20,0x30,0x38,0x3c,0x3e,0x3f,0x3f,0x3f},\r
+{0x10,0x18,0x1c,0x1e,0x1f,0x1f,0x1f,0x1f},\r
+{0x8,0xc,0xe,0xf,0xf,0xf,0xf,0xf},\r
+{0x4,0x6,0x7,0x7,0x7,0x7,0x7,0x7},\r
+{0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3},\r
+{0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1} };\r
+\r
+byte bitmasks2[8][8] = {\r
+{0,0,0,0,0,0,0,0},\r
+{0,0,0,0,0,0,0,0x80},\r
+{0,0,0,0,0,0,0x80,0xc0},\r
+{0,0,0,0,0,0x80,0xc0,0xe0},\r
+{0,0,0,0,0x80,0xc0,0xe0,0xf0},\r
+{0,0,0,0x80,0xc0,0xe0,0xf0,0xf8},\r
+{0,0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc},\r
+{0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe} };\r
+\r
+\r
+\r
+\r
+\r
+\r