--- /dev/null
+/* 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