--- /dev/null
+/*****************************************************************************\r
+VGA graphics demo\r
+Chris Giese <geezer@execpc.com> http://my.execpc.com/~geezer\r
+Release date: ?\r
+This code is public domain (no copyright).\r
+You can do whatever you want with it.\r
+\r
+This code uses the BIOS to set graphics mode, and uses the BIOS font.\r
+Should compile cleanly with Turbo C++ 1.0, Turbo C++ 3.0, 16- or 32-bit\r
+Watcom C, or DJGPP. DJGPP version will not work in Windows NT/2000/XP\r
+DOS box.\r
+\r
+Some additional things you could do with this:\r
+- Write a function tblit1(), similar to blit1(), that uses an on-off\r
+ transparency mask. Use this function to blit non-rectangular objects\r
+ such as a mouse cursor.\r
+- Write blit_plane(): a fast function to blit from monochrome to monochrome\r
+ or 4-plane bitmaps. Use an external shift() function, written in asm\r
+- Support VBE 1.x banked framebuffer\r
+- Support VBE 2.x linear framebuffer (pmode only, not at A000h:0000)\r
+- Support greater color depths: 15 bpp, 16 bpp, 24 bpp, 32 bpp\r
+- Color reduction, e.g. Heckbert (median-cut) algorithm\r
+- Clipping engine that lets you draw a window that is partially\r
+ obscured by "closer" windows\r
+- Mouse, keyboard, and timer events\r
+- Widgets: push button, checkbox, radio buttons, listbox, dialog, etc.\r
+*****************************************************************************/\r
+#include <string.h> /* [_f]memset() */\r
+/********************************* TURBO C **********************************/\r
+#if defined(__TURBOC__)\r
+#include <dos.h> /* struct REGPACK, intr() */\r
+\r
+/* The framebuffer is far outside the 16-bit data segment. The only way to\r
+make the framebuffer work like in-memory bitmaps is to use far pointers.\r
+\r
+We still use the SMALL memory model. */\r
+#define FAR far\r
+#define FARPTR(S, O) MK_FP(S, O)\r
+\r
+#define outportw(P,V) outport(P,V)\r
+\r
+#define R_AX r_ax\r
+#define R_BX r_bx\r
+#define R_BP r_bp\r
+#define R_ES r_es\r
+\r
+#define trap(N,R) intr(N,R)\r
+\r
+typedef struct REGPACK regs_t;\r
+\r
+#if __TURBOC__<0x300\r
+void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
+{\r
+ for(; n != 0; n--)\r
+ {\r
+ *s = c;\r
+ s++;\r
+ }\r
+}\r
+#else\r
+void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
+{\r
+ _fmemset(s, c, n);\r
+}\r
+#endif\r
+\r
+/********************************* DJGPP ************************************/\r
+#elif defined(__DJGPP__)\r
+#include <dpmi.h> /* __dpmi_... */\r
+#include <dos.h> /* inportb(), outportb() */\r
+\r
+#define FAR /* nothing */\r
+#define FARPTR(S, O) (unsigned char *)((S) * 16L + (O) + \\r
+ __djgpp_conventional_base)\r
+\r
+/* near pointers; not supported in Windows NT/2k/XP DOS box */\r
+#include <sys/nearptr.h> /* __djgpp_conventional_base, __djgpp_nearptr_enable() */\r
+#include <stdio.h> /* printf() */\r
+#include <crt0.h> /* _CRT0_FLAG_NEARPTR, _crt0_startup_flags */\r
+\r
+#define R_AX x.ax\r
+#define R_BX x.bx\r
+#define R_BP x.bp\r
+#define R_ES x.es\r
+\r
+#define trap(N,R) __dpmi_int(N,R)\r
+\r
+typedef __dpmi_regs regs_t;\r
+\r
+void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
+{\r
+ memset(s, c, n);\r
+}\r
+\r
+/******************************** WATCOM C **********************************/\r
+#elif defined(__WATCOMC__)\r
+#include <dos.h> /* union REGPACK, MK_FP(), intr() */\r
+\r
+#if defined(__386__)\r
+#define FAR /* nothing */\r
+#define FARPTR(S, O) (unsigned char *)((S) * 16L + (O))\r
+\r
+void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
+{\r
+ memset(s, c, n);\r
+}\r
+\r
+#else\r
+#define FAR far\r
+#define FARPTR(S, O) MK_FP(S, O)\r
+\r
+void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
+{\r
+ _fmemset(s, c, n);\r
+}\r
+#endif\r
+\r
+#define inportb(P) inp(P)\r
+#define outportb(P,V) outp(P,V)\r
+#define outportw(P,V) outpw(P,V)\r
+\r
+#define R_AX w.ax\r
+#define R_BX w.bx\r
+#define R_BP w.bp\r
+#define R_ES w.es\r
+\r
+/* WARNING: for 32-bit code, unused fields of regs_t\r
+must be zeroed before using this macro */\r
+#define trap(N,R) intr(N,R)\r
+\r
+typedef union REGPACK regs_t;\r
+\r
+#else\r
+#error Not Turbo C, not DJGPP, not Watcom C. Sorry.\r
+#endif\r
+\r
+#include <conio.h> /* getch() */\r
+\r
+/* need direct access to some VGA registers to select plane,\r
+enable Mode X, and fix screwy CGA addressing */\r
+#define VGA_SEQ_INDEX 0x3C4\r
+#define VGA_SEQ_DATA 0x3C5\r
+#define VGA_GC_INDEX 0x3CE\r
+#define VGA_GC_DATA 0x3CF\r
+#define VGA_CRTC_INDEX 0x3D4\r
+#define VGA_CRTC_DATA 0x3D5\r
+\r
+/* bitmap "class" */\r
+typedef struct\r
+{\r
+ unsigned wd, ht;\r
+ unsigned char FAR *raster;\r
+ unsigned fore_color, back_color;\r
+/* "member functions" */\r
+ const struct _driver *ops;\r
+} bmp_t;\r
+\r
+typedef struct _driver\r
+{\r
+/* "pure virtual functions": color drivers MUST implement these */\r
+ void (*write_pixel)(bmp_t *bmp, unsigned x, unsigned y, unsigned c);\r
+ unsigned (*read_pixel)(bmp_t *bmp, unsigned x, unsigned y);\r
+/* "virtual functions": drivers MAY implement these, for speed\r
+fill rectangular area with solid color */\r
+ void (*fill_rect)(bmp_t *bmp, int x, int y, int wd, int ht);\r
+/* copy monochrome bitmap to this bitmap (used to display text) */\r
+ void (*blit1)(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y);\r
+/* copy all or part of one bitmap to another (both of the same depth) */\r
+ void (*blit)(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y);\r
+} ops_t;\r
+/*============================================================================\r
+helper functions\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void set_plane(unsigned p)\r
+{\r
+ static unsigned curr_p = -1u;\r
+/**/\r
+ unsigned char pmask;\r
+\r
+ p &= 3;\r
+ if(p == curr_p)\r
+ return;\r
+ curr_p = p;\r
+ pmask = 1 << p;\r
+#if 0\r
+ outportb(VGA_GC_INDEX, 4);\r
+ outportb(VGA_GC_DATA, p);\r
+ outportb(VGA_SEQ_INDEX, 2);\r
+ outportb(VGA_SEQ_DATA, pmask);\r
+#else\r
+/* this is a little faster... */\r
+ outportw(VGA_GC_INDEX, (p << 8) | 4);\r
+ outportw(VGA_SEQ_INDEX, (pmask << 8) | 2);\r
+#endif\r
+}\r
+/*****************************************************************************\r
+fast planar (monochrome or 16-color) rectangle fill\r
+*****************************************************************************/\r
+void fill_plane(bmp_t *bmp, int x, int y, int wd, int ht, unsigned c)\r
+{\r
+ unsigned w, wd_in_bytes, off;\r
+ unsigned char lmask, rmask;\r
+ int x2, y2;\r
+\r
+ x2 = x + wd - 1;\r
+ w = (x2 >> 3) - (x >> 3) + 1;\r
+ lmask = 0x00FF >> (x & 7); /* FF 7F 3F 1F 0F 07 03 01 */\r
+ rmask = 0xFF80 >> (x2 & 7);/* 80 C0 E0 F0 F8 FC FE FF */\r
+ if(w == 1)\r
+ lmask &= rmask;\r
+ wd_in_bytes = bmp->wd / 8;\r
+ off = wd_in_bytes * y + x / 8;\r
+ if(c)\r
+/* for each row... */\r
+ for(y2 = y; y2 < y + ht; y2++)\r
+ {\r
+/* do partial byte on left */\r
+ bmp->raster[off] |= lmask;\r
+/* do solid bytes in middle */\r
+ if(w > 2)\r
+ vmemset(bmp->raster + off + 1, 0xFF, w - 2);\r
+/* do partial byte on right */\r
+ if(w > 1)\r
+ bmp->raster[off + w - 1] |= rmask;\r
+/* next row */\r
+ off += wd_in_bytes;\r
+ }\r
+ else\r
+ {\r
+ lmask = ~lmask;\r
+ rmask = ~rmask;\r
+ for(y2 = y; y2 < y + ht; y2++)\r
+ {\r
+ bmp->raster[off] &= lmask;\r
+ if(w > 2)\r
+ vmemset(bmp->raster + off + 1, 0, w - 2);\r
+ if(w > 1)\r
+ bmp->raster[off + w - 1] &= rmask;\r
+ off += wd_in_bytes;\r
+ }\r
+ }\r
+}\r
+/*****************************************************************************\r
+fast planar blit\r
+*****************************************************************************/\r
+void blit_plane(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
+{\r
+/* left as an exercise for the reader :)\r
+\r
+You may need an external, assembly-language function to shift (left or\r
+right) a long string of bytes. No need to shift by more than 7 bits. */\r
+}\r
+/*============================================================================\r
+driver for monochrome (1-bit) graphics\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void write_pixel1(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ unsigned wd_in_bytes;\r
+ unsigned off, mask;\r
+\r
+ c = (c & 1) * 0xFF;\r
+ wd_in_bytes = bmp->wd / 8;\r
+ off = wd_in_bytes * y + x / 8;\r
+ x = (x & 7) * 1;\r
+ mask = 0x80 >> x;\r
+ bmp->raster[off] = (bmp->raster[off] & ~mask) | (c & mask);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static unsigned read_pixel1(bmp_t *bmp, unsigned x, unsigned y)\r
+{\r
+ unsigned wd_in_bytes;\r
+ unsigned off, mask;\r
+\r
+ wd_in_bytes = bmp->wd / 8;\r
+ off = wd_in_bytes * y + x / 8;\r
+ x = (x & 7) * 1;\r
+ mask = 0x80 >> x;\r
+ return (bmp->raster[off] & mask) != 0;\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void fill_rect1(bmp_t *bmp, int x, int y, int wd, int ht)\r
+{\r
+ fill_plane(bmp, x, y, wd, ht, bmp->fore_color & 1);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+const ops_t g_ops1 =\r
+{\r
+ write_pixel1,\r
+ read_pixel1,\r
+ fill_rect1,\r
+ NULL, /* blit1 */\r
+ NULL /* blit */\r
+};\r
+/*============================================================================\r
+driver for 2-bit packed pixel (4-color CGA) graphics\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void write_pixel2(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ unsigned wd_in_bytes, off, mask;\r
+\r
+ c = (c & 3) * 0x55;\r
+ wd_in_bytes = bmp->wd / 4;\r
+ off = wd_in_bytes * y + x / 4;\r
+ x = (x & 3) * 2;\r
+ mask = 0xC0 >> x;\r
+ bmp->raster[off] = (bmp->raster[off] & ~mask) | (c & mask);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+const ops_t g_ops2 =\r
+{\r
+ write_pixel2,\r
+ NULL, /* read_pixel */\r
+ NULL, /* fill_rect */\r
+ NULL, /* blit1 */\r
+ NULL /* blit */\r
+};\r
+/*============================================================================\r
+driver for 4-plane 16-color graphics\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void write_pixel4p(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ unsigned wd_in_bytes, off, mask, p, pmask;\r
+\r
+ wd_in_bytes = bmp->wd / 8;\r
+ off = wd_in_bytes * y + x / 8;\r
+ x = (x & 7) * 1;\r
+ mask = 0x80 >> x;\r
+ pmask = 1;\r
+ for(p = 0; p < 4; p++)\r
+ {\r
+ set_plane(p);\r
+ if(pmask & c)\r
+ bmp->raster[off] |= mask;\r
+ else\r
+ bmp->raster[off] &= ~mask;\r
+ pmask <<= 1;\r
+ }\r
+}\r
+/*****************************************************************************\r
+pixel-by-pixel fill is too slow, so use this optimized function:\r
+*****************************************************************************/\r
+static void fill_rect4p(bmp_t *bmp, int x, int y, int wd, int ht)\r
+{\r
+ unsigned char p, pmask;\r
+\r
+ pmask = 1;\r
+ for(p = 0; p < 4; p++)\r
+ {\r
+ set_plane(p);\r
+ fill_plane(bmp, x, y, wd, ht, bmp->fore_color & pmask);\r
+ pmask <<= 1;\r
+ }\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+const ops_t g_ops4p =\r
+{\r
+ write_pixel4p,\r
+ NULL, /* read_pixel */\r
+ fill_rect4p,\r
+ NULL, /* blit1 */\r
+ NULL /* blit */\r
+};\r
+/*============================================================================\r
+driver for 8-bit 256-color graphics\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void write_pixel8(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ unsigned wd_in_bytes;\r
+ unsigned off;\r
+\r
+ wd_in_bytes = bmp->wd;\r
+ off = wd_in_bytes * y + x;\r
+ bmp->raster[off] = c;\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void fill_rect8(bmp_t *bmp, int x, int y, int wd, int ht)\r
+{\r
+ unsigned wd_in_bytes, off, y2;\r
+\r
+ wd_in_bytes = bmp->wd;\r
+ off = wd_in_bytes * y + x;\r
+ for(y2 = y; y2 < y + ht; y2++)\r
+ {\r
+ vmemset(bmp->raster + off, bmp->fore_color, wd);\r
+ off += wd_in_bytes;\r
+ }\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+const ops_t g_ops8 =\r
+{\r
+ write_pixel8,\r
+ NULL, /* read_pixel */\r
+ fill_rect8,\r
+ NULL, /* blit1 */\r
+ NULL /* blit */\r
+};\r
+/*============================================================================\r
+driver for 8-bit 256-color Mode-X graphics\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void write_pixel8x(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ unsigned wd_in_bytes;\r
+ unsigned off;\r
+\r
+ wd_in_bytes = bmp->wd / 4;\r
+ off = wd_in_bytes * y + x / 4;\r
+ set_plane(x & 3);\r
+ bmp->raster[off] = c;\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+const ops_t g_ops8x =\r
+{\r
+ write_pixel8x,\r
+ NULL, /* read_pixel */\r
+ NULL, /* fill_rect */\r
+ NULL, /* blit1 */\r
+ NULL /* blit */\r
+};\r
+/*============================================================================\r
+depth-independent routines, which call the depth-dependent routines\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+unsigned read_pixel(bmp_t *bmp, unsigned x, unsigned y)\r
+{\r
+ if(x >= bmp->wd || y >= bmp->ht)\r
+ return 0;\r
+ if(bmp->ops->read_pixel == NULL)\r
+ return 0; /* uh-oh */\r
+ return bmp->ops->read_pixel(bmp, x, y);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void write_pixel(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
+{\r
+ if(x >= bmp->wd || y >= bmp->ht)\r
+ return;\r
+ if(bmp->ops->write_pixel == NULL)\r
+ return; /* uh-oh */\r
+ bmp->ops->write_pixel(bmp, x, y, c);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void fill_rect(bmp_t *bmp, int x, int y, int wd, int ht)\r
+{\r
+ int x2, y2;\r
+\r
+/* clip */\r
+ if(x < 0)\r
+ {\r
+ if(wd + x < 0)\r
+ return;\r
+ wd += x;\r
+ x = 0;\r
+ }\r
+ if(x + wd >= (int)bmp->wd)\r
+ {\r
+ if(x >= (int)bmp->wd)\r
+ return;\r
+ wd = bmp->wd - x;\r
+ }\r
+ if(y < 0)\r
+ {\r
+ if(ht + y < 0)\r
+ return;\r
+ ht += y;\r
+ y = 0;\r
+ }\r
+ if(y + ht >= (int)bmp->ht)\r
+ {\r
+ if(y >= (int)bmp->ht)\r
+ return;\r
+ ht = bmp->ht - y;\r
+ }\r
+/* use fast routine if available */\r
+ if(bmp->ops->fill_rect != NULL)\r
+ {\r
+ bmp->ops->fill_rect(bmp, x, y, wd, ht);\r
+ return;\r
+ }\r
+ for(y2 = y; y2 < y + ht; y2++)\r
+ for(x2 = x; x2 < x + wd; x2++)\r
+ write_pixel(bmp, x2, y2, bmp->fore_color);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void hline(bmp_t *bmp, int x, int y, unsigned wd)\r
+{\r
+ fill_rect(bmp, x, y, wd, 1);\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void vline(bmp_t *bmp, int x, int y, unsigned ht)\r
+{\r
+ fill_rect(bmp, x, y, 1, ht);\r
+}\r
+/*****************************************************************************\r
+blit1 = blit from monochrome bitmap to bitmap of any color depth\r
+*****************************************************************************/\r
+void blit1(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
+{\r
+ unsigned x, y, c;\r
+\r
+/* source bitmap _must_ be monochrome */\r
+ if(src->ops != &g_ops1)\r
+ return;\r
+/* use fast routine if available */\r
+ if(src->ops->blit1 != NULL)\r
+ {\r
+ src->ops->blit1(src, dst, dst_x, dst_y);\r
+ return;\r
+ }\r
+ for(y = 0; y < src->ht; y++)\r
+ for(x = 0; x < src->wd; x++)\r
+ {\r
+ c = read_pixel(src, x, y);\r
+/* xxx - on-off transparency?\r
+ if(c == 0)\r
+ continue; */\r
+ if(c != 0)\r
+ c = dst->fore_color;\r
+ else\r
+ c = dst->back_color;\r
+ write_pixel(dst, dst_x + x, dst_y + y, c);\r
+ }\r
+}\r
+/*****************************************************************************\r
+blit = copy from one bitmap to another, both of the same color depth\r
+*****************************************************************************/\r
+void blit(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
+{\r
+ unsigned x, y, c;\r
+\r
+/* they must be the same depth */\r
+ if(src->ops != dst->ops)\r
+ return;\r
+/* use fast routine if available */\r
+ if(src->ops->blit != NULL)\r
+ {\r
+ src->ops->blit(src, dst, dst_x, dst_y);\r
+ return;\r
+ }\r
+ for(y = 0; y < src->ht; y++)\r
+ for(x = 0; x < src->wd; x++)\r
+ {\r
+ c = read_pixel(src, x, y);\r
+ write_pixel(dst, dst_x + x, dst_y + y, c);\r
+ }\r
+}\r
+/*****************************************************************************\r
+find 8x8 font in VGA BIOS ROM\r
+*****************************************************************************/\r
+unsigned char FAR *bios_8x8_font(void)\r
+{\r
+ unsigned char FAR *font;\r
+ regs_t regs;\r
+\r
+/* use BIOS INT 10h AX=1130h to find font #3 (8x8) in ROM */\r
+ memset(®s, 0, sizeof(regs)); /* for Watcom C */\r
+ regs.R_AX = 0x1130;\r
+ regs.R_BX = 0x0300;\r
+ trap(0x10, ®s);\r
+/* CauseWay DOS extender seems to return a selector in ES,\r
+instead of real-mode segment value (usu. 0xC000) */\r
+#if defined(__WATCOMC__)&&defined(__386__)\r
+ font = FARPTR(0xC000, regs.R_BP);\r
+#else\r
+ font = FARPTR(regs.R_ES, regs.R_BP);\r
+#endif\r
+ return font;\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+void bputs(bmp_t *bmp, unsigned x, unsigned y, const char *s)\r
+{\r
+ unsigned char FAR *font;\r
+ bmp_t src;\r
+\r
+ font = bios_8x8_font();\r
+ src.wd = 8;\r
+ src.ht = 8;\r
+ src.ops = &g_ops1;\r
+ for(; *s != '\0'; s++)\r
+ {\r
+ src.raster = font + 8 * (*s);\r
+ blit1(&src, bmp, x, y);\r
+ x += 8;\r
+ }\r
+}\r
+/*============================================================================\r
+DEMO\r
+============================================================================*/\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void border3d(bmp_t *bmp, int x, int y, unsigned wd, unsigned ht,\r
+ char down)\r
+{\r
+ if(down)\r
+ {\r
+ bmp->fore_color = 8;\r
+ hline(bmp, x + 0, y + 0, wd - 1);\r
+ vline(bmp, x + 0, y + 0, ht - 1);\r
+ bmp->fore_color = 0;\r
+ hline(bmp, x + 1, y + 1, wd - 3);\r
+ vline(bmp, x + 1, y + 1, ht - 3);\r
+ bmp->fore_color = 7;\r
+ hline(bmp, x + 1, y + ht - 2, wd - 2);\r
+ vline(bmp, x + wd - 2, y + 1, ht - 2);\r
+ bmp->fore_color = 15;\r
+ hline(bmp, x + 0, y + ht - 1, wd);\r
+ vline(bmp, x + wd - 1, y + 0, ht);\r
+ }\r
+ else\r
+ {\r
+ bmp->fore_color = 7;\r
+ hline(bmp, x + 0, y + 0, wd - 1);\r
+ vline(bmp, x + 0, y + 0, ht - 1);\r
+ bmp->fore_color = 15;\r
+ hline(bmp, x + 1, y + 1, wd - 3);\r
+ vline(bmp, x + 1, y + 1, ht - 3);\r
+ bmp->fore_color = 8;\r
+ hline(bmp, x + 1, y + ht - 2, wd - 2);\r
+ vline(bmp, x + wd - 2, y + 1, ht - 2);\r
+ bmp->fore_color = 0;\r
+ hline(bmp, x + 0, y + ht - 1, wd);\r
+ vline(bmp, x + wd - 1, y + 0, ht);\r
+ }\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+static void demo(bmp_t *bmp, const char *title)\r
+{\r
+ unsigned x = 10, y = 10, wd = 180, ht = 50;\r
+\r
+/* erase screen to blue */\r
+ bmp->fore_color = 1;\r
+ fill_rect(bmp, 0, 0, bmp->wd, bmp->ht);\r
+/* draw gray window with 3D border */\r
+ bmp->fore_color = 7;\r
+ fill_rect(bmp, x, y, wd, ht);\r
+ border3d(bmp, x, y, wd, ht, 0);\r
+/* draw white-on-green title bar */\r
+ bmp->fore_color = 2;\r
+ fill_rect(bmp, x + 2, y + 2, wd - 4, 10);\r
+ bmp->back_color = 2;\r
+ bmp->fore_color = 15;\r
+ bputs(bmp, x + 3, y + 3, title);\r
+/* draw menu bar on existing gray background */\r
+ bmp->back_color = 7;\r
+ bmp->fore_color = 0;\r
+ bputs(bmp, x + 3, y + 13, "File Edit");\r
+/* draw white inner area with 3D border */\r
+ bmp->fore_color = 15;\r
+ fill_rect(bmp, x + 3, y + 21, wd - 6, ht - 24);\r
+ border3d(bmp, x + 3, y + 21, wd - 6, ht - 24, 1);\r
+/* await key pressed */\r
+ getch();\r
+}\r
+/*****************************************************************************\r
+*****************************************************************************/\r
+int main(void)\r
+{\r
+ static const unsigned wd[] =\r
+ {\r
+ 640, 320, 640, 320, 320\r
+ };\r
+ static const unsigned ht[] =\r
+ {\r
+ 480, 200, 480, 200, 200\r
+ };\r
+ static const ops_t *ops[] =\r
+ {\r
+ &g_ops1, &g_ops2, &g_ops4p, &g_ops8, &g_ops8x\r
+ };\r
+ static const unsigned mode[] =\r
+ {\r
+ 0x11, 5, 0x12, 0x13, 0x13\r
+ };\r
+ static const char *title[] =\r
+ {\r
+ "640x480x2", "320x200x4", "640x480x16", "320x200x256",\r
+ "320x200x256 ModeX"\r
+ };\r
+/**/\r
+ regs_t regs;\r
+ unsigned i;\r
+ bmp_t bmp;\r
+\r
+#if defined(__DJGPP__)\r
+ if(!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))\r
+ {\r
+ if(!__djgpp_nearptr_enable())\r
+ {\r
+ printf("Could not enable nearptr access "\r
+ "(Windows NT/2000/XP?)\n");\r
+ }\r
+ }\r
+#endif\r
+ for(i = 0; i < sizeof(wd) / sizeof(wd[0]); i++)\r
+ {\r
+ bmp.raster = FARPTR(0xA000, 0);\r
+ bmp.wd = wd[i];\r
+ bmp.ht = ht[i];\r
+ bmp.ops = ops[i];\r
+\r
+ memset(®s, 0, sizeof(regs)); /* for Watcom C */\r
+ regs.R_AX = mode[i];\r
+ trap(0x10, ®s);\r
+/* to make CGA graphics work like other graphics modes... */\r
+ if(mode[i] == 0x05)\r
+ {\r
+/* 1) turn off screwy CGA addressing */\r
+ outportb(VGA_CRTC_INDEX, 0x17);\r
+ outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) | 1);\r
+/* 2) turn off doublescan */\r
+ outportb(VGA_CRTC_INDEX, 9);\r
+ outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x80);\r
+/* 3) move the framebuffer from B800:0000 to A000:0000 */\r
+ outportb(VGA_GC_INDEX, 6);\r
+ outportb(VGA_GC_DATA, inportb(VGA_GC_INDEX) & ~0x0C);\r
+ }\r
+/* to convert mode 13h to Mode X... */\r
+ else if(i == 4)\r
+ {\r
+/* 1) turn off Chain-4 addressing */\r
+ outportb(VGA_SEQ_INDEX, 0x04);\r
+ outportb(VGA_SEQ_DATA, inportb(VGA_SEQ_DATA) & ~0x08);\r
+/* 2) turn off doubleword clocking */\r
+ outportb(VGA_CRTC_INDEX, 0x14);\r
+ outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x40);\r
+/* 3) turn off word clocking in case it's on */\r
+ outportb(VGA_CRTC_INDEX, 0x17);\r
+ outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) | 0x40);\r
+ }\r
+ demo(&bmp, title[i]);\r
+ }\r
+/* return to text mode */\r
+ memset(®s, 0, sizeof(regs)); /* for Watcom C */\r
+ regs.R_AX = 0x03;\r
+ trap(0x10, ®s);\r
+ return 0;\r
+}\r