]> 4ch.mooo.com Git - 16.git/blobdiff - 16/keen456/KEEN4-6/ID_VW.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / ID_VW.C
diff --git a/16/keen456/KEEN4-6/ID_VW.C b/16/keen456/KEEN4-6/ID_VW.C
new file mode 100755 (executable)
index 0000000..69b54c5
--- /dev/null
@@ -0,0 +1,1548 @@
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is primarily based on:\r
+ * 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
+// ID_VW.C\r
+\r
+#include "ID_HEADS.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define VIEWWIDTH              40\r
+\r
+#define PIXTOBLOCK             4               // 16 pixels to an update block\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+cardtype       videocard;              // set by VW_Startup\r
+grtype         grmode;                 // CGAgr, EGAgr, VGAgr\r
+\r
+unsigned       bufferofs;              // hidden area to draw to before displaying\r
+unsigned       displayofs;             // origin of the visable screen\r
+unsigned       panx,pany;              // panning adjustments inside port in pixels\r
+unsigned       pansx,pansy;    // panning adjustments inside port in screen\r
+                                                       // block limited pixel values (ie 0/8 for ega x)\r
+unsigned       panadjust;              // panx/pany adjusted by screen resolution\r
+\r
+unsigned       screenseg;              // normally 0xa000 / 0xb800\r
+unsigned       linewidth;\r
+unsigned       ylookup[VIRTUALHEIGHT];\r
+\r
+unsigned       fontnumber;             // 0 based font number for drawing\r
+\r
+boolean                screenfaded;\r
+\r
+pictabletype   _seg *pictable;\r
+pictabletype   _seg *picmtable;\r
+spritetabletype _seg *spritetable;\r
+\r
+int                    bordercolor;\r
+boolean                        nopan;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+void   VWL_MeasureString (char far *string, word *width, word *height,\r
+               fontstruct _seg *font);\r
+void   VWL_DrawCursor (void);\r
+void   VWL_EraseCursor (void);\r
+void   VWL_DBSetup (void);\r
+void   VWL_UpdateScreenBlocks (void);\r
+\r
+\r
+int                    bordercolor;\r
+int                    cursorvisible;\r
+int                    cursornumber,cursorwidth,cursorheight,cursorx,cursory;\r
+memptr         cursorsave;\r
+unsigned       cursorspot;\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= VW_Startup\r
+=\r
+=======================\r
+*/\r
+\r
+static char *ParmStrings[] = {"HIDDENCARD","NOPAN",""};\r
+\r
+void   VW_Startup (void)\r
+{\r
+       int i,n;\r
+\r
+       asm     cld;\r
+\r
+       videocard = 0;\r
+\r
+       for (i = 1;i < _argc;i++)\r
+       {\r
+               n = US_CheckParm(_argv[i],ParmStrings);\r
+               if (n == 0)\r
+               {\r
+                       videocard = EGAcard;\r
+               }\r
+               else if (n == 1)\r
+               {\r
+                       nopan = true;\r
+               }\r
+       }\r
+\r
+       if (!videocard)\r
+               videocard = VW_VideoID ();\r
+\r
+#if GRMODE == EGAGR\r
+       grmode = EGAGR;\r
+       if (videocard != EGAcard && videocard != VGAcard)\r
+#ifdef KEEN\r
+Quit ("Improper video card!  If you really have an EGA/VGA card that I am not\n"\r
+         "detecting, use the -HIDDENCARD command line parameter!");\r
+#else\r
+Quit ("Improper video card!  If you really have an EGA/VGA card that I am not \n"\r
+         "detecting, use the -HIDDENCARD command line parameter!");\r
+#endif\r
+       EGAWRITEMODE(0);\r
+#endif\r
+\r
+#if GRMODE == CGAGR\r
+       grmode = CGAGR;\r
+       if (videocard < CGAcard || videocard > VGAcard)\r
+#ifdef KEEN\r
+Quit ("Improper video card!  If you really have a CGA card that I am not\n"\r
+         "detecting, use the -HIDDENCARD command line parameter!");\r
+#else\r
+Quit ("Improper video card!  If you really have a CGA card that I am not \n"\r
+         "detecting, use the -HIDDENCARD command line parameter!");\r
+#endif\r
+       MM_GetPtr (&(memptr)screenseg,0x10000l);        // grab 64k for floating screen\r
+#endif\r
+\r
+       cursorvisible = 0;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+=======================\r
+=\r
+= VW_Shutdown\r
+=\r
+=======================\r
+*/\r
+\r
+void   VW_Shutdown (void)\r
+{\r
+       VW_SetScreenMode (TEXTGR);\r
+#if GRMODE == EGAGR\r
+       VW_SetLineWidth (80);\r
+#endif\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= VW_SetScreenMode\r
+= Call BIOS to set TEXT / CGAgr / EGAgr / VGAgr\r
+=\r
+========================\r
+*/\r
+\r
+void VW_SetScreenMode (int grmode)\r
+{\r
+       switch (grmode)\r
+       {\r
+         case TEXTGR:  _AX = 3;\r
+                 geninterrupt (0x10);\r
+#ifdef CAT3D\r
+                 screenseg=0xb000;\r
+#endif\r
+                 break;\r
+         case CGAGR: _AX = 4;\r
+                 geninterrupt (0x10);          // screenseg is actually a main mem buffer\r
+                 break;\r
+         case EGAGR: _AX = 0xd;\r
+                 geninterrupt (0x10);\r
+                 screenseg=0xa000;\r
+                 break;\r
+#ifdef VGAGAME\r
+         case VGAGR:{\r
+                 char extern VGAPAL;   // deluxepaint vga pallet .OBJ file\r
+                 void far *vgapal = &VGAPAL;\r
+                 SetCool256 ();                // custom 256 color mode\r
+                 screenseg=0xa000;\r
+                 _ES = FP_SEG(vgapal);\r
+                 _DX = FP_OFF(vgapal);\r
+                 _BX = 0;\r
+                 _CX = 0x100;\r
+                 _AX = 0x1012;\r
+                 geninterrupt(0x10);                   // set the deluxepaint pallet\r
+\r
+                 break;\r
+#endif\r
+       }\r
+       VW_SetLineWidth(SCREENWIDTH);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       SCREEN FADES\r
+\r
+=============================================================================\r
+*/\r
+\r
+char colors[7][17]=\r
+{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\r
+ {0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,0},\r
+ {0,0,0,0,0,0,0,0,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},\r
+ {0,1,2,3,4,5,6,7,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},\r
+ {0,1,2,3,4,5,6,7,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0},\r
+ {0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f}};\r
+\r
+\r
+void VW_ColorBorder (int color)\r
+{\r
+       _AH=0x10;\r
+       _AL=1;\r
+       _BH=color;\r
+       geninterrupt (0x10);\r
+       bordercolor = color;\r
+}\r
+\r
+void VW_SetPalette(byte *palette)\r
+{\r
+       byte    p;\r
+       word    i;\r
+\r
+       for (i = 0;i < 15;i++)\r
+       {\r
+               p = palette[i];\r
+               colors[0][i] = 0;\r
+               colors[1][i] = (p > 0x10)? (p & 0x0f) : 0;\r
+               colors[2][i] = (p > 0x10)? p : 0;\r
+               colors[3][i] = p;\r
+               colors[4][i] = (p > 0x10)? 0x1f : p;\r
+               colors[5][i] = 0x1f;\r
+       }\r
+}\r
+\r
+void VW_SetDefaultColors(void)\r
+{\r
+#if GRMODE == EGAGR\r
+       colors[3][16] = bordercolor;\r
+       _ES=FP_SEG(&colors[3]);\r
+       _DX=FP_OFF(&colors[3]);\r
+       _AX=0x1002;\r
+       geninterrupt(0x10);\r
+       screenfaded = false;\r
+#endif\r
+}\r
+\r
+\r
+void VW_FadeOut(void)\r
+{\r
+#if GRMODE == EGAGR\r
+       int i;\r
+\r
+       for (i=3;i>=0;i--)\r
+       {\r
+         colors[i][16] = bordercolor;\r
+         _ES=FP_SEG(&colors[i]);\r
+         _DX=FP_OFF(&colors[i]);\r
+         _AX=0x1002;\r
+         geninterrupt(0x10);\r
+         VW_WaitVBL(6);\r
+       }\r
+       screenfaded = true;\r
+#endif\r
+}\r
+\r
+\r
+void VW_FadeIn(void)\r
+{\r
+#if GRMODE == EGAGR\r
+       int i;\r
+\r
+       for (i=0;i<4;i++)\r
+       {\r
+         colors[i][16] = bordercolor;\r
+         _ES=FP_SEG(&colors[i]);\r
+         _DX=FP_OFF(&colors[i]);\r
+         _AX=0x1002;\r
+         geninterrupt(0x10);\r
+         VW_WaitVBL(6);\r
+       }\r
+       screenfaded = false;\r
+#endif\r
+}\r
+\r
+void VW_FadeUp(void)\r
+{\r
+#if GRMODE == EGAGR\r
+       int i;\r
+\r
+       for (i=3;i<6;i++)\r
+       {\r
+         colors[i][16] = bordercolor;\r
+         _ES=FP_SEG(&colors[i]);\r
+         _DX=FP_OFF(&colors[i]);\r
+         _AX=0x1002;\r
+         geninterrupt(0x10);\r
+         VW_WaitVBL(6);\r
+       }\r
+       screenfaded = true;\r
+#endif\r
+}\r
+\r
+void VW_FadeDown(void)\r
+{\r
+#if GRMODE == EGAGR\r
+       int i;\r
+\r
+       for (i=5;i>2;i--)\r
+       {\r
+         colors[i][16] = bordercolor;\r
+         _ES=FP_SEG(&colors[i]);\r
+         _DX=FP_OFF(&colors[i]);\r
+         _AX=0x1002;\r
+         geninterrupt(0x10);\r
+         VW_WaitVBL(6);\r
+       }\r
+       screenfaded = false;\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= VW_SetAtrReg\r
+=\r
+= Sets an attribute (pallete / border) register\r
+= Does NOT vsync!\r
+=\r
+========================\r
+*/\r
+\r
+void VW_SetAtrReg (int reg, int value)\r
+{\r
+  asm  cli\r
+  asm  mov     dx,STATUS_REGISTER_1\r
+  asm  in      al,dx\r
+  asm  mov     dx,ATR_INDEX\r
+\r
+  asm  mov     al,BYTE PTR [reg]\r
+  asm  out     dx,al\r
+  asm  mov     al,BYTE PTR [value]\r
+  asm  out     dx,al\r
+  asm  mov     dx,0x3da\r
+  asm  in      al,dx\r
+  asm  mov     dx,ATR_INDEX\r
+  asm  mov     al,0x20\r
+  asm  out     dx,al\r
+  asm  sti\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_SetLineWidth\r
+=\r
+= Must be an even number of bytes\r
+=\r
+====================\r
+*/\r
+\r
+void VW_SetLineWidth (int width)\r
+{\r
+  int i,offset;\r
+\r
+#if GRMODE == EGAGR\r
+//\r
+// set wide virtual screen\r
+//\r
+asm    mov     dx,CRTC_INDEX\r
+asm    mov     al,CRTC_OFFSET\r
+asm mov        ah,[BYTE PTR width]\r
+asm    shr     ah,1\r
+asm    out     dx,ax\r
+#endif\r
+\r
+//\r
+// set up lookup tables\r
+//\r
+  linewidth = width;\r
+\r
+  offset = 0;\r
+\r
+  for (i=0;i<VIRTUALHEIGHT;i++)\r
+  {\r
+       ylookup[i]=offset;\r
+       offset += width;\r
+  }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_SetSplitScreen\r
+=\r
+====================\r
+*/\r
+#ifdef CAT3D\r
+void VW_SetSplitScreen (int linenum)\r
+{\r
+       VW_WaitVBL (1);\r
+       if (videocard==VGAcard)\r
+               linenum=linenum*2-1;\r
+       outportb (CRTC_INDEX,CRTC_LINECOMPARE);\r
+       outportb (CRTC_INDEX+1,linenum % 256);\r
+       outportb (CRTC_INDEX,CRTC_OVERFLOW);\r
+       outportb (CRTC_INDEX+1, 1+16*(linenum/256));\r
+       if (videocard==VGAcard)\r
+       {\r
+               outportb (CRTC_INDEX,CRTC_MAXSCANLINE);\r
+               outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));\r
+       }\r
+}\r
+#endif\r
+//===========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_ClearVideo\r
+=\r
+====================\r
+*/\r
+\r
+void   VW_ClearVideo (int color)\r
+{\r
+#if GRMODE == EGAGR\r
+       EGAWRITEMODE(2);\r
+       EGAMAPMASK(15);\r
+\r
+       color = (color << 8) & color;   //BUG: color is always 0 after this\r
+#endif\r
+\r
+#if GRMODE == CGAGR\r
+       color = (color << 12) & (color << 8) & (color << 4) & color;    //BUG: color is always 0 after this\r
+#endif\r
+\r
+       VW_WaitVBL(1);\r
+\r
+asm    mov     es, screenseg;\r
+asm    mov     di, displayofs;\r
+asm    and     di, not 1;\r
+asm    mov     cx, 8000h;\r
+asm    mov     ax, color;\r
+asm    rep stosw;\r
+\r
+#if GRMODE == EGAGR\r
+       EGAWRITEMODE(0);\r
+#endif\r
+}\r
+\r
+//===========================================================================\r
+\r
+#if NUMPICS>0\r
+\r
+/*\r
+====================\r
+=\r
+= VW_DrawPic\r
+=\r
+= X in bytes, y in pixels, chunknum is the #defined picnum\r
+=\r
+====================\r
+*/\r
+\r
+void VW_DrawPic(unsigned x, unsigned y, unsigned chunknum)\r
+{\r
+       int     picnum = chunknum - STARTPICS;\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+       source = grsegs[chunknum];\r
+       dest = ylookup[y]+x+bufferofs;\r
+       width = pictable[picnum].width;\r
+       height = pictable[picnum].height;\r
+\r
+       VW_MemToScreen(source,dest,width,height);\r
+}\r
+\r
+\r
+#endif\r
+\r
+#if NUMPICM>0\r
+\r
+/*\r
+====================\r
+=\r
+= VW_DrawMPic\r
+=\r
+= X in bytes, y in pixels, chunknum is the #defined picnum\r
+=\r
+====================\r
+*/\r
+\r
+void VW_DrawMPic(unsigned x, unsigned y, unsigned chunknum)\r
+{\r
+       int     picnum = chunknum - STARTPICM;\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+       source = grsegs[chunknum];\r
+       dest = ylookup[y]+x+bufferofs;\r
+       width = picmtable[picnum].width;\r
+       height = picmtable[picnum].height;\r
+\r
+       VW_MaskBlock(source,0,dest,width,height,width*height);\r
+}\r
+\r
+void VW_ClipDrawMPic(unsigned x, int y, unsigned chunknum)\r
+{\r
+       int     picnum = chunknum - STARTPICM;\r
+       memptr source;\r
+       unsigned dest,width,ofs,plane;\r
+       int             height;\r
+\r
+       source = grsegs[chunknum];\r
+       width = picmtable[picnum].width;\r
+       height = picmtable[picnum].height;\r
+       plane = width*height;\r
+\r
+       ofs = 0;\r
+       if (y<0)\r
+       {\r
+               ofs= -y*width;\r
+               height+=y;\r
+               y=0;\r
+       }\r
+       else if (y+height>216)\r
+       {\r
+               height-=(y-216);\r
+       }\r
+       dest = ylookup[y]+x+bufferofs;\r
+       if (height<1)\r
+               return;\r
+\r
+       VW_MaskBlock(source,ofs,dest,width,height,plane);\r
+}\r
+\r
+\r
+#endif\r
+\r
+//===========================================================================\r
+\r
+#if NUMSPRITES>0\r
+\r
+/*\r
+====================\r
+=\r
+= VW_DrawSprite\r
+=\r
+= X and Y in pixels, it will match the closest shift possible\r
+=\r
+= To do:\r
+= Add vertical clipping!\r
+= Make the shifts act as center points, rather than break points\r
+=\r
+====================\r
+*/\r
+\r
+void VW_DrawSprite(int x, int y, unsigned chunknum)\r
+{\r
+       spritetabletype far *spr;\r
+       spritetype _seg *block;\r
+       unsigned        dest,shift;\r
+\r
+       spr = &spritetable[chunknum-STARTSPRITES];\r
+       block = (spritetype _seg *)grsegs[chunknum];\r
+\r
+       y+=spr->orgy>>G_P_SHIFT;\r
+       x+=spr->orgx>>G_P_SHIFT;\r
+\r
+#if GRMODE == EGAGR\r
+       shift = (x&7)/2;\r
+#endif\r
+#if GRMODE == CGAGR\r
+       shift = 0;\r
+#endif\r
+\r
+       dest = bufferofs + ylookup[y];\r
+       if (x>=0)\r
+               dest += x/SCREENXDIV;\r
+       else\r
+               dest += (x+1)/SCREENXDIV;\r
+\r
+       VW_MaskBlock (block,block->sourceoffset[shift],dest,\r
+               block->width[shift],spr->height,block->planesize[shift]);\r
+}\r
+\r
+#endif\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= VW_Hlin\r
+=\r
+==================\r
+*/\r
+\r
+\r
+#if GRMODE == EGAGR\r
+\r
+unsigned char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};\r
+unsigned char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};\r
+\r
+void VW_Hlin(unsigned xl, unsigned xh, unsigned y, unsigned color)\r
+{\r
+  unsigned dest,xlb,xhb,maskleft,maskright,mid;\r
+\r
+       xlb=xl/8;\r
+       xhb=xh/8;\r
+\r
+       EGAWRITEMODE(2);\r
+       EGAMAPMASK(15);\r
+\r
+       maskleft = leftmask[xl&7];\r
+       maskright = rightmask[xh&7];\r
+\r
+       mid = xhb-xlb-1;\r
+       dest = bufferofs+ylookup[y]+xlb;\r
+\r
+  if (xlb==xhb)\r
+  {\r
+  //\r
+  // entire line is in one byte\r
+  //\r
+\r
+       maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+\r
+       asm     mov     dx,GC_INDEX\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     ah,[BYTE PTR maskleft]\r
+       asm     out     dx,ax           // mask off pixels\r
+\r
+       asm     mov     al,[BYTE PTR color]\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+       goto    done;\r
+  }\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[dest]\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm    mov     al,GC_BITMASK\r
+asm    mov     ah,[BYTE PTR maskleft]\r
+asm    out     dx,ax           // mask off pixels\r
+\r
+asm    mov     al,bh\r
+asm    mov     bl,[es:di]      // load latches\r
+asm    stosb\r
+\r
+//\r
+// draw middle\r
+//\r
+asm    mov     ax,GC_BITMASK + 255*256\r
+asm    out     dx,ax           // no masking\r
+\r
+asm    mov     al,bh\r
+asm    mov     cx,[mid]\r
+asm    rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm    mov     al,GC_BITMASK\r
+asm    mov     ah,[BYTE PTR maskright]\r
+asm    out     dx,ax           // mask off pixels\r
+\r
+asm    xchg    bh,[es:di]      // load latches and write pixels\r
+\r
+done:\r
+       EGABITMASK(255);\r
+       EGAWRITEMODE(0);\r
+}\r
+#endif\r
+\r
+\r
+#if GRMODE == CGAGR\r
+\r
+unsigned char pixmask[4] = {0xc0,0x30,0x0c,0x03};\r
+unsigned char leftmask[4] = {0xff,0x3f,0x0f,0x03};\r
+unsigned char rightmask[4] = {0xc0,0xf0,0xfc,0xff};\r
+unsigned char colorbyte[4] = {0,0x55,0xaa,0xff};\r
+\r
+//\r
+// could be optimized for rep stosw\r
+//\r
+void VW_Hlin(unsigned xl, unsigned xh, unsigned y, unsigned color)\r
+{\r
+       unsigned dest,xlb,xhb,mid;\r
+       byte maskleft,maskright;\r
+\r
+       color = colorbyte[color];       // expand 2 color bits to 8\r
+\r
+       xlb=xl/4;\r
+       xhb=xh/4;\r
+\r
+       maskleft = leftmask[xl&3];\r
+       maskright = rightmask[xh&3];\r
+\r
+       mid = xhb-xlb-1;\r
+       dest = bufferofs+ylookup[y]+xlb;\r
+asm    mov     es,[screenseg]\r
+\r
+       if (xlb==xhb)\r
+       {\r
+       //\r
+       // entire line is in one byte\r
+       //\r
+               maskleft&=maskright;\r
+\r
+               asm     mov     ah,[maskleft]\r
+               asm     mov     bl,[BYTE PTR color]\r
+               asm     and     bl,[maskleft]\r
+               asm     not     ah\r
+\r
+               asm     mov     di,[dest]\r
+\r
+               asm     mov     al,[es:di]\r
+               asm     and     al,ah                   // mask out pixels\r
+               asm     or      al,bl                   // or in color\r
+               asm     mov     [es:di],al\r
+               return;\r
+       }\r
+\r
+asm    mov     di,[dest]\r
+asm    mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm    mov     ah,[maskleft]\r
+asm    mov     bl,bh\r
+asm    and     bl,[maskleft]\r
+asm    not     ah\r
+asm    mov     al,[es:di]\r
+asm    and     al,ah                   // mask out pixels\r
+asm    or      al,bl                   // or in color\r
+asm    stosb\r
+\r
+//\r
+// draw middle\r
+//\r
+asm    mov     al,bh\r
+asm    mov     cx,[mid]\r
+asm    rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm    mov     ah,[maskright]\r
+asm    mov     bl,bh\r
+asm    and     bl,[maskright]\r
+asm    not     ah\r
+asm    mov     al,[es:di]\r
+asm    and     al,ah                   // mask out pixels\r
+asm    or      al,bl                   // or in color\r
+asm    stosb\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= VW_Bar\r
+=\r
+= Pixel addressable block fill routine\r
+=\r
+==================\r
+*/\r
+\r
+#if GRMODE == CGAGR\r
+\r
+void VW_Bar (unsigned x, unsigned y, unsigned width, unsigned height,\r
+       unsigned color)\r
+{\r
+       unsigned xh = x+width-1;\r
+\r
+       while (height--)\r
+               VW_Hlin (x,xh,y++,color);\r
+}\r
+\r
+#endif\r
+\r
+\r
+#if    GRMODE == EGAGR\r
+\r
+void VW_Bar (unsigned x, unsigned y, unsigned width, unsigned height,\r
+       unsigned color)\r
+{\r
+       unsigned dest,xh,xlb,xhb,maskleft,maskright,mid;\r
+\r
+       xh = x+width-1;\r
+       xlb=x/8;\r
+       xhb=xh/8;\r
+\r
+       EGAWRITEMODE(2);\r
+       EGAMAPMASK(15);\r
+\r
+       maskleft = leftmask[x&7];\r
+       maskright = rightmask[xh&7];\r
+\r
+       mid = xhb-xlb-1;\r
+       dest = bufferofs+ylookup[y]+xlb;\r
+\r
+       if (xlb==xhb)\r
+       {\r
+       //\r
+       // entire line is in one byte\r
+       //\r
+\r
+               maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+\r
+       asm     mov     dx,GC_INDEX\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     ah,[BYTE PTR maskleft]\r
+       asm     out     dx,ax           // mask off pixels\r
+\r
+       asm     mov     ah,[BYTE PTR color]\r
+       asm     mov     dx,[linewidth]\r
+yloop1:\r
+       asm     mov     al,ah\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+       asm     add     di,dx                   // down to next line\r
+       asm     dec     [height]\r
+       asm     jnz     yloop1\r
+\r
+               goto    done;\r
+       }\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[dest]\r
+asm    mov     bh,[BYTE PTR color]\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     si,[linewidth]\r
+asm    sub     si,[mid]                        // add to di at end of line to get to next scan\r
+asm    dec     si\r
+\r
+//\r
+// draw left side\r
+//\r
+yloop2:\r
+asm    mov     al,GC_BITMASK\r
+asm    mov     ah,[BYTE PTR maskleft]\r
+asm    out     dx,ax           // mask off pixels\r
+\r
+asm    mov     al,bh\r
+asm    mov     bl,[es:di]      // load latches\r
+asm    stosb\r
+\r
+//\r
+// draw middle\r
+//\r
+asm    mov     ax,GC_BITMASK + 255*256\r
+asm    out     dx,ax           // no masking\r
+\r
+asm    mov     al,bh\r
+asm    mov     cx,[mid]\r
+asm    rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm    mov     al,GC_BITMASK\r
+asm    mov     ah,[BYTE PTR maskright]\r
+asm    out     dx,ax           // mask off pixels\r
+\r
+asm    mov     al,bh\r
+asm    xchg    al,[es:di]      // load latches and write pixels\r
+\r
+asm    add     di,si           // move to start of next line\r
+asm    dec     [height]\r
+asm    jnz     yloop2\r
+\r
+done:\r
+       EGABITMASK(255);\r
+       EGAWRITEMODE(0);\r
+}\r
+\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= VW_MeasureString\r
+=\r
+==================\r
+*/\r
+\r
+#if NUMFONT+NUMFONTM>0\r
+void\r
+VWL_MeasureString (char far *string, word *width, word *height, fontstruct _seg *font)\r
+{\r
+       *height = font->height;\r
+       for (*width = 0;*string;string++)\r
+               *width += font->width[*((byte far *)string)];   // proportional width\r
+}\r
+\r
+void   VW_MeasurePropString (char far *string, word *width, word *height)\r
+{\r
+       VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONT+fontnumber]);\r
+}\r
+\r
+void   VW_MeasureMPropString  (char far *string, word *width, word *height)\r
+{\r
+       VWL_MeasureString(string,width,height,(fontstruct _seg *)grsegs[STARTFONTM+fontnumber]);\r
+}\r
+\r
+\r
+#endif\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       CGA stuff\r
+\r
+=============================================================================\r
+*/\r
+\r
+#if GRMODE == CGAGR\r
+\r
+#define CGACRTCWIDTH   40\r
+\r
+/*\r
+==========================\r
+=\r
+= VW_CGAFullUpdate\r
+=\r
+==========================\r
+*/\r
+\r
+void VW_CGAFullUpdate (void)\r
+{\r
+       byte    *update;\r
+       boolean halftile;\r
+       unsigned        x,y,middlerows,middlecollumns;\r
+\r
+       displayofs = bufferofs+panadjust;\r
+\r
+asm    mov     ax,0xb800\r
+asm    mov     es,ax\r
+\r
+asm    mov     si,[displayofs]\r
+asm    xor     di,di\r
+\r
+asm    mov     bx,100                          // pairs of scan lines to copy\r
+asm    mov     dx,[linewidth]\r
+asm    sub     dx,80\r
+\r
+asm    mov     ds,[screenseg]\r
+asm    test    si,1\r
+asm    jz      evenblock\r
+\r
+//\r
+// odd source\r
+//\r
+asm    mov     ax,39                           // words accross screen\r
+copytwolineso:\r
+asm    movsb\r
+asm    mov     cx,ax\r
+asm    rep     movsw\r
+asm    movsb\r
+asm    add     si,dx\r
+asm    add     di,0x2000-80            // go to the interlaced bank\r
+asm    movsb\r
+asm    mov     cx,ax\r
+asm    rep     movsw\r
+asm    movsb\r
+asm    add     si,dx\r
+asm    sub     di,0x2000                       // go to the non interlaced bank\r
+\r
+asm    dec     bx\r
+asm    jnz     copytwolineso\r
+asm    jmp     blitdone\r
+\r
+//\r
+// even source\r
+//\r
+evenblock:\r
+asm    mov     ax,40                           // words accross screen\r
+copytwolines:\r
+asm    mov     cx,ax\r
+asm    rep     movsw\r
+asm    add     si,dx\r
+asm    add     di,0x2000-80            // go to the interlaced bank\r
+asm    mov     cx,ax\r
+asm    rep     movsw\r
+asm    add     si,dx\r
+asm    sub     di,0x2000                       // go to the non interlaced bank\r
+\r
+asm    dec     bx\r
+asm    jnz     copytwolines\r
+\r
+blitdone:\r
+asm    mov     ax,ss\r
+asm    mov     ds,ax\r
+asm    mov     es,ax\r
+\r
+asm    xor     ax,ax                           // clear out the update matrix\r
+asm    mov     cx,UPDATEWIDE*UPDATEHIGH/2\r
+\r
+asm    mov     di,[baseupdateptr]\r
+asm    rep     stosw\r
+\r
+       updateptr = baseupdateptr;\r
+       *(unsigned *)(updateptr + UPDATEWIDE*PORTTILESHIGH) = UPDATETERMINATE;\r
+}\r
+\r
+\r
+#endif\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                          CURSOR ROUTINES\r
+\r
+These only work in the context of the double buffered update routines\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+====================\r
+=\r
+= VWL_DrawCursor\r
+=\r
+= Background saves, then draws the cursor at cursorspot\r
+=\r
+====================\r
+*/\r
+\r
+void VWL_DrawCursor (void)\r
+{\r
+       cursorspot = bufferofs + ylookup[cursory+pansy]+(cursorx+pansx)/SCREENXDIV;\r
+       VW_ScreenToMem(cursorspot,cursorsave,cursorwidth,cursorheight);\r
+       VWB_DrawSprite(cursorx,cursory,cursornumber);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= VWL_EraseCursor\r
+=\r
+====================\r
+*/\r
+\r
+void VWL_EraseCursor (void)\r
+{\r
+       VW_MemToScreen(cursorsave,cursorspot,cursorwidth,cursorheight);\r
+       VW_MarkUpdateBlock ((cursorx+pansx)&SCREENXMASK,cursory+pansy,\r
+               ( (cursorx+pansx)&SCREENXMASK)+cursorwidth*SCREENXDIV-1,\r
+               cursory+pansy+cursorheight-1);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= VW_ShowCursor\r
+=\r
+====================\r
+*/\r
+\r
+void VW_ShowCursor (void)\r
+{\r
+       cursorvisible++;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_HideCursor\r
+=\r
+====================\r
+*/\r
+\r
+void VW_HideCursor (void)\r
+{\r
+       cursorvisible--;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_MoveCursor\r
+=\r
+====================\r
+*/\r
+#define MAXCURSORX     (319-24)\r
+#define MAXCURSORY     (199-24)\r
+\r
+void VW_MoveCursor (int x, int y)\r
+{\r
+#ifdef CAT3D\r
+       if (x>MAXCURSORX)\r
+               x=MAXCURSORX;\r
+       if (y>MAXCURSORY)\r
+               y=MAXCURSORY;                   // catacombs hack to keep cursor on screen\r
+#endif\r
+\r
+       cursorx = x;\r
+       cursory = y;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= VW_SetCursor\r
+=\r
+= Load in a sprite to be used as a cursor, and allocate background save space\r
+=\r
+====================\r
+*/\r
+\r
+void VW_SetCursor (int spritenum)\r
+{\r
+       VW_FreeCursor ();\r
+\r
+       cursornumber = spritenum;\r
+\r
+       CA_CacheGrChunk (spritenum);\r
+       MM_SetLock (&grsegs[spritenum],true);\r
+\r
+       cursorwidth = spritetable[spritenum-STARTSPRITES].width+1;\r
+       cursorheight = spritetable[spritenum-STARTSPRITES].height;\r
+\r
+       MM_GetPtr (&cursorsave,cursorwidth*cursorheight*5);\r
+       MM_SetLock (&cursorsave,true);\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= VW_FreeCursor\r
+=\r
+= Frees the memory used by the cursor and its background save\r
+=\r
+====================\r
+*/\r
+\r
+void VW_FreeCursor (void)\r
+{\r
+       if (cursornumber)\r
+       {\r
+               MM_SetLock (&grsegs[cursornumber],false);\r
+               MM_SetPurge (&grsegs[cursornumber],3);\r
+               MM_SetLock (&cursorsave,false);\r
+               MM_FreePtr (&cursorsave);\r
+               cursornumber = 0;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                               Double buffer management routines\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+======================\r
+=\r
+= VW_InitDoubleBuffer\r
+=\r
+======================\r
+*/\r
+\r
+void VW_InitDoubleBuffer (void)\r
+{\r
+#if GRMODE == EGAGR\r
+       VW_SetScreen (displayofs+panadjust,0);                  // no pel pan\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= VW_FixRefreshBuffer\r
+=\r
+= Copies the view page to the buffer page on page flipped refreshes to\r
+= avoid a one frame shear around pop up windows\r
+=\r
+======================\r
+*/\r
+\r
+void VW_FixRefreshBuffer (void)\r
+{\r
+#if GRMODE == EGAGR\r
+       VW_ScreenToScreen (displayofs,bufferofs,PORTTILESWIDE*4*CHARWIDTH,\r
+               (PORTTILESHIGH-1)*16);\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= VW_QuitDoubleBuffer\r
+=\r
+======================\r
+*/\r
+\r
+void VW_QuitDoubleBuffer (void)\r
+{\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= VW_MarkUpdateBlock\r
+=\r
+= Takes a pixel bounded block and marks the tiles in bufferblocks\r
+= Returns 0 if the entire block is off the buffer screen\r
+=\r
+=======================\r
+*/\r
+\r
+int VW_MarkUpdateBlock (int x1, int y1, int x2, int y2)\r
+{\r
+       int     x,y,xt1,yt1,xt2,yt2,nextline;\r
+       byte *mark;\r
+\r
+       xt1 = x1>>PIXTOBLOCK;\r
+       yt1 = y1>>PIXTOBLOCK;\r
+\r
+       xt2 = x2>>PIXTOBLOCK;\r
+       yt2 = y2>>PIXTOBLOCK;\r
+\r
+       if (xt1<0)\r
+               xt1=0;\r
+       else if (xt1>=UPDATEWIDE-1)\r
+               return 0;\r
+\r
+       if (yt1<0)\r
+               yt1=0;\r
+       else if (yt1>UPDATEHIGH)\r
+               return 0;\r
+\r
+       if (xt2<0)\r
+               return 0;\r
+       else if (xt2>=UPDATEWIDE-1)\r
+               xt2 = UPDATEWIDE-2;\r
+\r
+       if (yt2<0)\r
+               return 0;\r
+       else if (yt2>=UPDATEHIGH)\r
+               yt2 = UPDATEHIGH-1;\r
+\r
+       mark = updateptr + uwidthtable[yt1] + xt1;\r
+       nextline = UPDATEWIDE - (xt2-xt1) - 1;\r
+\r
+       for (y=yt1;y<=yt2;y++)\r
+       {\r
+               for (x=xt1;x<=xt2;x++)\r
+                       *mark++ = 1;                    // this tile will need to be updated\r
+\r
+               mark += nextline;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+\r
+/*\r
+===========================\r
+=\r
+= VW_UpdateScreen\r
+=\r
+= Updates any changed areas of the double buffer and displays the cursor\r
+=\r
+===========================\r
+*/\r
+\r
+void VW_UpdateScreen (void)\r
+{\r
+       if (cursorvisible>0)\r
+               VWL_DrawCursor();\r
+\r
+#if GRMODE == EGAGR\r
+       VWL_UpdateScreenBlocks();\r
+#endif\r
+#if GRMODE == CGAGR\r
+       VW_CGAFullUpdate();\r
+#endif\r
+\r
+       if (cursorvisible>0)\r
+               VWL_EraseCursor();\r
+}\r
+\r
+\r
+\r
+void VWB_DrawTile8 (int x, int y, int tile)\r
+{\r
+       x+=pansx;\r
+       y+=pansy;\r
+       if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+7,y+7))\r
+               VW_DrawTile8 (x/SCREENXDIV,y,tile);\r
+}\r
+\r
+void VWB_DrawTile8M (int x, int y, int tile)\r
+{\r
+       int xb;\r
+\r
+       x+=pansx;\r
+       y+=pansy;\r
+       xb = x/SCREENXDIV;                      // use intermediate because VW_DT8M is macro\r
+       if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+7,y+7))\r
+               VW_DrawTile8M (xb,y,tile);\r
+}\r
+\r
+void VWB_DrawTile16 (int x, int y, int tile)\r
+{\r
+       x+=pansx;\r
+       y+=pansy;\r
+       if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+15,y+15))\r
+               VW_DrawTile16 (x/SCREENXDIV,y,tile);\r
+}\r
+\r
+void VWB_DrawTile16M (int x, int y, int tile)\r
+{\r
+       int xb;\r
+\r
+       x+=pansx;\r
+       y+=pansy;\r
+       xb = x/SCREENXDIV;              // use intermediate because VW_DT16M is macro\r
+       if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+15,y+15))\r
+               VW_DrawTile16M (xb,y,tile);\r
+}\r
+\r
+#if NUMPICS\r
+void VWB_DrawPic (int x, int y, int chunknum)\r
+{\r
+// mostly copied from drawpic\r
+       int     picnum = chunknum - STARTPICS;\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+       x+=pansx;\r
+       y+=pansy;\r
+       x/= SCREENXDIV;\r
+\r
+       source = grsegs[chunknum];\r
+       dest = ylookup[y]+x+bufferofs;\r
+       width = pictable[picnum].width;\r
+       height = pictable[picnum].height;\r
+\r
+       if (VW_MarkUpdateBlock (x*SCREENXDIV,y,(x+width)*SCREENXDIV-1,y+height-1))\r
+               VW_MemToScreen(source,dest,width,height);\r
+}\r
+#endif\r
+\r
+#if NUMPICM>0\r
+void VWB_DrawMPic(int x, int y, int chunknum)\r
+{\r
+// mostly copied from drawmpic\r
+       int     picnum = chunknum - STARTPICM;\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+       x+=pansx;\r
+       y+=pansy;\r
+       x/=SCREENXDIV;\r
+\r
+       source = grsegs[chunknum];\r
+       dest = ylookup[y]+x+bufferofs;\r
+       width = picmtable[picnum].width;\r
+       height = picmtable[picnum].height;\r
+\r
+       if (VW_MarkUpdateBlock (x*SCREENXDIV,y,(x+width)*SCREENXDIV-1,y+height-1))\r
+               VW_MaskBlock(source,0,dest,width,height,width*height);\r
+}\r
+#endif\r
+\r
+\r
+void VWB_Bar (int x, int y, int width, int height, int color)\r
+{\r
+       x+=pansx;\r
+       y+=pansy;\r
+       if (VW_MarkUpdateBlock (x,y,x+width,y+height-1) )\r
+               VW_Bar (x,y,width,height,color);\r
+}\r
+\r
+\r
+#if NUMFONT\r
+void VWB_DrawPropString         (char far *string)\r
+{\r
+       int x,y;\r
+       x = px+pansx;\r
+       y = py+pansy;\r
+       VW_DrawPropString (string);\r
+       VW_MarkUpdateBlock(x,y,x+bufferwidth*8-1,y+bufferheight-1);\r
+}\r
+#endif\r
+\r
+\r
+#if NUMFONTM\r
+void VWB_DrawMPropString (char far *string)\r
+{\r
+       int x,y;\r
+       x = px+pansx;\r
+       y = py+pansy;\r
+       VW_DrawMPropString (string);\r
+       VW_MarkUpdateBlock(x,y,x+bufferwidth*8-1,y+bufferheight-1);\r
+}\r
+#endif\r
+\r
+#if NUMSPRITES\r
+void VWB_DrawSprite(int x, int y, int chunknum)\r
+{\r
+       spritetabletype far *spr;\r
+       spritetype _seg *block;\r
+       unsigned        dest,shift,width,height;\r
+\r
+       x+=pansx;\r
+       y+=pansy;\r
+\r
+       spr = &spritetable[chunknum-STARTSPRITES];\r
+       block = (spritetype _seg *)grsegs[chunknum];\r
+\r
+       y+=spr->orgy>>G_P_SHIFT;\r
+       x+=spr->orgx>>G_P_SHIFT;\r
+\r
+\r
+#if GRMODE == EGAGR\r
+       shift = (x&7)/2;\r
+#endif\r
+#if GRMODE == CGAGR\r
+       shift = 0;\r
+#endif\r
+\r
+       dest = bufferofs + ylookup[y];\r
+       if (x>=0)\r
+               dest += x/SCREENXDIV;\r
+       else\r
+               dest += (x+1)/SCREENXDIV;\r
+\r
+       width = block->width[shift];\r
+       height = spr->height;\r
+\r
+       if (VW_MarkUpdateBlock (x&SCREENXMASK,y,(x&SCREENXMASK)+width*SCREENXDIV-1\r
+               ,y+height-1))\r
+               VW_MaskBlock (block,block->sourceoffset[shift],dest,\r
+                       width,height,block->planesize[shift]);\r
+}\r
+#endif\r
+\r
+void VWB_Plot (int x, int y, int color)\r
+{\r
+       x+=pansx;\r
+       y+=pansy;\r
+       if (VW_MarkUpdateBlock (x,y,x,y))\r
+               VW_Plot(x,y,color);\r
+}\r
+\r
+void VWB_Hlin (int x1, int x2, int y, int color)\r
+{\r
+       x1+=pansx;\r
+       x2+=pansx;\r
+       y+=pansy;\r
+       if (VW_MarkUpdateBlock (x1,y,x2,y))\r
+               VW_Hlin(x1,x2,y,color);\r
+}\r
+\r
+void VWB_Vlin (int y1, int y2, int x, int color)\r
+{\r
+       x+=pansx;\r
+       y1+=pansy;\r
+       y2+=pansy;\r
+       if (VW_MarkUpdateBlock (x,y1,x,y2))\r
+               VW_Vlin(y1,y2,x,color);\r
+}\r
+\r
+\r
+//===========================================================================\r