]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hb/c3_scale.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / c3_scale.c
diff --git a/src/lib/hb/c3_scale.c b/src/lib/hb/c3_scale.c
new file mode 100755 (executable)
index 0000000..018083d
--- /dev/null
@@ -0,0 +1,690 @@
+/* Catacomb 3-D 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 "C3_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[MAXSCALE+1];\r
+t_compscale _seg *scaledirectory[MAXSCALE+1];\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>64 || 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
+       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
+       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>MAXSCALE)\r
+               scale = MAXSCALE;\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