/* Module: ZG_LwLvl (ZipGraph Low-Level functions) Version 1.10 01-Nov-1989 Language: ANSI C w/MS-DOS extensions Environ: IBM-PC compatibles w/MDA, CGA, HGC, EGA, MCGA, or VGA Compilers: Borland Turbo C v2.00 Lattice C v6.01 Microsoft C v5.10 and QuickC v2.01 Zortech C & C++ v2.01 Purpose: Provides low-level graphics routines for detecting graphics adapters, setting graphics modes, and plotting pixels. This module is required by the higher-level ZipGraph modules. Written by: Scott Robert Ladd 705 West Virginia Gunnison CO 81230 BBS (303)641-6438 FidoNet 1:104/708 */ #define __ZG_LWLVL_C 1 #if !defined(LATTICE) #include "conio.h" #endif #include "dos.h" #include "zg_lwlvl.h" /*----------------------------- handle compiler differences -----------------------------*/ #if defined(_MSC) || defined(_QC) || defined(__ZTC__) || defined(LATTICE) #define OUT_PORT(port,val) outp(port,val) #elif defined(__TURBOC__) #define OUT_PORT(port,val) outportb(port,val) #endif /*-------------------------- pointer conversion macro --------------------------*/ #if !defined(MK_FP) #define MK_FP(seg,off) ((void far *)(((long)(seg) << 16)|(unsigned)(off))) #endif /*------------------------------ ZipGraph INTERNAL PROTOTYPES ------------------------------*/ static void DummyPlot(int x, int y, int color); static int DummyRead(int x, int y); static void CGA1_Plot(int x, int y, int color); static void CGA2_Plot(int x, int y, int color); static void MCGA_Plot(int x, int y, int color); static void M256_Plot(int x, int y, int color); static void EVGA_Plot(int x, int y, int color); static int CGA1_Read(int x, int y); static int CGA2_Read(int x, int y); static int MCGA_Read(int x, int y); static int M256_Read(int x, int y); static int EVGA_Read(int x, int y); static void HGC_GraphMode(void); static void HGC_TextMode(void); static void HGC_Plot(int x, int y, int color); static int HGC_Read(int x, int y); /*--------------------------- ZipGraph PUBLIC VARIABLES ---------------------------*/ struct { int Type; int Monitor; int Mode; int Xwidth; int Ylength; int NoColors; } ZG_VideoInfo; void (* ZG_PlotPixel)(int x, int y, int color) = DummyPlot; int (* ZG_ReadPixel)(int x, int y) = DummyRead; /*---------------------------------------- ZipGraph INTERNAL TABLES and VARIABLES ----------------------------------------*/ static const struct { int BestRes; int MostColor; unsigned long ModeList; } VideoTable[06] = { { 0, 0, 0x00000000L}, { ZG_MOD_640x200x2, ZG_MOD_320x200x4, 0x00000006L}, { ZG_MOD_720x348x2, ZG_MOD_720x348x2, 0x00000001L}, { ZG_MOD_640x350x16, ZG_MOD_640x350x16, 0x0000007EL}, { ZG_MOD_640x480x2, ZG_MOD_320x200x256, 0x00000486L}, { ZG_MOD_640x480x16, ZG_MOD_320x200x256, 0x000003FEL} }; static const struct { char ActualMode; void (* PixelProc)(int x, int y, int color); int (* ReadProc)(int x, int y); int Xwidth; int Ylength; int NoColors; } ModeData[10] = { { 0x00, HGC_Plot, HGC_Read, 720, 348, 2 }, { 0x04, CGA2_Plot, CGA2_Read, 320, 200, 4 }, { 0x06, CGA1_Plot, CGA1_Read, 640, 200, 2 }, { 0x0D, MCGA_Plot, MCGA_Read, 320, 200, 16 }, { 0x0E, EVGA_Plot, EVGA_Read, 640, 200, 16 }, { 0x0F, EVGA_Plot, EVGA_Read, 640, 350, 4 }, { 0x10, EVGA_Plot, EVGA_Read, 640, 350, 16 }, { 0x11, EVGA_Plot, EVGA_Read, 640, 480, 2 }, { 0x12, EVGA_Plot, EVGA_Read, 640, 480, 16 }, { 0x13, M256_Plot, M256_Read, 320, 200, 256} }; static unsigned char OriginalMode = 0; static int PixelMode = ZG_PXL_SET; static int ZG_Inited = 0; /*------------------------------ IBM-type adapter global data ------------------------------*/ #define CGA_VID_SEG 0xB800 #define EVGA_VID_SEG 0xA000 /*------------------------- MDA and HGC global data -------------------------*/ /* Hercules video RAM segment */ #define HGC_VID_SEG 0xB000 /* Monochrome 6845 Video Controller ports */ #define HGC_IDX_PORT 0x03B4 #define HGC_DAT_PORT 0x03B5 #define HGC_CTL_PORT 0x03B8 #define HGC_CFG_PORT 0x03BF /*---------------------------- ZipGraph PUBLIC FUNCTIONS! ----------------------------*/ int ZG_Init(void) { union REGS regs; int i, status_changed; unsigned char orig_status; ZG_VideoInfo.Type = ZG_ERROR; ZG_VideoInfo.Monitor = ZG_ERROR; ZG_VideoInfo.Mode = ZG_ERROR; ZG_VideoInfo.Xwidth = 0; ZG_VideoInfo.Ylength = 0; ZG_VideoInfo.NoColors = 0; regs.h.ah = 0x1A; /* VGA Identifier Adapter Service */ regs.h.al = 0; int86(0x10,®s,®s); if (regs.h.al == 0x1A) { switch (regs.h.bl) { case 1 : ZG_VideoInfo.Type = ZG_VID_MDA; ZG_VideoInfo.Monitor = ZG_MTR_MONO; break; case 2 : ZG_VideoInfo.Type = ZG_VID_CGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; case 4 : ZG_VideoInfo.Type = ZG_VID_EGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; case 5 : ZG_VideoInfo.Type = ZG_VID_EGA; ZG_VideoInfo.Monitor = ZG_MTR_MONO; break; case 7 : ZG_VideoInfo.Type = ZG_VID_VGA; ZG_VideoInfo.Monitor = ZG_MTR_MONO; break; case 8 : ZG_VideoInfo.Type = ZG_VID_VGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; case 10: ZG_VideoInfo.Type = ZG_VID_MCGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; case 11: ZG_VideoInfo.Type = ZG_VID_MCGA; ZG_VideoInfo.Monitor = ZG_MTR_MONO; break; case 12: ZG_VideoInfo.Type = ZG_VID_MCGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; default: return 1; } } else { /* check for an EGA */ regs.h.ah = 0x12; regs.x.bx = 0x0010; int86(0x10,®s,®s); if (regs.x.bx != 0x10) { ZG_VideoInfo.Type = ZG_VID_EGA; regs.h.ah = 0x12; regs.x.bx = 0x0010; int86(0x10,®s,®s); if (regs.h.bh == 0) ZG_VideoInfo.Monitor = ZG_MTR_COLOR; else ZG_VideoInfo.Monitor = ZG_MTR_MONO; } else { int86(0x11,®s,®s); switch ((regs.h.al & 0x30) >> 4) { case 0 : return 1; case 1 : case 2 : ZG_VideoInfo.Type = ZG_VID_CGA; ZG_VideoInfo.Monitor = ZG_MTR_COLOR; break; case 3 : status_changed = 0; orig_status = (unsigned char)(inp(0x03BA) & 0x80); for (i = 0; (i < 30000) && (!status_changed); ++i) if (orig_status != (unsigned char)(inp(0x03BA) & 0x80)) status_changed = 1; if (status_changed) ZG_VideoInfo.Type = ZG_VID_HGC; else ZG_VideoInfo.Type = ZG_VID_MDA; ZG_VideoInfo.Monitor = ZG_MTR_MONO; } } } if (ZG_VideoInfo.Type != ZG_VID_HGC) { regs.h.ah = 0x0F; int86(0x10,®s,®s); OriginalMode = regs.h.al; } ZG_Inited = 1; return 0; } int ZG_SetMode(int VideoMode) { union REGS regs; if (VideoMode < 0) return 1; if (VideoMode == ZG_MOD_BESTRES) VideoMode = VideoTable[ZG_VideoInfo.Type].BestRes; else if (VideoMode == ZG_MOD_MOSTCOLOR) VideoMode = VideoTable[ZG_VideoInfo.Type].MostColor; if ((VideoMode > ZG_MOD_320x200x256) || (!(VideoTable[ZG_VideoInfo.Type].ModeList & (1 << VideoMode)))) return 1; ZG_PlotPixel = ModeData[VideoMode].PixelProc; ZG_ReadPixel = ModeData[VideoMode].ReadProc; if (VideoMode == ZG_MOD_720x348x2) HGC_GraphMode(); else { regs.h.ah = 0; regs.h.al = ModeData[VideoMode].ActualMode; int86(0x10,®s,®s); } ZG_VideoInfo.Mode = VideoMode; ZG_VideoInfo.Xwidth = ModeData[VideoMode].Xwidth; ZG_VideoInfo.Ylength = ModeData[VideoMode].Ylength; ZG_VideoInfo.NoColors = ModeData[VideoMode].NoColors; return 0; } int ZG_Done(void) { union REGS regs; if (!ZG_Inited) return 1; if (ZG_VideoInfo.Type == ZG_VID_HGC) HGC_TextMode(); else { regs.h.ah = 0; regs.h.al = OriginalMode; int86(0x10,®s,®s); } return 0; } int ZG_SetPixelMode(int PixMode) { if ((PixMode < ZG_PXL_SET) || (PixMode > ZG_PXL_XOR)) return 1; PixelMode = PixMode; return 0; } int ZG_SetCGAPalette(char PaletteNo) { union REGS regs; if (ZG_VideoInfo.Type != ZG_VID_CGA) return 1; regs.h.ah = 0x0B; regs.h.bl = PaletteNo; regs.h.bh = 0x01; int86(0x10,®s,®s); return 0; } int ZG_SetEVGAPalette(char Palette, char Color) { union REGS regs; if ((ZG_VideoInfo.Type != ZG_VID_EGA) && (ZG_VideoInfo.Type != ZG_VID_VGA)) return 1; regs.h.ah = 0x10; regs.h.al = 0x00; regs.h.bh = Color; regs.h.bl = Palette; int86(0x10,®s,®s); return 0; } /*-------------------------------- Dummy pixel plotter and reader --------------------------------*/ static void DummyPlot(int x, int y, int color) { /* it does nothing */ } static int DummyRead(int x, int y) { /* it does nothing */ return 0; } /*--------------------------------------------- CGA, EGA, MCGA, VGA pixel plotting functions ---------------------------------------------*/ static void CGA1_Plot(int x, int y, int color) { /* this routine used for CGA 640x200x2 mode */ unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(CGA_VID_SEG, 0x2000 * (y&1) + 0x50 * (y/2) + (x >> 3)); /* calculate bit mask */ pixel_mask = 0x80 >> (x & 7); /* set pixel */ switch (PixelMode) { case ZG_PXL_SET : if (color) *pixel_byte |= pixel_mask; else *pixel_byte &= ~pixel_mask; break; case ZG_PXL_AND : if (color) *pixel_byte &= pixel_mask; break; case ZG_PXL_OR : if (!color) *pixel_byte |= pixel_mask; break; case ZG_PXL_XOR : if (!color) *pixel_byte ^= pixel_mask; } } static void CGA2_Plot(int x, int y, int color) { /* this routine used for CGA 320x200x4 mode */ unsigned int pixel_mask, alt_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(CGA_VID_SEG,0x2000 * (y & 1) + 80 * (y >> 1) + (x >> 2)); pixel_mask = (color & 3) << (6 - ((x & 3) << 1)); switch (PixelMode) { case ZG_PXL_SET : /* clear the appropriate bits */ alt_mask = 0xC0 >> ((x & 3) << 1); *pixel_byte &= ~alt_mask; /* insert the bits for the specified color */ *pixel_byte |= pixel_mask; break; case ZG_PXL_AND : *pixel_byte &= pixel_mask; break; case ZG_PXL_OR : *pixel_byte |= pixel_mask; break; case ZG_PXL_XOR : *pixel_byte ^= pixel_mask; } } static void MCGA_Plot(int x, int y, int color) { /* this routine used for MCGA/VGA 320x200 16-color mode */ unsigned char pixel_mask; volatile unsigned char dummy; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y * 40) + (x >> 3)); /* set up mask */ pixel_mask = (char)(0x80 >> (x & 7)); /* set-up video controller */ OUT_PORT(0x03CE, 8); OUT_PORT(0x03CF, pixel_mask); OUT_PORT(0x03CE, 3); OUT_PORT(0x03CF, (char)(PixelMode << 3)); OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, 0x0F); /* do a dummy read to load latches */ dummy = *pixel_byte; /* clear latches */ *pixel_byte = 0; /* set bit planes */ OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, (char)color); *pixel_byte = 0xFF; /* finish up */ OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, 0x0F); OUT_PORT(0x03CE, 3); OUT_PORT(0x03CF, 0); OUT_PORT(0x03CE, 8); OUT_PORT(0x03CF, 0xFF); } static void M256_Plot(int x, int y, int color) { /* this routine used for MCGA/VGA 320x200x256 mode */ unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y << 8) + (y << 6) + x); /* set pixel */ switch (PixelMode) { case ZG_PXL_SET : *pixel_byte = (unsigned char)color; break; case ZG_PXL_AND : *pixel_byte &= (unsigned char)color; break; case ZG_PXL_OR : *pixel_byte |= (unsigned char)color; break; case ZG_PXL_XOR : *pixel_byte ^= (unsigned char)color; } } static void EVGA_Plot(int x, int y, int color) { /* this routine used for all EGA/VGA modes expect 256-color modes */ unsigned char pixel_mask; volatile unsigned char dummy; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y * 80) + (x >> 3)); /* set up mask */ pixel_mask = (char)(0x80 >> (x & 7)); /* set-up video controller */ OUT_PORT(0x03CE, 8); OUT_PORT(0x03CF, pixel_mask); OUT_PORT(0x03CE, 3); OUT_PORT(0x03CF, (char)(PixelMode << 3)); OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, 0x0F); /* do a dummy read to load latches */ dummy = *pixel_byte; /* clear latches */ *pixel_byte = 0; /* set bit planes */ OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, (char)color); *pixel_byte = 0xFF; /* finish up */ OUT_PORT(0x03C4, 2); OUT_PORT(0x03C5, 0x0F); OUT_PORT(0x03CE, 3); OUT_PORT(0x03CF, 0); OUT_PORT(0x03CE, 8); OUT_PORT(0x03CF, 0xFF); } /*--------------------------------------------- CGA, EGA, MCGA, VGA pixel reading functions ---------------------------------------------*/ static int CGA1_Read(int x, int y) { /* this routine used for CGA 640x200x2 mode */ unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(CGA_VID_SEG,0x2000 * (y & 3) + 80 * (y >> 1) + (x >> 3)); /* calculate bit mask */ pixel_mask = 0x80 >> (x & 7); /* read pixel */ if (pixel_mask & *pixel_byte) return 1; else return 0; } static int CGA2_Read(int x, int y) { /* this routine used for CGA 320x200x4 mode */ unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(CGA_VID_SEG,0x2000 * (y & 1) + 80 * (y >> 1) + (x >> 2)); pixel_mask = 3 << (6 - ((x & 3) << 1)); return (int)((*pixel_byte & pixel_mask) >> (6 - ((x & 3) << 1))); } static int MCGA_Read(int x, int y) { /* this routine used for all EGA/VGA modes expect 256-color modes */ char i; int color = 0; unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y * 40) + (x >> 3)); /* set up mask */ pixel_mask = 0x80 >> (x & 7); /* read the color bits */ for (i = 0; i < 4; ++i) { OUT_PORT(0x3CE, 4); OUT_PORT(0x3CF, i); OUT_PORT(0x3CE, 5); OUT_PORT(0x3CF, 0); if (*pixel_byte & pixel_mask) color |= 1 << i; } return color; } static int M256_Read(int x, int y) { /* this routine used for MCGA/VGA 320x200x256 mode */ unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y << 8) + (y << 6) + x); /* return pixel value */ return *pixel_byte; } static int EVGA_Read(int x, int y) { /* this routine used for all EGA/VGA modes expect 256-color modes */ char i; int color = 0; unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(EVGA_VID_SEG, (y * 80 + (x >> 3))); /* set up mask */ pixel_mask = 0x80 >> (x & 7); /* read the color bits */ for (i = 0; i < 4; ++i) { OUT_PORT(0x3CE, 4); OUT_PORT(0x3CF, i); OUT_PORT(0x3CE, 5); OUT_PORT(0x3CF, 0); if (*pixel_byte & pixel_mask) color |= 1 << i; } return color; } /*--------------- HGC functions ---------------*/ static void HGC_GraphMode(void) { /* Codes to be loaded to Hercules 6845 to set graphics mode */ static const unsigned char HGC_GRAPH_CODES[12] = {0x35,0x2D,0x2E,0x07,0x5B,0x02,0x57,0x57,0x02,0x03,0x00,0x00}; unsigned int i; unsigned char far * screen; OUT_PORT(HGC_CFG_PORT,3); screen = MK_FP(HGC_VID_SEG,0); OUT_PORT(HGC_CTL_PORT,2); /* set control port */ for (i = 0; i < sizeof(HGC_GRAPH_CODES); ++i) { OUT_PORT(HGC_IDX_PORT, (char)i); OUT_PORT(HGC_DAT_PORT, HGC_GRAPH_CODES[i]); } for (i = 0; i <= 32767; ++i) { *screen = '\x00'; ++screen; } OUT_PORT(HGC_CTL_PORT,10); /* set control port */ } static void HGC_TextMode(void) { /* Codes to be loaded to Hercules 6845 to set text mode */ static const unsigned char HGC_TEXT_CODES[12] = {0x61,0x50,0x52,0x0F,0x19,0x06,0x19,0x19,0x02,0x0D,0x0B,0x0C}; unsigned int i; unsigned char far * screen; OUT_PORT(HGC_CFG_PORT,3); screen = MK_FP(HGC_VID_SEG,0); OUT_PORT(HGC_CTL_PORT,0x20); /* set control port */ for (i = 0; i < sizeof(HGC_TEXT_CODES); ++i) { OUT_PORT(HGC_IDX_PORT, (char)i); OUT_PORT(HGC_DAT_PORT, HGC_TEXT_CODES[i]); } for (i = 0; i <= 32767; ++i) { if (i % 2 == 1) *screen = '\x07'; else *screen = '\x20'; ++screen; } OUT_PORT(HGC_CTL_PORT,0x28); /* set control port */ } static void HGC_Plot(int x, int y, int color) { /* this routine used for HGC 720x348x2 mode */ unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(HGC_VID_SEG,0x2000 * (y & 3) + 90 * (y >> 2) + (x >> 3)); /* calculate bit mask */ pixel_mask = 0x80 >> (x & 7); /* set pixel */ switch (PixelMode) { case ZG_PXL_SET : if (color) *pixel_byte |= pixel_mask; else *pixel_byte &= ~pixel_mask; break; case ZG_PXL_AND : if (color) *pixel_byte &= pixel_mask; break; case ZG_PXL_OR : if (!color) *pixel_byte |= pixel_mask; break; case ZG_PXL_XOR : if (!color) *pixel_byte ^= pixel_mask; } } static int HGC_Read(int x, int y) { /* this routine used for HGC 720x348x2 mode */ unsigned int pixel_mask; unsigned char far * pixel_byte; /* find the byte containing our pixel */ pixel_byte = MK_FP(HGC_VID_SEG,0x2000 * (y & 3) + 90 * (y >> 2) + (x >> 3)); /* calculate bit mask */ pixel_mask = 0x80 >> (x & 7); /* read pixel */ if (pixel_mask & *pixel_byte) return 1; else return 0; }