--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_COMM.C - PCX_LIB Library Common Functions\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/03 - fixed "segread" call.\r
+ * 91/04/07 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PORTABILITY NOTES\r
+ *\r
+ * 1. While this program is written in ANSI C, it uses a number of \r
+ * function calls that are specific to the Microsoft C V6.0 library.\r
+ * These are documented as follows for the purposes of porting this\r
+ * program to other compilers and/or processors: \r
+ *\r
+ * int86x - execute 80x86 interrupt routine (far data)\r
+ * segread - get current 80x86 segment register values\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <dos.h>\r
+#include "pcx_int.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\f\r
+/* GLOBALS */\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_OPEN - Open PCX Workblock\r
+ *\r
+ * Purpose: To allocate and initialize a PCX image file workblock.\r
+ *\r
+ * Setup: PCX_WORKBLK *pcx_open\r
+ * (\r
+ * char *fname,\r
+ * BOOL wrt_flag\r
+ * )\r
+ *\r
+ * Where: fname is a PCX image file name.\r
+ * wrt_flag is a Boolean flag which if TRUE indicates that\r
+ * the PCX image file is to be opened for writing;\r
+ * otherwise it is opened for reading.\r
+ *\r
+ * Return: A pointer to a PCX image file workblock if successful;\r
+ * otherwise NULL.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+PCX_WORKBLK *pcx_open\r
+(\r
+ char *fname,\r
+ BOOL wrt_flag\r
+)\r
+{\r
+ PCX_WORKBLK *wbp; /* PCX image file workblock pointer */\r
+\r
+ /* Allocate a workblock */\r
+\r
+ if ((wbp = (PCX_WORKBLK *) malloc(sizeof(PCX_WORKBLK))) == NULL)\r
+ return (NULL);\r
+\r
+ /* Open the PCX image file in binary mode */\r
+\r
+ if (wrt_flag == FALSE)\r
+ wbp->fp = fopen(fname, "rb"); /* Open for reading */\r
+ else\r
+ wbp->fp = fopen(fname, "wb"); /* Open for writing */\r
+\r
+ if (wbp->fp == NULL) /* Check for successful file opening */\r
+ {\r
+ free(wbp); /* Free the workblock memory */\r
+ return (NULL);\r
+ }\r
+\r
+ return (wbp); /* Return the workblock pointer */\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_CLOSE - Close PCX Workblock\r
+ *\r
+ * Purpose: To close a PCX image file and release its workblock\r
+ * memory.\r
+ *\r
+ * Setup: BOOL pcx_close\r
+ * (\r
+ * PCX_WORKBLK *wbp\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+BOOL pcx_close\r
+(\r
+ PCX_WORKBLK *wbp\r
+)\r
+{\r
+ free(wbp->palettep); /* Free the extended palette (if it exists) */\r
+\r
+ free(wbp); /* Free the PCX image file workblock */\r
+\r
+ if (fclose(wbp->fp) == EOF) /* Close the PCX image file */\r
+ return (FALSE);\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_ISVGA - Check For VGA Display Adapter\r
+ *\r
+ * Purpose: To determine whether a display adapter supports VGA BIOS\r
+ * service routines.\r
+ *\r
+ * Setup: BOOL pcx_isvga(void)\r
+ *\r
+ * Return: TRUE if display adapter is VGA-compatible; otherwise\r
+ * FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+BOOL pcx_isvga(void)\r
+{\r
+ unsigned char *vinfop; /* VGA information buffer pointer */\r
+ union REGS regs; /* 80x86 register values */\r
+ struct SREGS sregs; /* 80x86 segment register values */\r
+\r
+ /* Allocate a VGA functionality/state information buffer */\r
+\r
+ if ((vinfop = (unsigned char *) malloc(sizeof(unsigned char) * 64)) ==\r
+ NULL)\r
+ return (FALSE);\r
+\r
+ /* Attempt to read the VGA information */\r
+\r
+ regs.h.ah = 0x1b; /* Select "Return VGA Info" BIOS routine */\r
+ regs.x.bx = 0; /* Implementation type */\r
+\r
+ /* Get the VGA information buffer offset value */\r
+\r
+ regs.x.di = (unsigned int) vinfop;\r
+\r
+ segread(&sregs); /* Get the current DS segment register value */\r
+\r
+ sregs.es = sregs.ds;\r
+\r
+ int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */\r
+\r
+ free(vinfop); /* Free the VGA information buffer */\r
+\r
+ /* The value 0x1b is returned in register AL only if a VGA display */\r
+ /* adapter is present */\r
+\r
+ if (regs.h.al == 0x1b)\r
+ return (TRUE);\r
+ else\r
+ return (FALSE);\r
+}\r
+\r
--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_DISP.C - PCX_LIB Library Image Display Functions\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/03 - fixed "segread" call.\r
+ * 91/04/07 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PORTABILITY NOTES\r
+ *\r
+ * 1. While this program is written in ANSI C, it uses a number of \r
+ * function calls that are specific to the Microsoft C V6.0 library.\r
+ * These are documented as follows for the purposes of porting this\r
+ * program to other compilers and/or processors: \r
+ *\r
+ * _fmemcpy - "memcpy" for small model / far data\r
+ * int86 - execute 80x86 interrupt routine\r
+ * int86x - execute 80x86 interrupt routine (far\r
+ * data)\r
+ * _remapallpalette - remap entire video display color palette\r
+ * _selectpalette - select CGA color palette\r
+ * outpw - output word to 80x86 I/O port\r
+ * segread - get current 80x86 segment register\r
+ * values\r
+ *\r
+ * 2. When porting this program to other processors, remember that words\r
+ * are stored by 80x86-based machines in the big-endian format. That\r
+ * is, the eight least significant bits (lower byte) are stored\r
+ * first, followed by the eight most significant bits (upper byte).\r
+ * If PCX-format files are transferred to little-endian machines\r
+ * (such as those based on 680x0 and Z8000 processors), the order of\r
+ * bytes within each word will have to be reversed before they can \r
+ * be interpreted. (This applies to the file header only, since the\r
+ * encoded image data and optional 256-color palette are stored as\r
+ * bytes.)\r
+ *\r
+ * 3. MS-DOS does not recognize the 720 x 348 graphics mode of the\r
+ * Hercules monochrome display adapter. Therefore, the constant\r
+ * PCX_HERC should never be passed as a video mode parameter to any\r
+ * BIOS service routine.\r
+ *\r
+ * The Microsoft C compiler includes a "video mode" parameter\r
+ * definition (_HERCMONO) that is defined as 0x08. This is a\r
+ * reserved MS-DOS video mode that is apparently used internally by\r
+ * the ROM BIOS. It can, however, be passed to the Microsoft C\r
+ * library function "_setvideomode" to force the Hercules display\r
+ * adapter into graphics mode.\r
+ *\r
+ * Most other MS-DOS C compilers offer similar library functions to\r
+ * force the Hercules monochrome display adapter into its 720 x 348\r
+ * graphics mode.\r
+ *\r
+ ************************************************************************* \r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <conio.h>\r
+#include <dos.h>\r
+#include <malloc.h>\r
+#include <graph.h>\r
+#include "pcx_int.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\r
+static BOOL pcx_read_init(PCX_WORKBLK *, int, int);\r
+static BOOL pcx_read_extpal(PCX_WORKBLK *);\r
+static BOOL pcx_read_header(PCX_WORKBLK *);\r
+static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int);\r
+static BOOL pcx_set_palette(PCX_PAL *, int);\r
+\r
+static void pcx_cga_palette(PCX_PAL *, int);\r
+static void pcx_put_cga(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_put_ega(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_put_herc(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int);\r
+\f\r
+/* GLOBALS */\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_READ - Read PCX Image File\r
+ *\r
+ * Purpose: To read and display a PCX-format image file.\r
+ *\r
+ * Setup: BOOL pcx_read\r
+ * (\r
+ * char *fname,\r
+ * int vmode,\r
+ * int page\r
+ * )\r
+ *\r
+ * Where: fname is a PCX image file name.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * PCX_HERC - 720 x 348 Hercules monochrome\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * page is the video display page number. Valid values are:\r
+ *\r
+ * Mode PCX_HERC - 0 or 1\r
+ * Mode 0x0d - 0 to 7\r
+ * Mode 0x0e - 0 to 3\r
+ * Mode 0x0f - 0 or 1\r
+ * Mode 0x10 - 0 or 1\r
+ * All Other - 0\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Note: The video display adapter must be in the appropriate mode\r
+ * and active page for the image to be displayed.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+BOOL pcx_read\r
+(\r
+ char *fname,\r
+ int vmode,\r
+ int page\r
+)\r
+{\r
+ int bpline; /* Number of bytes per scan line */\r
+ int line_num; /* Scan line number */\r
+ int max_lines; /* Maximum number of scan lines */\r
+ unsigned char *linep; /* PCX scan line buffer pointer */\r
+ BOOL status = TRUE; /* Return status */\r
+ PCX_WORKBLK *wbp; /* PCX image file workblock pointer */\r
+\r
+ /* Open a PCX image file workblock */\r
+\r
+ if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL)\r
+ return (FALSE);\r
+\r
+ /* Initialize the workblock for reading */\r
+\r
+ if (pcx_read_init(wbp, vmode, page) == FALSE)\r
+ {\r
+ (void) pcx_close(wbp); /* Close the PCX workblock */\r
+ return (FALSE);\r
+ }\r
+\r
+ /* Calculate the image height */\r
+\r
+ max_lines = wbp->header.yul + wbp->header.ylr + 1;\r
+\r
+ /* Calculate number of bytes per line (for all color planes) */\r
+\r
+ bpline = wbp->header.bppscan * wbp->header.nplanes;\r
+\r
+ /* Allocate the PCX scan line buffer */\r
+\r
+ if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *)\r
+ NULL)\r
+ {\r
+ /* Set the file pointer to the beginning of the encoded image data */\r
+\r
+ if (status == TRUE)\r
+ if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0)\r
+ status = FALSE;\r
+\r
+ /* Set the video display adapter color palette unless the PCX file */\r
+ /* is Version 3.0 (i.e. - PC Paintbrush Version 2.8 w/o palette) */\r
+\r
+ if (status == TRUE)\r
+ if (wbp->header.version != 3)\r
+ if (pcx_set_palette(wbp->palettep, vmode) == FALSE)\r
+ status = FALSE;\r
+\r
+ /* Read the image line by line */\r
+\r
+ if (status == TRUE)\r
+ {\r
+ for (line_num = 0; line_num < max_lines; line_num++)\r
+ {\r
+ /* Read the current scan line */\r
+\r
+ if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE)\r
+ {\r
+ status = FALSE;\r
+ break;\r
+ }\r
+\r
+ /* Display the current scan line */\r
+\r
+ wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);\r
+ }\r
+ }\r
+\r
+ free(linep); /* Free the PCX scan line buffer */\r
+ }\r
+ else\r
+ status = FALSE;\r
+ \r
+ if (pcx_close(wbp) == FALSE) /* Close the PCX workblock */\r
+ status = FALSE;\r
+\r
+ return (status);\r
+}\r
+\f\r
+/* PRIVATE FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_READ_INIT - Initialize PCX Workblock For Reading\r
+ *\r
+ * Purpose: To initialize a PCX image file workblock for reading.\r
+ *\r
+ * Setup: static BOOL pcx_read_init\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * int vmode,\r
+ * int page\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * PCX_HERC - 720 x 348 Hercules monochrome\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * page is the video display page number. Valid values are:\r
+ *\r
+ * Mode PCX_HERC - 0 or 1\r
+ * Mode 0x0d - 0 to 7\r
+ * Mode 0x0e - 0 to 3\r
+ * Mode 0x0f - 0 or 1\r
+ * Mode 0x10 - 0 or 1\r
+ * All Other - 0\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_read_init\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ int vmode,\r
+ int page\r
+)\r
+{\r
+ int width; /* Display width */\r
+ int leftover; /* Number of unseen bits */\r
+ BOOL status = TRUE; /* Return status */\r
+\r
+ /* Read the file header */\r
+\r
+ if ((pcx_read_header(wbp)) == FALSE)\r
+ return (FALSE);\r
+\r
+ /* Initialize the workblock color palette pointer */\r
+\r
+ wbp->palettep = wbp->header.palette;\r
+ wbp->epal_flag = FALSE;\r
+\r
+ /* Read the extended palette (if any) */\r
+\r
+ if (vmode == 0x13 && wbp->header.version == 5)\r
+ if (pcx_read_extpal(wbp) == FALSE)\r
+ return (FALSE);\r
+\r
+ /* Initialize the display page address offset */\r
+\r
+ wbp->page_offset = (unsigned long) 0L;\r
+\r
+ switch (vmode) /* Select PCX line display function */\r
+ {\r
+ case PCX_HERC: /* 720 x 348 Hercules monochrome */\r
+\r
+ /* Hercules monochrome display adapter supports 2 pages */\r
+\r
+ wbp->page_offset = 0x08000000L * (unsigned long) page;\r
+\r
+ /* Calculate display width in pixels */\r
+\r
+ width = min((wbp->header.xlr - wbp->header.xul + 1), 720);\r
+\r
+ /* Calculate number of bytes to display */\r
+\r
+ wbp->num_bytes = (width + 7) >> 3;\r
+\r
+ /* Calculate mask for leftover bits */\r
+\r
+ if ((leftover = width & 7) != 0)\r
+ wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
+ else\r
+ wbp->mask = 0xff;\r
+\r
+ wbp->pcx_funcp = pcx_put_herc; /* Set the display function ptr */\r
+\r
+ break;\r
+\r
+ case 0x04: /* 320 x 200 4-color CGA */\r
+ case 0x05: /* 320 x 200 4-color CGA (color burst off) */\r
+ \r
+ /* Calculate display width in pixels */\r
+\r
+ width = min((wbp->header.xlr - wbp->header.xul + 1), 320);\r
+\r
+ /* Calculate number of bytes to display */\r
+\r
+ wbp->num_bytes = (width + 3) >> 2;\r
+\r
+ /* Calculate mask for leftover bits */\r
+\r
+ if ((leftover = (width & 3) << 1) != 0)\r
+ wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
+ else\r
+ wbp->mask = 0xff;\r
+\r
+ wbp->pcx_funcp = pcx_put_cga; /* Set the display function ptr */\r
+\r
+ break;\r
+\r
+ case 0x06: /* 640 x 200 2-color CGA */\r
+\r
+ /* Calculate display width in pixels */\r
+\r
+ width = min((wbp->header.xlr - wbp->header.xul + 1), 640);\r
+\r
+ /* Calculate number of bytes to display */\r
+\r
+ wbp->num_bytes = (width + 7) >> 3;\r
+\r
+ /* Calculate mask for leftover bits */\r
+\r
+ if ((leftover = width & 7) != 0)\r
+ wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
+ else\r
+ wbp->mask = 0xff;\r
+\r
+ wbp->pcx_funcp = pcx_put_cga; /* Set the display function ptr */\r
+\r
+ break;\r
+\r
+ case 0x0d: /* 320 x 200 16-color EGA/VGA */\r
+ case 0x0e: /* 640 x 200 16-color EGA/VGA */\r
+ case 0x0f: /* 640 x 350 2-color EGA/VGA */\r
+ case 0x10: /* 640 x 350 16-color EGA/VGA */\r
+ case 0x11: /* 640 x 480 2-color VGA */\r
+ case 0x12: /* 640 x 480 16-color VGA */\r
+\r
+ switch (vmode) /* Initialize the display adapter page offset */\r
+ {\r
+ case 0x0d: /* 320 x 200 16-color EGA/VGA (8 pages maximum) */\r
+\r
+ wbp->page_offset = 0x02000000L * (unsigned long) page;\r
+\r
+ break;\r
+\r
+ case 0x0e: /* 640 x 200 16-color EGA/VGA (4 pages maximum) */\r
+\r
+ wbp->page_offset = 0x04000000L * (unsigned long) page;\r
+\r
+ break;\r
+\r
+ case 0x0f: /* 640 x 350 2-color EGA/VGA (2 pages maximum) */\r
+ case 0x10: /* 640 x 350 16-color EGA/VGA (2 pages maximum) */\r
+\r
+ wbp->page_offset = 0x08000000L * (unsigned long) page;\r
+\r
+ break;\r
+\r
+ default: /* All other modes support only one page */\r
+\r
+ break;\r
+ }\r
+\r
+ /* Calculate display width in pixels */\r
+\r
+ width = min((wbp->header.xlr - wbp->header.xul + 1), 640);\r
+\r
+ /* Calculate number of bytes to display */\r
+\r
+ wbp->num_bytes = (width + 7) >> 3;\r
+\r
+ /* Calculate mask for leftover bits */\r
+\r
+ if ((leftover = width & 7) != 0)\r
+ wbp->mask = (0xff << (8 - leftover)) & 0xff;\r
+ else\r
+ wbp->mask = 0xff;\r
+\r
+ wbp->pcx_funcp = pcx_put_ega; /* Set the display function ptr */\r
+\r
+ break;\r
+\r
+ case 0x13: /* 320 x 200 256-color VGA */\r
+\r
+ /* Calculate number of bytes to display */\r
+\r
+ wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320);\r
+\r
+ wbp->mask = 0; /* Dummy parameter */\r
+\r
+ wbp->pcx_funcp = pcx_put_vga; /* Set the display function ptr */\r
+\r
+ break;\r
+\r
+ default: /* Other display adapters not supported */\r
+\r
+ status = FALSE;\r
+\r
+ break;\r
+ }\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_READ_HEADER - Read PCX File Header\r
+ *\r
+ * Purpose: To read and validate a PCX file header.\r
+ *\r
+ * Setup: static BOOL pcx_read_header\r
+ * (\r
+ * PCX_WORKBLK *wbp\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Result: The file header is read into the "header" member of the\r
+ * PCX workblock.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_read_header\r
+(\r
+ PCX_WORKBLK *wbp\r
+)\r
+{\r
+ BOOL status = TRUE; /* Status flag */\r
+ PCX_HDR *hdrp; /* PCX file header buffer pointer */\r
+\r
+ hdrp = &(wbp->header); /* Initialize the file header pointer */\r
+\r
+ /* Read the file header */\r
+\r
+ if (fseek(wbp->fp, 0L, SEEK_SET) != 0)\r
+ status = FALSE;\r
+\r
+ if (status == TRUE)\r
+ if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1)\r
+ status = FALSE;\r
+\r
+ /* Validate the PCX file format */\r
+\r
+ if (status == TRUE)\r
+ if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))\r
+ status = FALSE;\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_READ_EXTPAL - Read Extended Palette\r
+ *\r
+ * Purpose: To read an extended (256-color) palette (if it exists).\r
+ *\r
+ * Setup: static BOOL pcx_read_extpal\r
+ * (\r
+ * PCX_WORKBLK *wbp\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Note: It is possible for a PCX image file without an appended\r
+ * 256-color palette to have the value 0x0c as the 769th byte\r
+ * (the location of the extended palette indicator byte) from \r
+ * the end of the file (i.e. - in the encoded image data \r
+ * section). This function will misinterpret the following\r
+ * 768 bytes of encoded image data as an extended palette.\r
+ *\r
+ * This problem will only occur if an attempt is made to\r
+ * display a PCX image using the wrong MS-DOS video mode. It\r
+ * can be detected by decoding the image data and using \r
+ * "ftell" to note the file position of the end of the \r
+ * encoded image data section, then comparing it to the file\r
+ * position of the indicator byte. If the supposed indicator\r
+ * byte is located within the encoded image data section, the\r
+ * indicator byte is invalid and so the file header palette\r
+ * should be used instead.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_read_extpal\r
+(\r
+ PCX_WORKBLK *wbp\r
+)\r
+{\r
+ int indicator; /* PCX extended palette indicator */\r
+\r
+ /* Position the file pointer to the extended palette indicator byte */\r
+\r
+ if (fseek(wbp->fp, -769L, SEEK_END) != 0)\r
+ return (FALSE);\r
+\r
+ /* Read the (assumed) extended palette indicator byte */\r
+\r
+ if ((indicator = getc(wbp->fp)) == EOF)\r
+ return (FALSE);\r
+\r
+ if (indicator == PCX_EPAL_FLAG) /* Check for indicator byte */\r
+ {\r
+ /* Allocate an extended palette buffer */\r
+\r
+ if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),\r
+ PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)\r
+ return (FALSE);\r
+\r
+ /* Read the extended palette */\r
+\r
+ if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) !=\r
+ PCX_EPAL_SIZE)\r
+ {\r
+ free(wbp->palettep); /* Free the extended palette buffer */\r
+ return (FALSE);\r
+ }\r
+\r
+ wbp->epal_flag = TRUE; /* Indicate extended palette present */\r
+ }\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_READ_LINE - Read PCX Line\r
+ *\r
+ * Purpose: To read an encoded line (all color planes) from a PCX-\r
+ * format image file and write the decoded data to a line\r
+ * buffer.\r
+ *\r
+ * Setup: static BOOL pcx_read_line\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char *linep,\r
+ * int bpline\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ * linep is a PCX scan line buffer pointer.\r
+ * bpline is the number of bytes per scan line (all color\r
+ * planes).\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_read_line\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char *linep,\r
+ int bpline\r
+)\r
+{\r
+ int data; /* Image data byte */\r
+ int count; /* Image data byte repeat count */\r
+ int offset = 0; /* Scan line buffer offset */\r
+\r
+ while (offset < bpline) /* Decode current scan line */\r
+ {\r
+ if ((data = getc(wbp->fp)) == EOF) /* Get next byte */\r
+ return (FALSE);\r
+\r
+ /* If top two bits of byte are set, lower six bits show how */\r
+ /* many times to duplicate next byte */\r
+\r
+ if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG)\r
+ {\r
+ count = data & PCX_COMP_MASK; /* Mask off repeat count */\r
+\r
+ if ((data = getc(wbp->fp)) == EOF) /* Get next byte */\r
+ return (FALSE);\r
+\r
+ memset(linep, data, count); /* Duplicate byte */\r
+ linep += count;\r
+ offset += count;\r
+ }\r
+ else\r
+ {\r
+ *linep++ = (unsigned char) data; /* Copy byte */\r
+ offset++;\r
+ }\r
+ }\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_SET_PALETTE - Set Palette\r
+ *\r
+ * Purpose: To set the display palette according to a PCX file\r
+ * palette.\r
+ *\r
+ * Setup: static BOOL pcx_set_palette\r
+ * (\r
+ * PCX_PAL *palettep,\r
+ * int vmode\r
+ * )\r
+ *\r
+ * Where: palettep is a pointer to a PCX file palette.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * PCX_HERC - 720 x 348 Hercules monochrome\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_set_palette\r
+(\r
+ PCX_PAL *palettep,\r
+ int vmode\r
+)\r
+{\r
+ int i; /* Scratch counter */\r
+ int red_lo; /* Low red intensity */\r
+ int red_hi; /* High red intensity */\r
+ int green_lo; /* Green low intensity */\r
+ int green_hi; /* Green high intensity */\r
+ int blue_lo; /* Blue low intensity */\r
+ int blue_hi; /* Blue high intensity */\r
+ unsigned char *ega_palp; /* EGA 16-color palette buffer pointer */\r
+ unsigned long *vga_palp; /* VGA 256-color palette buffer pointer */\r
+ BOOL status = TRUE; /* Return status */\r
+ union REGS regs; /* 80x86 register values */\r
+ struct SREGS sregs; /* 80x86 segment register values */\r
+\r
+ switch (vmode)\r
+ {\r
+ case PCX_HERC: /* 720 x 348 Hercules monochrome */\r
+\r
+ break;\r
+\r
+ case 0x04: /* 320 x 200 4-color CGA display */\r
+ case 0x05: /* 320 x 200 monochrome CGA display (burst off) */\r
+ case 0x06: /* 640 x 200 2-color CGA display */\r
+\r
+ /* Set the CGA color palette */\r
+\r
+ pcx_cga_palette(palettep, vmode);\r
+\r
+ break;\r
+\r
+ case 0x0d: /* 320 x 200 16-color EGA/VGA */\r
+ case 0x0e: /* 640 x 200 16-color EGA/VGA */\r
+ case 0x0f: /* 640 x 350 2-color EGA/VGA */\r
+ case 0x10: /* 640 x 350 16-color EGA/VGA */\r
+ case 0x11: /* 640 x 480 2-color VGA */\r
+ case 0x12: /* 640 x 480 16-color VGA */\r
+\r
+ if (pcx_isvga() == TRUE) /* Check for VGA display adapter */\r
+ {\r
+ /* Allocate a 16-color VGA display adapter palette buffer */\r
+\r
+ if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),\r
+ PCX_PAL_SIZE)) == (unsigned long *) NULL)\r
+ {\r
+ status = FALSE;\r
+ break;\r
+ }\r
+\r
+ /* Map PCX hardware palette to 16-color VGA palette (each color */\r
+ /* value is a "long" with the form: */\r
+ /* */\r
+ /* 00000000-00BBBBBB-00GGGGGG-00RRRRRR */\r
+ /* */\r
+ /* where each color is a 6-bit value. */\r
+\r
+ for (i = 0; i < PCX_PAL_SIZE; i++)\r
+ vga_palp[i] = (long) (palettep[i].red >> 2) |\r
+ ((long) (palettep[i].green >> 2)) << 8 |\r
+ ((long) (palettep[i].blue >> 2)) << 16;\r
+\r
+ (void) _remapallpalette(vga_palp); /* Remap entire palette */\r
+\r
+ free(vga_palp); /* Free the VGA palette buffer */\r
+ }\r
+ else /* EGA display adapter */\r
+ {\r
+ /* Allocate an EGA display adapter palette buffer */\r
+\r
+ if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char),\r
+ PCX_PAL_SIZE + 1)) == (unsigned char *) NULL)\r
+ {\r
+ status = FALSE;\r
+ break;\r
+ }\r
+\r
+ /* Map PCX hardware palette to 16-color EGA palette (each EGA */\r
+ /* color value is an "unsigned char" with the form: */\r
+ /* */\r
+ /* 0 0 R' G' B' R G B */\r
+ /* */\r
+ /* where X' is the low-intensity value and X is the high */\r
+ /* intensity value for the color X.) */\r
+ /* */\r
+ /* NOTE: the "_remapallpalette" function could be used to set */\r
+ /* the palette for EGA display adapters. However, this */\r
+ /* function does not appear to update the palette */\r
+ /* register values in the Dynamic Save Area (see the */\r
+ /* function header for "pcx_init_palette" in PCX_FILE.C) */\r
+ /* for a detailed explanation). */\r
+\r
+ for (i = 0; i < PCX_PAL_SIZE; i++)\r
+ {\r
+ /* Extract low and high intensity bits for each color */\r
+\r
+ red_lo = (palettep[i].red >> 6) & 0x01;\r
+ red_hi = (palettep[i].red >> 6) & 0x02;\r
+ green_lo = (palettep[i].green >> 6) & 0x01;\r
+ green_hi = (palettep[i].green >> 6) & 0x02;\r
+ blue_lo = (palettep[i].blue >> 6) & 0x01;\r
+ blue_hi = (palettep[i].blue >> 6) & 0x02;\r
+\r
+ /* Combine color intensity bits for EGA palette value */\r
+\r
+ ega_palp[i] = (unsigned char) ((red_lo << 5) | (green_lo << 4) |\r
+ (blue_lo << 3) | (red_hi << 1) | green_hi | (blue_hi >>\r
+ 1));\r
+ }\r
+\r
+ /* Set the border (overscan) color to black (BIOS default) */\r
+\r
+ ega_palp[16] = (unsigned char) 0;\r
+\r
+ regs.h.ah = 0x10; /* Select "Set All Palette Registers" */\r
+ regs.h.al = 0x02;\r
+\r
+ /* Get the EGA palette registers buffer offset value */\r
+\r
+ regs.x.dx = (unsigned int) ega_palp;\r
+\r
+ segread(&sregs); /* Get the current DS segment register value */\r
+\r
+ sregs.es = sregs.ds;\r
+\r
+ int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */\r
+\r
+ free(ega_palp); /* Free the EGA palette buffer */\r
+ }\r
+\r
+ break;\r
+\r
+ case 0x13: /* 320 x 200 256-color VGA display */\r
+\r
+ /* Allocate a 256-color VGA display adapter palette buffer */\r
+\r
+ if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),\r
+ PCX_EPAL_SIZE)) == (unsigned long *) NULL)\r
+ {\r
+ status = FALSE;\r
+ break;\r
+ }\r
+\r
+ /* Map PCX extended palette to 256-color VGA palette */\r
+\r
+ for (i = 0; i < PCX_EPAL_SIZE; i++)\r
+ vga_palp[i] = (long) (palettep[i].red >> 2) |\r
+ ((long) (palettep[i].green >> 2)) << 8 |\r
+ ((long) (palettep[i].blue >> 2)) << 16;\r
+\r
+ (void) _remapallpalette(vga_palp); /* Remap entire palette */\r
+\r
+ free(vga_palp); /* Free the VGA palette buffer */\r
+\r
+ break;\r
+\r
+ default: /* Other modes not supported */\r
+\r
+ status = FALSE;\r
+\r
+ break;\r
+ }\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_CGA_PALETTE - Select CGA Palette\r
+ *\r
+ * Purpose: To set the Color Graphics Adapter (CGA) display palette\r
+ * according to a PCX file palette.\r
+ *\r
+ * Setup: static void pcx_cga_palette\r
+ * (\r
+ * PCX_PAL *palettep,\r
+ * int vmode\r
+ * )\r
+ *\r
+ * Where: palettep is a pointer to a PCX file palette.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ *\r
+ * Note: ZSoft's PC Paintbrush products no longer support the CGA\r
+ * color palette. When a CGA color palette is encountered,\r
+ * PC Paintbrush maps it to a monochrome (black and white)\r
+ * palette.\r
+ *\r
+ * MS-DOS video mode 0x05 (320 x 200 monochrome CGA display,\r
+ * color burst off) will only display a monochrome image on\r
+ * a composite video monitor (typically a television set with\r
+ * an RF adapter). All other monitors will display a color\r
+ * palette in this mode (which is different for CGA and EGA\r
+ * or VGA display adapters).\r
+ *\r
+ * The "background" color is actually the foreground color\r
+ * (i.e. - the color of activated pixels) for MS-DOS video\r
+ * mode 0x06. The background color is black for CGA display\r
+ * adapters.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_cga_palette\r
+(\r
+ PCX_PAL *palettep,\r
+ int vmode\r
+)\r
+{\r
+ short pal_num; /* Palette number */\r
+ BOOL sel_flag; /* Palette selector bit flag */\r
+ BOOL int_flag; /* Intensity bit flag */\r
+ union REGS regs; /* 80x86 register values */\r
+\r
+ /* Set the background color */\r
+\r
+ regs.h.ah = 0x0b; /* Select "Set Color Palette" BIOS routine */\r
+ regs.h.bh = 0;\r
+\r
+ regs.h.bl = (unsigned char) PCX_CGA_BKGND(palettep);\r
+\r
+ int86(0x10, ®s, ®s); /* Call BIOS video service */\r
+\r
+ if (vmode != 0x06) /* Select the CGA color palette */\r
+ {\r
+ /* Check the palette selector bit flag */\r
+\r
+ sel_flag = PCX_CGA_SELECT(palettep) ? TRUE : FALSE;\r
+\r
+ /* Check the intensity bit flag */\r
+\r
+ int_flag = PCX_CGA_INTENSITY(palettep) ? TRUE : FALSE;\r
+\r
+ /* Determine the CGA palette number */\r
+\r
+ if (int_flag == TRUE) /* Intensity = bright */\r
+ {\r
+ if (sel_flag == TRUE)\r
+ pal_num = 3; /* Light cyan - light magenta - white */\r
+ else\r
+ pal_num = 1; /* Cyan - magenta - light grey */\r
+ }\r
+ else /* Intensity = dim */\r
+ {\r
+ if (sel_flag == TRUE)\r
+ pal_num = 2; /* Light green - light red - yellow */\r
+ else\r
+ pal_num = 0; /* Green - red - brown */\r
+ }\r
+\r
+ /* Select the foreground color palette */\r
+\r
+ (void) _selectpalette(pal_num);\r
+ }\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_PUT_HERC - Display Hercules PCX Line\r
+ *\r
+ * Purpose: To copy a decoded PCX image scan line to a Hercules\r
+ * monochrome graphics display adapter buffer.\r
+ *\r
+ * Setup: static void pcx_put_herc\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ * linep is a PCX scan line buffer pointer.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+void pcx_put_herc\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] &= wbp->mask;\r
+\r
+ /* Calculate Hercules display buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +\r
+ ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);\r
+\r
+ /* Copy data from the scan line buffer to the Hercules display buffer */\r
+\r
+ (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_PUT_CGA - Display CGA PCX Line\r
+ *\r
+ * Purpose: To copy a decoded PCX image scan line to a CGA display\r
+ * adapter buffer.\r
+ *\r
+ * Setup: static void pcx_put_cga\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ * linep is a PCX scan line buffer pointer.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_put_cga\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] &= wbp->mask;\r
+\r
+ /* Calculate CGA display buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)\r
+ + 0x2000 * (line_num & 1);\r
+\r
+ /* Copy data from the scan line buffer to the CGA display buffer */\r
+\r
+ (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_PUT_EGA - Display EGA/VGA PCX Line\r
+ *\r
+ * Purpose: To copy a decoded PCX image scan line to an EGA/VGA\r
+ * display adapter buffer.\r
+ *\r
+ * Setup: static void pcx_put_ega\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ * linep is a PCX scan line buffer pointer.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_put_ega\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ int plane_num; /* EGA/VGA color plane number */\r
+ int plane_mask; /* EGA/VGA color plane mask */\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +\r
+ line_num * 80;\r
+\r
+ outpw(0x03ce, 0x0005); /* Select EGA/VGA write mode 0 */\r
+\r
+ /* Copy PCX scan line data to each color plane */\r
+\r
+ plane_mask = 0x0100; /* Start with color plane 0 */\r
+\r
+ for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)\r
+ {\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] &= wbp->mask;\r
+\r
+ outpw(0x03c4, plane_mask + 2); /* Select current color plane */\r
+\r
+ /* Copy data from the scan line buffer to the EGA/VGA display */\r
+\r
+ (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
+\r
+ linep += wbp->header.bppscan; /* Increment plane offset */\r
+\r
+ plane_mask <<= 1; /* Sequence plane mask */\r
+ }\r
+\r
+ outpw(0x03c4, 0x0f02); /* Select all color planes */\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_PUT_VGA - Display VGA PCX Line\r
+ *\r
+ * Purpose: To copy a decoded PCX image scan line to a VGA display\r
+ * adapter buffer.\r
+ *\r
+ * Setup: static void pcx_put_vga\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX image file workblock pointer.\r
+ * linep is a PCX scan line buffer pointer.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_put_vga\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;\r
+\r
+ /* Copy data from the scan line buffer to the VGA display buffer */\r
+\r
+ (void) _fmemcpy(displayp, linep, wbp->num_bytes);\r
+}\r
+\r
--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_EXAM.C - PCX_LIB File Header Examination Utility\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/06 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PORTABILITY NOTES\r
+ *\r
+ * 1. When porting this program to other processors, remember that words\r
+ * are stored by 80x86-based machines in the big-endian format. That\r
+ * is, the eight least significant bits (lower byte) are stored\r
+ * first, followed by the eight most significant bits (upper byte).\r
+ * If PCX-format files are transferred to little-endian machines\r
+ * (such as those based on 680x0 and Z8000 processors), the order of\r
+ * bytes within each word will have to be reversed before they can \r
+ * be interpreted. (This applies to the file header only, since the\r
+ * encoded image data and optional 256-color palette are stored as\r
+ * bytes.)\r
+ *\r
+ ************************************************************************* \r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include "pcx_int.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\f\r
+/* GLOBALS */\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * MAIN - Executive Function\r
+ *\r
+ * Purpose: To read and display a PCX-format image file header.\r
+ *\r
+ * Setup: int main\r
+ * (\r
+ * int argc,\r
+ * char **argv\r
+ * )\r
+ *\r
+ * Where: argc is the number of command-line arguments.\r
+ * argv is a pointer to an array of command-line argument\r
+ * strings.\r
+ *\r
+ * Return: 0 if successful; otherwise 2.\r
+ *\r
+ * Result: The file header information is written to "stdout".\r
+ *\r
+ * Note: Usage is:\r
+ *\r
+ * PCX_EXAM filename\r
+ *\r
+ * where "filename" is the name of a PCX-format image file.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+int main\r
+(\r
+ int argc,\r
+ char **argv\r
+)\r
+{\r
+ char *vers; /* Version number string pointer */\r
+ char *pal_type; /* Palette type string pointer */\r
+ int range; /* Palette range */\r
+ int indicator; /* Extended palette indicator byte */\r
+ BOOL status = TRUE; /* Return status */\r
+ BOOL ep_flag = FALSE; /* Extended palette flag */\r
+ FILE *fp; /* File pointer */\r
+ PCX_HDR *hdrp; /* File header structure pointer */\r
+ PCX_PAL *ext_palettep; /* Extended palette pointer */\r
+\r
+ /* Display program title */\r
+\r
+ puts("\nPCX_EXAM - PCX Image File Examination Utility\n");\r
+\r
+ /* Check for filename */\r
+\r
+ if (argc < 2)\r
+ {\r
+ /* Display usage information */\r
+\r
+ fputs(" Synopsis: This public domain utility displays inf", stderr);\r
+ fputs("ormation contained in the\n header of a ", stderr);\r
+ fputs("Paintbrush (R) PCX-format image file.\n\n Usage: ", stderr);\r
+ fputs(" PCX_EXAM filename\n\n Example: PCX_EXAM picture", stderr);\r
+ fputs(".pcx\n", stderr);\r
+\r
+ return (2);\r
+ }\r
+\r
+ /* Allocate a PCX file header buffer */\r
+\r
+ if ((hdrp = (PCX_HDR *) malloc(sizeof(PCX_HDR))) == (PCX_HDR *) NULL)\r
+ {\r
+ fputs("ERROR: out of memory\n", stderr);\r
+ return (2);\r
+ }\r
+\r
+ /* Open the PCX image file in binary mode */\r
+\r
+ if ((fp = fopen(argv[1], "rb")) == (FILE *) NULL)\r
+ {\r
+ fprintf(stderr, "ERROR: cannot open file %s\n", argv[1]);\r
+\r
+ free(hdrp); /* Free the file header memory */\r
+\r
+ return (2);\r
+ }\r
+\r
+ /* Read the file header */\r
+\r
+ if (status == TRUE)\r
+ if (fseek(fp, 0L, SEEK_SET) != 0)\r
+ {\r
+ fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]);\r
+ status = FALSE;\r
+ }\r
+\r
+ if (status == TRUE)\r
+ if (fread(hdrp, sizeof(PCX_HDR), 1, fp) != 1)\r
+ {\r
+ fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]);\r
+ status = FALSE;\r
+ }\r
+\r
+ /* Validate the PCX file format */\r
+\r
+ if (status == TRUE)\r
+ if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))\r
+ {\r
+ fprintf(stderr, "ERROR: file %s not valid PCX format\n", argv[1]);\r
+ status = FALSE;\r
+ }\r
+\r
+ /* Determine the version number */\r
+\r
+ switch (hdrp->version)\r
+ {\r
+ case 0:\r
+\r
+ vers = "PC Paintbrush 2.5";\r
+\r
+ break;\r
+\r
+ case 2:\r
+\r
+ vers = "PC Paintbrush 2.8 (with palette information)";\r
+\r
+ break;\r
+\r
+ case 3:\r
+\r
+ vers = "PC Paintbrush 2.8 (without palette information)";\r
+\r
+ break;\r
+\r
+ case 4:\r
+\r
+ vers = "PC Paintbrush for Windows (not 3.0)";\r
+\r
+ break;\r
+\r
+ case 5:\r
+\r
+ vers = "PC Paintbrush 3.0 and greater";\r
+\r
+ break;\r
+\r
+ default:\r
+\r
+ vers = "Unknown version";\r
+\r
+ break;\r
+ }\r
+\r
+ /* Display the PCX file header information */\r
+\r
+ printf("PCX filename: %s\n", argv[1]);\r
+ printf("Version: %s\n", vers);\r
+ printf("Encoding: %s\n", hdrp->encoding == 1 ? "Run length" :\r
+ "Unknown");\r
+ printf("%d bits per pixel\n", hdrp->bppixel);\r
+ printf("Image from (%d, %d) to (%d, %d) pixels.\n", hdrp->xul,\r
+ hdrp->yul, hdrp->xlr, hdrp->ylr);\r
+ printf("Created on a device with %d x %d dpi resolution\n",\r
+ hdrp->horz_res, hdrp->vert_res);\r
+ printf("Number of color planes: %d\n", hdrp->nplanes);\r
+ printf("Bytes per color plane scan line: %d\n", hdrp->bppscan);\r
+\r
+ switch (hdrp->palette_type & PCX_PAL_MASK)\r
+ {\r
+ case 1:\r
+\r
+ pal_type = "color or B&W";\r
+\r
+ break;\r
+\r
+ case 2:\r
+\r
+ pal_type = "grayscale";\r
+\r
+ break;\r
+\r
+ default:\r
+\r
+ pal_type = "unknown";\r
+\r
+ break;\r
+ }\r
+\r
+ printf("Palette type: %s\n", pal_type);\r
+\r
+ /* Check for extended (256-color) palette */\r
+\r
+ if (hdrp->version == 5)\r
+ {\r
+ /* Check for valid palette indicator byte */\r
+\r
+ if (fseek(fp, -769L, SEEK_END) != 0)\r
+ {\r
+ fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]);\r
+ status = FALSE;\r
+ }\r
+\r
+ if (status == TRUE)\r
+ {\r
+ if ((indicator = getc(fp)) == PCX_EPAL_FLAG)\r
+ {\r
+ /* Allocate an extended palette buffer */\r
+\r
+ if ((ext_palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),\r
+ PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)\r
+ {\r
+ fputs("ERROR: out of memory\n", stderr);\r
+ status = FALSE;\r
+ }\r
+\r
+ /* Read the extended palette */\r
+\r
+ if (status == TRUE)\r
+ {\r
+ if (fread(ext_palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=\r
+ PCX_EPAL_SIZE)\r
+ {\r
+ free(ext_palettep); /* Free extended palette buffer */\r
+ status = FALSE;\r
+ }\r
+ }\r
+\r
+ ep_flag = TRUE; /* Indicate extended palette exists */\r
+ }\r
+ }\r
+ }\r
+\r
+ if (status == TRUE)\r
+ if (ep_flag == TRUE)\r
+ {\r
+ /* Display extended (256-color) palette */\r
+\r
+ puts("Extended 256-color palette:\n");\r
+\r
+ puts("COLOR RED GREEN BLUE\n");\r
+\r
+ for (range = 0; range < PCX_EPAL_SIZE; range++)\r
+ printf(" %03d %2x %2x %2x\n", range,\r
+ ext_palettep[range].red, ext_palettep[range].green,\r
+ ext_palettep[range].blue);\r
+\r
+ putchar('\n');\r
+\r
+ free(ext_palettep); /* Free the extended palette */\r
+ }\r
+ else\r
+ {\r
+ /* Display file header palette */\r
+\r
+ puts("File header color palette:\n");\r
+\r
+ printf("RED ... ");\r
+\r
+ for (range = 0; range < PCX_PAL_SIZE; range++)\r
+ printf("%2x ", hdrp->palette[range].red);\r
+\r
+ printf("\nGREEN ... ");\r
+\r
+ for (range = 0; range < PCX_PAL_SIZE; range++)\r
+ printf("%2x ", hdrp->palette[range].green);\r
+\r
+ printf("\nBLUE ... ");\r
+\r
+ for (range = 0; range < PCX_PAL_SIZE; range++)\r
+ printf("%2x ", hdrp->palette[range].blue);\r
+\r
+ putchar('\n');\r
+ }\r
+\r
+ if (fclose(fp) == EOF) /* Close the file */\r
+ {\r
+ fprintf(stderr, "Error: cannot close file %s\n", argv[1]);\r
+ status = FALSE;\r
+ }\r
+\r
+ free (hdrp); /* Free the file header buffer */\r
+\r
+ return (0);\r
+}\r
+\r
--- /dev/null
+/* \r
+ *************************************************************************\r
+ *\r
+ * PCX_EXT.H - PCX_LIB Library External Definitions Include File\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/07 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/* DEFINITIONS */\r
+\r
+#define _PCX_EXT_H 1\r
+\r
+#define FALSE 0\r
+#define TRUE 1\r
+\r
+typedef int BOOL; /* Boolean flag */\r
+\f\r
+/* STRUCTURE DECLARATIONS */\r
+\r
+typedef struct pcx_vsb /* BIOS video services data save buffer */\r
+{\r
+ struct pcx_ppt /* Primary Pointer Table */\r
+ {\r
+ void _far *vptp; /* Video Parameter Table pointer */\r
+ unsigned char _far *dsap; /* Dynamic Save Area pointer */\r
+ void _far *tmacgp; /* Text Mode Aux Char Generator pointer */\r
+ void _far *gmacgp; /* Graphics Mode Aux Char Generator ptr */\r
+ void _far *sptp; /* Secondary Pointer Table pointer */\r
+ void _far *rsv_1; /* Reserved */\r
+ void _far *rsv_2; /* Reserved */\r
+ }\r
+ pcx_ppt;\r
+\r
+ /* Previous Primary Pointer Table pointer */\r
+\r
+ struct pcx_ppt _far *prev_pptp;\r
+}\r
+PCX_VSB;\r
+\f\r
+/* FUNCTIONS PROTOTYPES */\r
+\r
+extern BOOL pcx_init_dsa(PCX_VSB **);\r
+extern BOOL pcx_isvga(void);\r
+extern BOOL pcx_read(char *, int, int);\r
+extern BOOL pcx_write(char *, int, int, int, int);\r
+\r
+extern void pcx_free_dsa(PCX_VSB *);\r
+\r
--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_FILE.C - PCX_LIB Library Image File Functions\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/03 - fixed "segread" call.\r
+ * 91/04/07 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PORTABILITY NOTES\r
+ *\r
+ * 1. While this program is written in ANSI C, it uses a number of \r
+ * function calls that are specific to the Microsoft C V6.0 library.\r
+ * These are documented as follows for the purposes of porting this\r
+ * program to other compilers and/or processors: \r
+ *\r
+ * _ffree - "free" for small model / far data\r
+ * _fmalloc - "malloc" for small model / far data\r
+ * _fmemcpy - "memcpy" for small model / far data\r
+ * int86 - execute 80x86 interrupt routine\r
+ * int86x - execute 80x86 interrupt routine (far data)\r
+ * outpw - output word to 80x86 I/O port\r
+ * segread - get current 80x86 segment register values\r
+ *\r
+ * 2. When porting this program to other processors, remember that words\r
+ * are stored by 80x86-based machines in the big-endian format. That\r
+ * is, the eight least significant bits (lower byte) are stored\r
+ * first, followed by the eight most significant bits (upper byte).\r
+ * If PCX-format files are transferred to little-endian machines\r
+ * (such as those based on 680x0 and Z8000 processors), the order of\r
+ * bytes within each word will have to be reversed before they can \r
+ * be interpreted. (This applies to the file header only, since the\r
+ * encoded image data and optional 256-color palette are stored as\r
+ * bytes.)\r
+ *\r
+ * 3. MS-DOS does not recognize the 720 x 348 graphics mode of the\r
+ * Hercules monochrome display adapter. Therefore, the constant\r
+ * PCX_HERC should never be passed as a video mode parameter to any\r
+ * BIOS service routine.\r
+ *\r
+ * The Microsoft C compiler includes a "video mode" parameter\r
+ * definition (_HERCMONO) that is defined as 0x08. This is a\r
+ * reserved MS-DOS video mode that is apparently used internally by\r
+ * the ROM BIOS. It can, however, be passed to the Microsoft C\r
+ * library function "_setvideomode" to force the Hercules display\r
+ * adapter into graphics mode.\r
+ *\r
+ * Most other MS-DOS C compilers offer similar library functions to\r
+ * force the Hercules monochrome display adapter into its 720 x 348\r
+ * graphics mode.\r
+ *\r
+ ************************************************************************* \r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <conio.h>\r
+#include <malloc.h>\r
+#include <dos.h>\r
+#include <graph.h>\r
+#include "pcx_int.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\r
+static BOOL pcx_encode(int, int, FILE *);\r
+static BOOL pcx_init_palette(PCX_PAL *, int);\r
+static BOOL pcx_write_extpal(FILE *);\r
+static BOOL pcx_write_line(unsigned char *, int, FILE *);\r
+static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int);\r
+\r
+static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int);\r
+static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int);\r
+\f\r
+/* GLOBALS */\r
+\r
+/* Default EGA palette register values */\r
+\r
+static BYTE pcx_EGA_DefPal_1[16] = /* Modes 0x0d and 0x0e */\r
+{\r
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,\r
+ 0x14, 0x15, 0x16, 0x17\r
+};\r
+\r
+static BYTE pcx_EGA_DefPal_2[16] = /* Mode 0x0f */\r
+{\r
+ 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,\r
+ 0x00, 0x18, 0x00, 0x00\r
+};\r
+\r
+static BYTE pcx_EGA_DefPal_3[16] = /* Mode 0x10 */\r
+{\r
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, \r
+ 0x3c, 0x3d, 0x3e, 0x3f\r
+};\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_WRITE - Write PCX File\r
+ *\r
+ * Purpose: To write a PCX-format image file from an image stored in\r
+ * a video buffer. The image is assumed to start in the\r
+ * upper left corner of the screen.\r
+ *\r
+ * Setup: BOOL pcx_write\r
+ * (\r
+ * char *fname,\r
+ * int vmode,\r
+ * int page,\r
+ * int width,\r
+ * int height,\r
+ * )\r
+ *\r
+ * Where: fname is a PCX image file name.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * PCX_HERC - 720 x 348 Hercules monochrome\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * page is the video display page number. Valid values are:\r
+ *\r
+ * Mode PCX_HERC - 0 or 1\r
+ * Mode 0x0d - 0 to 7\r
+ * Mode 0x0e - 0 to 3\r
+ * Mode 0x0f - 0 or 1\r
+ * Mode 0x10 - 0 or 1\r
+ * All Other - 0\r
+ *\r
+ * width is the image width in pixels.\r
+ * height is the image height in pixels.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+BOOL pcx_write\r
+(\r
+ char *fname,\r
+ int vmode,\r
+ int page,\r
+ int width,\r
+ int height\r
+)\r
+{\r
+ int bpline; /* Number of bytes per scan line */\r
+ int line_num; /* Scan line number */\r
+ unsigned char *linep; /* Image scan line buffer pointer */\r
+ BOOL status = TRUE; /* Return status */\r
+ PCX_WORKBLK *wbp; /* PCX image file workblock pointer */\r
+\r
+ /* Open a PCX image file workblock */\r
+\r
+ if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL)\r
+ return (FALSE);\r
+\r
+ /* Initialize the workblock for writing */\r
+\r
+ if (pcx_write_init(wbp, vmode, page, width, height) == FALSE)\r
+ status = FALSE;\r
+\r
+ /* Calculate number of bytes per line (for all color planes) */\r
+\r
+ bpline = wbp->header.bppscan * wbp->header.nplanes;\r
+\r
+ /* Allocate a scan line buffer */\r
+\r
+ if (status == TRUE)\r
+ if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *)\r
+ NULL)\r
+ status = FALSE;\r
+\r
+ /* Write the file header to the file */\r
+\r
+ if (status == TRUE)\r
+ if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1)\r
+ status = FALSE;\r
+\r
+ /* Write the encoded image data to the file */\r
+\r
+ if (status == TRUE)\r
+ {\r
+ for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++)\r
+ {\r
+ /* Get the current video buffer scan line */\r
+\r
+ wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);\r
+\r
+ /* Encode the scan line and write it to the file */\r
+\r
+ if (pcx_write_line(linep, bpline, wbp->fp) == FALSE)\r
+ {\r
+ status = FALSE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (vmode == 0x13) /* Is a 256-color palette supported ? */\r
+ {\r
+ /* Write the extended palette to the file */\r
+\r
+ if (status == TRUE)\r
+ if (pcx_write_extpal(wbp->fp) == FALSE)\r
+ status = FALSE;\r
+ }\r
+\r
+ if (pcx_close(wbp) == FALSE) /* Close the PCX workblock */\r
+ status = FALSE;\r
+\r
+ free(linep); /* Free the scan line buffer */\r
+\r
+ /* Remove the PCX image file if an error occurred */\r
+\r
+ if (status == FALSE)\r
+ (void) remove(fname);\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_INIT_DSA - Initialize Dynamic Save Area\r
+ *\r
+ * Purpose: To set up a Video Services Primary Pointer Table and an\r
+ * associated Dynamic Save Area where BIOS service "Set All\r
+ * Palette Registers" (function 0x02) can store the EGA color\r
+ * palette registers settings after it updates them.\r
+ *\r
+ * Setup: BOOL pcx_init_dsa\r
+ * (\r
+ * PCX_VSB **vsbpp\r
+ * )\r
+ *\r
+ * Where: vsbp is a pointer to where a pointer to an instantiated\r
+ * PCX_VSB structure is to be returned.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Note: The EGA display adapter color palette registers are\r
+ * write-only. In order to save the current color palette\r
+ * with a PCX-format image file by calling "pcx_write", you\r
+ * must call this function BEFORE you display the image in\r
+ * the following MS-DOS video modes:\r
+ *\r
+ * 0x0d - 320 x 200 16-color EGA\r
+ * 0x0e - 640 x 200 16-color EGA\r
+ * 0x0f - 640 x 350 2-color EGA\r
+ * 0x10 - 640 x 350 16-color EGA\r
+ *\r
+ * You MUST call "pcx_free_dsa" upon completion of your\r
+ * program. See the function header of "pcx_init_palette"\r
+ * for more information.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+BOOL pcx_init_dsa\r
+(\r
+ PCX_VSB **vsbpp\r
+)\r
+{\r
+ unsigned char _far *dsap; /* Dynamic Save Area pointer */\r
+ PCX_VSB *vsbp; /* Video services data save buffer ptr */\r
+\r
+ *vsbpp = (PCX_VSB *) NULL; /* Initialize returned pointer */\r
+\r
+ /* Allocate a Dynamic Save Area buffer */\r
+\r
+ if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *\r
+ 256)) == (unsigned char _far *) NULL)\r
+ return (FALSE);\r
+\r
+ /* Allocate a BIOS video services data save buffer */\r
+\r
+ if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL)\r
+ {\r
+ _ffree(dsap); /* Free the Dynamic Save Area buffer */\r
+ return (FALSE);\r
+ }\r
+\r
+ /* Save the existing Primary Pointer Table pointer */\r
+\r
+ vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L);\r
+\r
+ /* Copy the existing Primary Pointer Table into the buffer */\r
+\r
+ (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt),\r
+ vsbp->prev_pptp, sizeof(struct pcx_ppt));\r
+\r
+ vsbp->pcx_ppt.dsap = dsap; /* Update the Dynamic Save Area ptr */\r
+\r
+ /* Update the Primary Pointer Table pointer in the Video Save Table */\r
+\r
+ *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt);\r
+\r
+ *vsbpp = vsbp; /* Return Video Services data save buffer ptr */\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_FREE_DSA - Release Dynamic Save Area\r
+ *\r
+ * Purpose: To release memory allocated to the Video Services Primary\r
+ * Pointer Table and associated Dynamic Save Area and reset\r
+ * the pointer in the Video Save Table.\r
+ *\r
+ * Setup: void pcx_free_dsa\r
+ * (\r
+ * PCX_VSB *vsbp\r
+ * )\r
+ *\r
+ * Where: vsbp is a pointer to a PCX_VSB structure that was\r
+ * previously allocated and initialized by "pcx_init_dsa".\r
+ *\r
+ * Note: You MUST call this function on completion of your program\r
+ * if you previously called "pcx_init_dsa". Failure to do so\r
+ * will leave the system in an unstable state. See the\r
+ * function header of "pcx_init_palette" for more\r
+ * information.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+void pcx_free_dsa\r
+(\r
+ PCX_VSB *vsbp\r
+)\r
+{\r
+ /* Restore the previous primary pointer table pointer */\r
+\r
+ *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp;\r
+\r
+ _ffree(vsbp->pcx_ppt.dsap); /* Free the Dynamic Save Area */\r
+\r
+ free(vsbp); /* Free the Video Services data save buffer */\r
+}\r
+\f\r
+/* PRIVATE FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_WRITE_INIT - Initialize PCX Workblock For Writing\r
+ *\r
+ * Purpose: To initialize a PCX image file workblock for writing.\r
+ *\r
+ * Setup: static BOOL pcx_write_init\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * int vmode,\r
+ * int page,\r
+ * int width,\r
+ * int height\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * Ox07 - 720 x 348 Hercules monochrome\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * page is the video display page number. Valid values are:\r
+ *\r
+ * Mode PCX_HERC - 0 or 1\r
+ * Mode 0x0d - 0 to 7\r
+ * Mode 0x0e - 0 to 3\r
+ * Mode 0x0f - 0 or 1\r
+ * Mode 0x10 - 0 or 1\r
+ * All Other - 0\r
+ *\r
+ * width is the image width in pixels.\r
+ * height is the image height in pixels.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_write_init\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ int vmode,\r
+ int page,\r
+ int width,\r
+ int height\r
+)\r
+{\r
+ int max_width; /* Maximum image width */\r
+ int max_height; /* Maximum image height */\r
+ int shift; /* Mask shift value */\r
+ BOOL status = TRUE; /* Return status */\r
+ PCX_HDR *hdrp; /* File header buffer pointer */\r
+\r
+ /* Initialize the display page address offset */\r
+\r
+ wbp->page_offset = (unsigned long) 0L;\r
+\r
+ hdrp = &(wbp->header); /* Initialize the file header pointer */\r
+\r
+ /* Initialize the header constants */\r
+\r
+ hdrp->pcx_id = 0x0a; /* PCX format identifier */\r
+ hdrp->version = 5; /* Version number */\r
+ hdrp->encoding = 1; /* Encoding format (run-length) */\r
+ hdrp->xul = 0; /* Upper left x-position */\r
+ hdrp->yul = 0; /* Upper left y-position */\r
+ hdrp->reserved = 0; /* (Used to be video mode) */\r
+ hdrp->palette_type = 1; /* Color or b&w palette type */\r
+\r
+ memset(hdrp->filler, 0, sizeof(hdrp->filler)); /* Padding */\r
+\r
+ /* Initialize the video mode-dependent parameters */\r
+\r
+ switch (vmode)\r
+ {\r
+ case PCX_HERC: /* 720 x 348 Hercules monochrome */\r
+\r
+ max_width = min(width, 720); /* Maximum image width */\r
+ max_height = min(height, 348); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 720; /* Horizontal resolution */\r
+ hdrp->vert_res = 348; /* Vertical resolution */\r
+ hdrp->nplanes = 1; /* Number of color planes */\r
+\r
+ /* Maximum two pages supported */\r
+\r
+ wbp->page_offset = 0x08000000L * (unsigned long) page;\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_herc; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x04: /* 320 x 200 4-color CGA */\r
+ case 0x05: /* 320 x 200 4-color CGA (color burst off) */\r
+\r
+ max_width = min(width, 320); /* Maximum image width */\r
+ max_height = min(height, 200); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 2; /* Bits per pixel */\r
+ hdrp->horz_res = 320; /* Horizontal resolution */\r
+ hdrp->vert_res = 200; /* Vertical resolution */\r
+ hdrp->nplanes = 1; /* Number of color planes */\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 3) >> 2;\r
+\r
+ shift = (max_width & 3) << 1; /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_cga; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x06: /* 640 x 200 2-color CGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 200); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 200; /* Vertical resolution */\r
+ hdrp->nplanes = 1; /* Number of color planes */\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_cga; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x0d: /* 320 x 200 16-color EGA/VGA */\r
+\r
+ max_width = min(width, 320); /* Maximum image width */\r
+ max_height = min(height, 200); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 320; /* Horizontal resolution */\r
+ hdrp->vert_res = 200; /* Vertical resolution */\r
+ hdrp->nplanes = 4; /* Number of color planes */\r
+\r
+ /* Maximum eight display pages supported */\r
+\r
+ wbp->page_offset = 0x02000000L * (unsigned long) page;\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x0e: /* 640 x 200 16-color EGA/VGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 200); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 200; /* Vertical resolution */\r
+ hdrp->nplanes = 4; /* Number of color planes */\r
+\r
+ /* Maximum four display pages supported */\r
+\r
+ wbp->page_offset = 0x04000000L * (unsigned long) page;\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x0f: /* 640 x 350 2-color EGA/VGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 350); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 350; /* Vertical resolution */\r
+ hdrp->nplanes = 2; /* Number of color planes */\r
+\r
+ /* Maximum two display pages supported */\r
+\r
+ wbp->page_offset = 0x08000000L * (unsigned long) page;\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x10: /* 640 x 350 16-color EGA/VGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 350); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 350; /* Vertical resolution */\r
+ hdrp->nplanes = 4; /* Number of color planes */\r
+\r
+ /* Maximum two display pages supported */\r
+\r
+ wbp->page_offset = 0x08000000L * (unsigned long) page;\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x11: /* 640 x 480 2-color VGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 480); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 480; /* Vertical resolution */\r
+ hdrp->nplanes = 1; /* Number of color planes */\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x12: /* 640 x 480 16-color VGA */\r
+\r
+ max_width = min(width, 640); /* Maximum image width */\r
+ max_height = min(height, 480); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 1; /* Bits per pixel */\r
+ hdrp->horz_res = 640; /* Horizontal resolution */\r
+ hdrp->vert_res = 480; /* Vertical resolution */\r
+ hdrp->nplanes = 4; /* Number of color planes */\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = (max_width + 7) >> 3;\r
+\r
+ shift = (max_width & 7); /* Calculate mask shift value */\r
+\r
+ wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ case 0x13: /* 320 x 200 256-color VGA */\r
+\r
+ max_width = min(width, 320); /* Maximum image width */\r
+ max_height = min(height, 200); /* Maximum image height */\r
+\r
+ hdrp->bppixel = 8; /* Bits per pixel */\r
+ hdrp->horz_res = 320; /* Horizontal resolution */\r
+ hdrp->vert_res = 200; /* Vertical resolution */\r
+ hdrp->nplanes = 1; /* Number of color planes */\r
+\r
+ /* Calculate number of bytes to copy */\r
+\r
+ wbp->num_bytes = max_width;\r
+\r
+ shift = 0; /* Dummy parameter */\r
+\r
+ wbp->pcx_funcp = pcx_get_vga; /* Set display capture fcn ptr */\r
+\r
+ break;\r
+\r
+ default: /* Other modes not supported */\r
+\r
+ status = FALSE;\r
+\r
+ break;\r
+ }\r
+\r
+ /* Initialize common video mode-dependent parameters */\r
+\r
+ hdrp->xlr = max_width - 1; /* Lower right x-position */\r
+ hdrp->ylr = max_height - 1; /* Lower right y-position */\r
+ hdrp->scrn_width = hdrp->horz_res; /* Screen width */\r
+ hdrp->scrn_height = hdrp->vert_res; /* Screen height */\r
+\r
+ /* Calculate mask for "white" data */\r
+\r
+ if (shift != 0)\r
+ wbp->mask = 0xff >> shift;\r
+ else\r
+ wbp->mask = 0x00;\r
+\r
+ /* Initialize the file header palette */\r
+\r
+ status = pcx_init_palette(hdrp->palette, vmode);\r
+\r
+ /* Calculate number of bytes per color plane scan line (must be an */\r
+ /* even number of bytes) */\r
+\r
+ hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2);\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_INIT_PALETTE - Initialize File Header Palette\r
+ *\r
+ * Purpose: To initialize the file header 16-color palette.\r
+ *\r
+ * Setup: static BOOL pcx_init_palette\r
+ * (\r
+ * PCX_PAL *palettep,\r
+ * int vmode\r
+ * )\r
+ *\r
+ * Where: palettep is a pointer to the PCX file header buffer\r
+ * "palette" member.\r
+ * vmode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * 0x04 - 320 x 200 4-color CGA\r
+ * 0x05 - 320 x 200 4-color CGA (color burst off)\r
+ * 0x06 - 640 x 200 2-color CGA\r
+ * Ox07 - 720 x 348 Hercules monochrome\r
+ * 0x0d - 320 x 200 16-color EGA/VGA\r
+ * 0x0e - 640 x 200 16-color EGA/VGA\r
+ * 0x0f - 640 x 350 2-color EGA/VGA\r
+ * 0x10 - 640 x 350 16-color EGA/VGA\r
+ * 0x11 - 640 x 480 2-color VGA\r
+ * 0x12 - 640 x 480 16-color VGA\r
+ * 0x13 - 320 x 200 256-color VGA\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Note: The CGA color palette is not supported.\r
+ *\r
+ * If a VGA display adapter is present, the color palette\r
+ * registers can be read directly from the adapter using the\r
+ * BIOS routine "Read All Palette Registers" (function 0x09).\r
+ *\r
+ * Unfortunately, the EGA display adapter color palette\r
+ * registers are write-only. This means that the current\r
+ * color palette for EGA displays cannot in general be read.\r
+ *\r
+ * The BIOS routine "Set All Palette Registers" (function\r
+ * 0x02) will write the current palette register values to a\r
+ * buffer called the Dynamic Save Area. The EGA color\r
+ * palette can be read from the first 16 bytes of this 256-\r
+ * byte RAM block.\r
+ *\r
+ * The Dynamic Save Area is not statically allocated; it must\r
+ * be supplied by the user. The BIOS video services data in\r
+ * segment 0x40 includes a pointer at address 0040:00a8 that\r
+ * references the Video Services Primary Pointer Table in the\r
+ * EGA/VGA BIOS. This table contains seven pointers, the\r
+ * second of which is used by the "Set All Palette Registers"\r
+ * routine to reference the Dynamic Save Area. Since the\r
+ * Dynamic Save Area does not exist at system initialization,\r
+ * the value of this pointer is 0000:0000 (in which case the\r
+ * the updated palette register values are not saved to RAM\r
+ * when they are updated).\r
+ *\r
+ * To utilize the EGA palette register save feature, the\r
+ * user must perform the following:\r
+ *\r
+ * 1. Save a copy of the pointer at address 0040:00a8.\r
+ * 2. Allocate a buffer for a new Primary Pointer Table.\r
+ * 3. Copy the existing Primary Pointer Table to the\r
+ * allocated buffer.\r
+ * 4. Allocate a 256-byte buffer for a Dynamic Save Area.\r
+ * 5. Initialize the second pointer of the Primary Pointer\r
+ * Table to point to the Dynamic Save Area buffer.\r
+ *\r
+ * Before the program finishes, the user must also restore\r
+ * the saved Primary Pointer Table pointer to address\r
+ * 0040:00a8. Failure to do so will mean that subsequent\r
+ * calls by other programs to the "Set All Palette\r
+ * Registers" routine will result in the color palette\r
+ * registers values being written to unallocated memory (or\r
+ * memory that has been allocated for another purpose).\r
+ *\r
+ * The function "pcx_init_dsa" performs the five steps\r
+ * outlined above, while the function "pcx_free_dsa" restores\r
+ * the saved pointer on completion of your program.\r
+ *\r
+ * If the Dynamic Save Area pointer is 0000:0000 (the default\r
+ * value at system initialization), the BIOS default color\r
+ * palette settings for the appropriate mode are stored in\r
+ * the file header color palette.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_init_palette\r
+(\r
+ PCX_PAL *palettep,\r
+ int vmode\r
+)\r
+{\r
+ int i; /* Scratch counter */\r
+ int val; /* Current palette register value */\r
+ int red; /* Temporary value */\r
+ int green; /* Temporary value */\r
+ int blue; /* Temporary value */\r
+ unsigned char *ega_palp; /* EGA/VGA palette buffer pointer */\r
+ unsigned char _far *dsap; /* Dynamic Save Area pointer */\r
+ union REGS regs; /* 80x86 register values */\r
+ struct SREGS sregs; /* 80x86 segment register values */\r
+\r
+ if (vmode < 0x0d || vmode > 0x12)\r
+ {\r
+ /* Clear the file header palette */\r
+\r
+ memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE);\r
+\r
+ return (TRUE);\r
+ }\r
+\r
+ /* Allocate a 16-color (plus border color) EGA/VGA palette buffer */\r
+\r
+ if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char), \r
+ (PCX_PAL_SIZE + 1))) == (unsigned char *) NULL)\r
+ return (FALSE);\r
+\r
+ if (pcx_isvga() == TRUE) /* Check for VGA display adapter */\r
+ {\r
+ /* Read the EGA/VGA palette registers */\r
+\r
+ regs.h.ah = 0x10; /* Select "Read All Palette Registers" routine */\r
+ regs.h.al = 0x09;\r
+\r
+ /* Get the EGA/VGA palette buffer offset value */\r
+\r
+ regs.x.dx = (unsigned int) ega_palp;\r
+\r
+ segread(&sregs); /* Get the current DS segment register value */\r
+\r
+ sregs.es = sregs.ds;\r
+\r
+ int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */\r
+ }\r
+ else\r
+ {\r
+ /* Check for a Dynamic Save Area buffer */\r
+\r
+ dsap = *(*((unsigned char _far * _far * _far *) 0x004000a8L) + 1);\r
+\r
+ if (dsap != (unsigned char _far *) NULL)\r
+ {\r
+ /* Copy the current palette into the local EGA/VGA palette buffer */\r
+\r
+ (void) _fmemcpy((unsigned char _far *) ega_palp, dsap,\r
+ PCX_PAL_SIZE);\r
+ }\r
+ else\r
+ {\r
+ /* Copy the appropriate default palette settings */\r
+\r
+ switch (vmode)\r
+ {\r
+ case 0x0d: /* 320 x 200 16-color EGA */\r
+ case 0x0e: /* 640 x 200 16-color EGA */\r
+\r
+ memcpy(ega_palp, pcx_EGA_DefPal_1, PCX_PAL_SIZE);\r
+\r
+ break;\r
+\r
+ case 0x0f: /* 640 x 350 2-color EGA */\r
+\r
+ memcpy(ega_palp, pcx_EGA_DefPal_2, PCX_PAL_SIZE);\r
+\r
+ break;\r
+\r
+ case 0x10: /* 640 x 350 16-color EGA */\r
+\r
+ memcpy(ega_palp, pcx_EGA_DefPal_3, PCX_PAL_SIZE);\r
+\r
+ break;\r
+\r
+ default: /* (Should never reach here) */\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* Map the EGA/VGA palette to the PCX file header palette */\r
+\r
+ for (i = 0; i < PCX_PAL_SIZE; i++)\r
+ {\r
+ val = (int) ega_palp[i]; /* Get current color palette value */\r
+\r
+ /* Extract color values */\r
+\r
+ red = ((val & 0x20) >> 5) | ((val & 0x04) >> 1);\r
+ green = ((val & 0x10) >> 4) | (val & 0x02);\r
+ blue = ((val & 0x08) >> 3) | ((val & 0x01) << 1);\r
+\r
+ /* Map each color to a 6-bit value. Only the top two bits are */\r
+ /* significant for EGA displays. The lower four bits (which */\r
+ /* repeat the top two bits) are significant when the image is */\r
+ /* presented on a VGA display emulating an EGA display. */\r
+\r
+ palettep[i].red = (BYTE) ((red << 6) | (red << 4) | (red << 2));\r
+ palettep[i].green = (BYTE) ((green << 6) | (green << 4) | (green <<\r
+ 2));\r
+ palettep[i].blue = (BYTE) ((blue << 6) | (blue << 4) | (blue << 2));\r
+ }\r
+ }\r
+\r
+ free(ega_palp); /* Free the EGA/VGA palette buffer */\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_WRITE_LINE - Write PCX Line\r
+ *\r
+ * Purpose: To write an image scan line to a PCX-format image file.\r
+ *\r
+ * Setup: static BOOL pcx_write_line\r
+ * (\r
+ * unsigned char *linep,\r
+ * int buflen,\r
+ * FILE *fp\r
+ * )\r
+ *\r
+ * Where: linep is a PCX scan line buffer pointer.\r
+ * buflen is the length of the image scan line buffer in\r
+ * bytes.\r
+ * fp is a file pointer.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ * Note: The PCX scan line buffer is assumed to contain the color\r
+ * plane scan lines in sequence, with padding for an even\r
+ * number of bytes and trailing "white" data for each line as\r
+ * appropriate.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_write_line\r
+(\r
+ unsigned char *linep,\r
+ int buflen,\r
+ FILE *fp\r
+)\r
+{\r
+ int curr_data; /* Current data byte */\r
+ int prev_data; /* Previous data byte */\r
+ int data_count; /* Data repeat count */\r
+ int line_count; /* Scan line byte count */\r
+\r
+ prev_data = *linep++; /* Initialize the previous data byte */\r
+ data_count = 1;\r
+ line_count = 1;\r
+\r
+ while (line_count < buflen) /* Encode scan line */\r
+ {\r
+ curr_data = *linep++; /* Get the current data byte */\r
+ line_count++; /* Increment the scan line counter */\r
+\r
+ if (curr_data == prev_data) /* Repeating data bytes ? */\r
+ {\r
+ data_count++; /* Increment the data repeat count */\r
+\r
+ /* Check for maximum allowable repeat count */\r
+\r
+ if (data_count == PCX_COMP_MASK)\r
+ {\r
+ /* Encode the data */\r
+\r
+ if (pcx_encode(prev_data, data_count, fp) == FALSE)\r
+ return (FALSE);\r
+\r
+ data_count = 0; /* Reset the data repeat count */\r
+ }\r
+ }\r
+ else /* End of repeating data bytes */\r
+ {\r
+ if (data_count > 0)\r
+ {\r
+ /* Encode the data */\r
+\r
+ if (pcx_encode(prev_data, data_count, fp) == FALSE)\r
+ return (FALSE);\r
+ }\r
+\r
+ prev_data = curr_data; /* Current data byte now previous */\r
+ data_count = 1;\r
+ }\r
+ }\r
+\r
+ if (data_count > 0) /* Any remaining data ? */\r
+ {\r
+ /* Encode the data */\r
+\r
+ if (pcx_encode(prev_data, data_count, fp) == FALSE)\r
+ return (FALSE);\r
+ }\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_ENCODE - Encode Byte Pair\r
+ *\r
+ * Purpose: To write an encoded byte pair (or a single unencoded\r
+ * byte) to a PCX-format image file.\r
+ *\r
+ * Setup: static BOOL pcx_encode\r
+ * (\r
+ * int data,\r
+ * int count,\r
+ * FILE *fp\r
+ * )\r
+ *\r
+ * Where: data is the data byte to be encoded (if necessary).\r
+ * count is the number of times the data byte is repeated in\r
+ * the image data.\r
+ * fp is a pointer to the PCX-format file the encoded byte\r
+ * pair or single byte is to be written to.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_encode\r
+(\r
+ int data,\r
+ int count,\r
+ FILE *fp\r
+)\r
+{\r
+ if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1)\r
+ {\r
+ /* Write the count byte */\r
+\r
+ if (putc(PCX_COMP_FLAG | count, fp) == EOF)\r
+ return (FALSE);\r
+ }\r
+\r
+ /* Write the data byte */\r
+\r
+ if (putc(data, fp) == EOF)\r
+ return (FALSE);\r
+\r
+ return (TRUE);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_WRITE_EXTPAL - Write Extended Palette\r
+ *\r
+ * Purpose: To read the current 256-color VGA palette and write an\r
+ * equivalent extended PCX palette to a PCX-format image\r
+ * file.\r
+ *\r
+ * Setup: static BOOL pcx_write_extpal\r
+ * (\r
+ * FILE *fp\r
+ * )\r
+ *\r
+ * Where: fp is a file pointer.\r
+ *\r
+ * Return: TRUE if successful; otherwise FALSE.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static BOOL pcx_write_extpal\r
+(\r
+ FILE *fp\r
+)\r
+{\r
+ int i; /* Scratch counter */\r
+ BOOL status = TRUE; /* Return status */\r
+ PCX_PAL *palettep; /* Extended PCX palette buffer pointer */\r
+ unsigned char *vga_palp; /* 256-color VGA palette buffer pointer */\r
+ union REGS regs; /* 80x86 register values */\r
+ struct SREGS sregs; /* 80x86 segment register values */\r
+\r
+ /* Allocate an extended PCX palette buffer */\r
+\r
+ if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) ==\r
+ (PCX_PAL *) NULL)\r
+ return (FALSE);\r
+\r
+ /* Allocate a 256-color VGA palette buffer */\r
+\r
+ if ((vga_palp = (unsigned char *) calloc(sizeof(unsigned char), 768))\r
+ == (unsigned char *) NULL)\r
+ {\r
+ free(palettep); /* Free the extended PCX palette buffer */\r
+ return (FALSE);\r
+ }\r
+\r
+ /* Read the current VGA palette (DAC registers) */\r
+\r
+ regs.h.ah = 0x10; /* Select "Read DAC Registers" BIOS routine */\r
+ regs.h.al = 0x17;\r
+ regs.x.bx = 0; /* Read all 256 DAC registers */\r
+ regs.x.cx = 256;\r
+ \r
+ /* Get the VGA palette buffer offset value */\r
+\r
+ regs.x.dx = (unsigned int) vga_palp;\r
+\r
+ segread(&sregs); /* Get the current DS segment register value */\r
+\r
+ sregs.es = sregs.ds;\r
+\r
+ int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */\r
+\r
+ /* Map the VGA palette to an extended PCX palette */\r
+\r
+ for (i = 0; i < PCX_EPAL_SIZE; i++)\r
+ {\r
+ palettep[i].red = (BYTE) (vga_palp[i * 3] << 2);\r
+ palettep[i].green = (BYTE) (vga_palp[i * 3 + 1] << 2);\r
+ palettep[i].blue = (BYTE) (vga_palp[i * 3 + 2] << 2);\r
+ }\r
+\r
+ /* Write the extended PCX palette indicator byte to the file */\r
+\r
+ if (status == TRUE)\r
+ if (fputc(PCX_EPAL_FLAG, fp) == EOF)\r
+ status = FALSE;\r
+\r
+ /* Write the extended PCX palette to the file */\r
+\r
+ if (status == TRUE)\r
+ if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=\r
+ PCX_EPAL_SIZE)\r
+ status = FALSE;\r
+\r
+ free(palettep); /* Free the extended PCX palette buffer */\r
+\r
+ free(vga_palp); /* Free the VGA palette buffer */\r
+\r
+ return (status);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_GET_HERC - Get Hercules Scan Line\r
+ *\r
+ * Purpose: To read a Hercules monochrome graphics display adapter\r
+ * scan line into a buffer.\r
+ *\r
+ * Setup: static void pcx_get_herc\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * linep is a pointer to where the scan line is to be\r
+ * returned.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_get_herc\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate Hercules display buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +\r
+ ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);\r
+\r
+ /* Copy data from the Hercules display buffer to the scan line buffer */\r
+\r
+ (void) _fmemcpy(linep, displayp, wbp->num_bytes);\r
+\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] |= wbp->mask;\r
+\r
+ /* Pad scan line with "white" data byte (if necessary) */\r
+\r
+ if (wbp->num_bytes & 1)\r
+ linep[wbp->num_bytes] = 0xff;\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_GET_CGA - Get CGA Scan Line\r
+ *\r
+ * Purpose: To read a CGA display adapter scan line into a buffer.\r
+ *\r
+ * Setup: static void pcx_get_cga\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * linep is a pointer to where the scan line is to be\r
+ * returned.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_get_cga\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate CGA display buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)\r
+ + 0x2000 * (line_num & 1);\r
+\r
+ /* Copy data from the CGA display buffer to the scan line buffer */\r
+\r
+ (void) _fmemcpy(linep, displayp, wbp->num_bytes);\r
+\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] |= wbp->mask;\r
+\r
+ /* Pad scan line with "white" data byte (if necessary) */\r
+\r
+ if (wbp->num_bytes & 1)\r
+ linep[wbp->num_bytes] = 0xff;\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_GET_EGA - Get EGA/VGA Scan Line\r
+ *\r
+ * Purpose: To read an EGA/VGA display adapter scan line into a\r
+ * buffer.\r
+ *\r
+ * Setup: static void pcx_get_ega\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * linep is a pointer to where the scan line is to be\r
+ * returned.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_get_ega\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ int plane_num; /* EGA/VGA color plane number */\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +\r
+ line_num * 80;\r
+\r
+ /* Copy PCX scan line data from each color plane */\r
+\r
+ for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)\r
+ {\r
+ /* Select the current color plane in EGA/VGA Read Mode 0 */\r
+\r
+ outpw(0x03ce, (plane_num << 8) | 0x04);\r
+\r
+ /* Copy data from the EGA/VGA display to the scan line buffer */\r
+\r
+ (void) _fmemcpy(linep, displayp, wbp->num_bytes);\r
+\r
+ /* Mask off unseen pixels */\r
+\r
+ linep[wbp->num_bytes - 1] |= wbp->mask;\r
+\r
+ /* Pad plane scan line with "white" data byte (if necessary) */\r
+\r
+ if (wbp->num_bytes & 1)\r
+ linep[wbp->num_bytes] = 0xff;\r
+\r
+ linep += wbp->header.bppscan; /* Increment plane offset */\r
+ }\r
+\r
+ /* Select EGA/VGA Write Mode 0 with all color planes enabled */\r
+\r
+ outpw(0x03c4, 0x0f02);\r
+}\r
+\f\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * PCX_GET_VGA - Get VGA Scan Line\r
+ *\r
+ * Purpose: To read a VGA display adapter scan line into a buffer.\r
+ *\r
+ * Setup: static void pcx_get_vga\r
+ * (\r
+ * PCX_WORKBLK *wbp,\r
+ * unsigned char _far *linep,\r
+ * int line_num\r
+ * )\r
+ *\r
+ * Where: wbp is a PCX workblock pointer.\r
+ * linep is a pointer to where the scan line is to be\r
+ * returned.\r
+ * line_num is the scan line number.\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+static void pcx_get_vga\r
+(\r
+ PCX_WORKBLK *wbp,\r
+ unsigned char _far *linep,\r
+ int line_num\r
+)\r
+{\r
+ unsigned char _far *displayp; /* Display buffer pointer */\r
+\r
+ /* Calculate buffer pointer */\r
+\r
+ displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;\r
+\r
+ /* Copy data from the VGA display buffer to the scan line buffer */\r
+\r
+ (void) _fmemcpy(linep, displayp, wbp->num_bytes);\r
+\r
+ /* Pad scan line with "white" data byte (if necessary) */\r
+\r
+ if (wbp->num_bytes & 1)\r
+ linep[wbp->num_bytes] = 0xff;\r
+}\r
+\r
--- /dev/null
+\r
+\r
+Ian Ashdown\r
+byHeart Software\r
+620 Ballantree Road\r
+West Vancouver, B.C.\r
+Canada V7S 1W3\r
+\r
+Issue 1: 91/02/12\r
+Issue 2: 91/03/27\r
+Issue 3: 91/08/08\r
+Issue 4: 91/08/11\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ PCX Graphics\r
+\r
+ by \r
+\r
+ Ian Ashdown\r
+ byHeart Software\r
+\f\r
+Looking to add monochrome or full-color bit-mapped graphics to your \r
+application programs? If so, you might consider the PCX graphics file \r
+format. Originally developed in 1982 by ZSoft Corporation for their PC \r
+Paintbrush (R) products, it has become a de facto industry standard for \r
+storing and transferring bit-mapped images on MS-DOS machines. It can \r
+support displays of any resolution using palettes of up to 256 \r
+simultaneous colors, and is very simple to implement. Furthermore, it's \r
+not limited to MS-DOS and OS/2-based machines; the PCX format is \r
+applicable to any environment supporting bit-mapped graphics. \r
+\r
+Today, more commercial programs support ZSoft's PCX format than any \r
+other, including Aldus-Microsoft's Tag Image File Format (TIFF). \r
+However, unlike TIFF with its publicly-available technical \r
+specifications, the PCX file format has never been completely documented. \r
+When ZSoft first created PC Paintbrush, the only video displays they had \r
+to contend with were two monochrome adapters (Hercules and Tecmar) and \r
+the IBM Color Graphics Adapter (CGA). They have since quietly modified \r
+and extended their format on several occasions to support EGA, VGA and \r
+SuperVGA displays. Documentation is scarce, incomplete and sometimes \r
+contradictory. There's a small booklet available from ZSoft that \r
+describes the current version (with several omissions), a sample Pascal \r
+program from their CompuServe forum (GO WINAPB), a few magazine articles, \r
+and chapters in a few books (see the references at the end of this \r
+article). \r
+\r
+Personally, I think it's about time to remedy this situation. The \r
+following is a complete set of technical specifications for the current \r
+version of PCX. All of the information has been derived from printed \r
+information provided by ZSoft and conversations with their Technical \r
+Services department. This is it, folks! We now have formal (if not \r
+exactly official) specifications to work with when including the PCX \r
+graphics file format in our application programs. \r
+\r
+My original plan was to include sample C source code for reading and \r
+writing PCX image files. However, both this article and the source code \r
+grew to the extent that one had to go. If you don't want to develop your \r
+own PCX file handling routines from scratch, PCX_LIB is available through \r
+the CUG Library as CUG Volume #???. It includes fully commented C source \r
+code for reading and writing PCX image files, complete with software \r
+drivers for Hercules, CGA, EGA, and VGA display adapters.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 1\r
+\f\r
+PCX Specifications \r
+\r
+The PCX graphics file format (Version 5) is designed to store monochrome \r
+and color bit-mapped images of any resolution with palettes of up to 256 \r
+simultaneous colors. It was originally designed for MS-DOS \r
+microcomputers, but is adaptable to other bit-mapped graphic \r
+environments. A simple but effective byte-oriented, run-length encoding \r
+scheme is used to compress the image data.\r
+\r
+There are two or three sections to a PCX graphics file - a 128-byte \r
+header, the encoded image data (which can be of any length) and an \r
+optional 256-color palette (see Figure 1). This palette is appended to \r
+the file only if the image contains more than 16 colors. \r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 2\r
+\f\r
+1. PCX File Header\r
+\r
+The file header describes the graphical environment in which the image is \r
+to be displayed. The information contained in the header is somewhat \r
+device-dependent in that the PCX file format implicitly assumes the \r
+presence of a standard IBM PC-compatible display adapter. Furthermore, \r
+the specific type and video mode of the adapter needed to display the \r
+image correctly cannot be uniquely determined from the file header \r
+information. It is in general the user's responsibility to ensure that \r
+the correct video mode has been selected before displaying a PCX image. \r
+\r
+The file header structure is shown in Figure 2. A complete description \r
+of each structure member is as follows: \r
+\r
+1.1 PCX Flag\r
+\r
+A constant value (0x0a) that signifies a PCX image file. \r
+\r
+1.2 Version\r
+\r
+Indicates the PCX file format version. It can be one of five values: \r
+\r
+ 0 - Version 2.5 of PC Paintbrush.\r
+ 2 - Version 2.8 (with palette information).\r
+ 3 - Version 2.8 (without palette information).\r
+ 4 - PC Paintbrush for Windows (not 3.0).\r
+ 5 - Version 3.0 and greater of PC Paintbrush and Paintbrush Plus, \r
+ including Publisher's Paintbrush. \r
+\r
+Most commercial programs supporting the PCX file format conform to \r
+Version 5. See Section 3, "Color Palettes", for further information. \r
+\r
+1.3 Encoding (1)\r
+\r
+A constant value (0x01) that indicates run-length encoding was used to \r
+encode and compress the image data. \r
+\r
+1.4 Bits per Pixel\r
+\r
+The number of bits per pixel per color plane (typically 1, 2, 4 or 8). \r
+\r
+1.5 Window\r
+\r
+A structure with the following members: \r
+\r
+ Name Bytes Description\r
+\r
+ xul 2 Upper left corner horizontal position\r
+ yul 2 Upper left corner vertical position\r
+ xlr 2 Lower right corner horizontal position\r
+ ylr 2 Lower right corner vertical position\r
+\r
+These members describe the position and size of the image within the \r
+display, and are measured in pixels (starting with zero). \r
+\r
+\r
+\r
+\r
+\r
+ p. 3\r
+\f\r
+1.6 HDPI (2)\r
+\r
+"Horizontal dots per inch". The value represents the horizontal \r
+resolution of the device used to create the image. \r
+\r
+1.7 VDPI (2)\r
+\r
+"Vertical dots per inch". The value represents the vertical resolution \r
+of the device used to create the image. \r
+\r
+1.8 Color Map\r
+\r
+The color palette to be used when displaying an image with 16 or fewer \r
+colors. See Section 3, "Color Palettes", for further information. \r
+\r
+1.9 Reserved\r
+\r
+This member was used to indicate the appropriate MS-DOS video mode in \r
+previous PCX file format versions. It is ignored in Version 5, but\r
+should be set to zero.\r
+\r
+1.10 NPlanes\r
+\r
+The number of color planes used to display the image (typically 1 or 4). \r
+See Section 3, "Color Palettes", for further information. \r
+\r
+1.11 Bytes per Line\r
+\r
+The number of bytes required for a buffer when decoding one color plane \r
+scan line. This value should be an even number (for compatibility with \r
+some existing commercial programs). See Section 2, "Image Encoding and \r
+Decoding", for further information. \r
+\r
+1.12 Palette Info (3)\r
+\r
+A bit-mapped variable indicating how to interpret the color palette. \r
+Only the lowest two bits are significant; the others are ignored. It \r
+can have one of two possible values: \r
+\r
+ 0x01 - color or black & white\r
+ 0x02 - grayscale\r
+\r
+If the variable is set to 0x02 (grayscale), the color palette must be set \r
+to shades of gray. \r
+\r
+1.13 HScreen Size (4)\r
+\r
+Horizontal screen size in pixels.\r
+\r
+1.14 VScreen Size (4)\r
+\r
+Vertical screen size in pixels.\r
+\r
+1.15 Filler\r
+\r
+Blank space to fill out 128-byte header. All bytes within this member \r
+should be set to zero. \r
+\r
+\r
+ p. 4\r
+\f\r
+Notes\r
+\r
+1. ZSoft has reserved the right to change the encoding scheme for better \r
+ image compression performance in future versions. \r
+\r
+2. Horizontal and vertical resolution for video display adapters is \r
+ defined as the total number of displayed pixels for the current video \r
+ mode. For scanners, it is defined in terms of dots per inch. (These \r
+ values are provided for information only. They are not required for \r
+ encoding or decoding PCX image files.) \r
+\r
+3. The "palette info" member of the file header was used in previous \r
+ versions of the PCX file format to indicate whether the palette \r
+ represented a color or grayscale palette. If it was set to 0x02 (as a \r
+ bitmap - the upper 6 bits could be set at random), the file decoding \r
+ functions could assume a default grayscale palette if necessary. \r
+ However, the palette already had a true (and possibly nonlinear) \r
+ grayscale, so the "palette info" member was never really used by \r
+ ZSoft. The current PC Paintbrush IV and IV Plus products simply \r
+ ignore it. \r
+\r
+4. The "HScreen Size" and "VScreen Size" members were added to Version 5 \r
+ of the PCX format to support PC Paintbrush IV Version 1.02 and IV Plus \r
+ Version 1.0. Since earlier Version 5 PCX files may contain \r
+ uninitialized data in place of these members, ZSoft specifically \r
+ recommends that they not be used to determine the appropriate video \r
+ mode for displaying the files.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 5\r
+\f\r
+2. Image Encoding and Decoding \r
+\r
+The PCX graphics file format considers an image to be a contiguous \r
+sequence (block) of eight-bit bytes representing a bit-mapped raster \r
+display. A simple byte-oriented, run-length encoding (RLE) scheme is\r
+used to compress the display data. When the display is represented by\r
+more than one color plane (such as color images on EGA displays), each\r
+scan line is stored sequentially by color plane. \r
+\r
+The run-length encoding scheme uses a byte pair consisting of a "count" \r
+byte and a following "data" byte to represent sequences of display bytes \r
+with the same value. A count byte is uniquely identified by having its \r
+two most significant bits set; its six least significant bits are used to \r
+represent the count value (1 to 63). The following data byte is the \r
+value that is repeated in the display data the number of times indicated \r
+by the count value. \r
+\r
+Any display data byte which is not part of a sequence of bytes of the \r
+same value and which does not have its two most significant bits set is \r
+stored as itself in the encoded image data. Single display data bytes \r
+with a value of 0xc0 or greater are encoded with a count value of one. \r
+\r
+2.1. Decoding\r
+\r
+Decoding display data from encoded image data is done on a line-by-line \r
+basis. The pixel dimensions of the displayed image are calculated as: \r
+\r
+ horz_size = Window.xlr - Window.xul + 1\r
+\r
+and\r
+\r
+ vert_size = Window.ylr - Window.yul + 1\r
+\r
+The number of bytes required to buffer one complete scan line for all \r
+color planes in sequence is: \r
+\r
+ buffer_size = NPlanes * Bytes per Line\r
+\r
+Since there are always an integral number of bytes in the buffer, there \r
+may be unused data at the end of each color plane scan line if the number \r
+of bits per pixel is other than eight. This unused data should be masked \r
+off when transferring the line buffer contents to the video display \r
+adapter memory. \r
+\r
+In theory, each color plane scan line may contain an even or odd number \r
+of bytes. However, some application programs expect an even number of \r
+bytes. ZSoft ensures that their products create PCX files with an even \r
+number of bytes per color plane scan line, and recommends that other \r
+programs do the same for compatibility. Of course, decoding functions \r
+should be able to read files with either an even or odd number of bytes \r
+per color plane scan line. \r
+\r
+Decoding begins with the first scan line and proceeds by examining each \r
+byte of the encoded image data. If the two most significant bits of the \r
+byte are set, the lower six bits indicate how many times the next byte is \r
+\r
+\r
+\r
+\r
+ p. 6\r
+\f\r
+Decoding begins with the first scan line and proceeds by examining each \r
+byte of the encoded image data. If the two most significant bits of the \r
+byte are set, the lower six bits indicate how many times the next byte is \r
+to be duplicated in the line buffer. If these two bits are not set, the \r
+byte itself is copied (once) to the line buffer. A count is kept of the \r
+number of bytes in the line buffer. The current scan line is complete \r
+when its value equals "buffer_size". \r
+\r
+If the display contains more than one color plane, each plane is decoded \r
+in sequence. The order in which they are decoded is device-dependent. \r
+For instance, the Enhanced Graphics Adapter has four color planes ordered \r
+as blue, green, red and intensity. The beginning of each color plane \r
+scan line within the line buffer is given by: \r
+\r
+ offset = plane_number * Bytes per Line\r
+\r
+where "plane_number" is a number between 0 and NPlanes - 1. \r
+\r
+A decoding break occurs at the end of each scan line. That is, an \r
+encoding byte pair can only represent a contiguous sequence of bytes \r
+within the current scan line. However, this is not necessarily true for \r
+color planes. An encoding byte pair may represent a contiguous sequence \r
+of identical bytes that extends across two color planes for one display \r
+image scan line. \r
+\r
+Decoding continues until all scan lines (as indicated by "vert_size") \r
+have been decoded. Some older versions of PC Paintbrush padded the image \r
+with extra (uninitialized) scan lines so that all blocks of scan lines (8 \r
+or 16 lines) read from the file were the same size. The image data was \r
+read until end-of-file was returned. ZSoft no longer uses this \r
+technique, since it conflicts with the appended color palette (see \r
+Subsection 3.3, "VGA 256-Color Palettes"). The extra data read could \r
+also overrun the user's image buffer. \r
+\r
+A sample C function to decode a complete image scan line (all color planes)\r
+from a PCX file is shown in Figure 3. \r
+\r
+2.2. Encoding\r
+\r
+Encoding display image data is also done on a line-by-line basis, \r
+following the order of scan lines stored in the display adapter's memory \r
+buffer. The current scan line is encoded for each color plane on a per-\r
+byte basis. As noted above, ZSoft recommends that all color plane scan \r
+lines be padded if necessary to ensure they contain an even number of \r
+bytes. \r
+\r
+ZSoft also recommends that the data used to pad the last one or two bytes \r
+of a scan line represent white data. Apparently, some application \r
+programs display this data when printing or faxing the files.\r
+\r
+A sample C function to encode a single monochrome or color image scan \r
+line for a PCX file is shown in Figure 4.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 7\r
+\f\r
+3. Color Palettes \r
+\r
+The PCX file format supports color palettes of up to 16 colors in the \r
+file header. Larger palettes (up to a maximum of 256 colors) are stored \r
+in an optional color palette that is appended to the encoded image data \r
+portion of the file. \r
+\r
+The file header color palette has two different formats, both designed \r
+for IBM PC-compatible machines. A device-specific palette is used for \r
+Color Graphics Adapters (CGA), and a standard R-G-B palette is used for \r
+Enhanced Graphics Adapters (EGA), Multicolor Graphics Adapters (MCGA), \r
+Video Graphics Adapters (VGA) and extended Video Graphics Adapters \r
+(SuperVGA). \r
+\r
+ZSoft's PC Paintbrush products no longer support the CGA color palette. \r
+The following information is provided only for compatibility with older \r
+PCX files. \r
+\r
+3.1. CGA Color Palettes\r
+\r
+The PCX format supports eight possible CGA color palettes for video modes \r
+4 (320x200 4-color graphics) and 5 (320x200 monochrome graphics, color \r
+burst off). Each palette consists of a background color and three \r
+foreground colors (or shades of grey). The background can be one of 16 \r
+colors, the value for which is stored in the first byte of the PCX file \r
+header Color Map member. Only the upper four bits are significant; the \r
+value must be right-shifted by four bits (or divided by 16) to determine \r
+the appropriate CGA hardware palette register value. \r
+\r
+The foreground color palette is specified by the fourth byte of the Color \r
+Map, which has the following structure: \r
+\r
+ Name Bit Description\r
+\r
+ Color Burst Enable 7 0 - color\r
+ 1 - monochrome\r
+ Palette 6 0 - yellow\r
+ 1 - white\r
+ Intensity 5 0 - dim\r
+ 1 - bright\r
+\r
+The lower five bits are ignored. \r
+\r
+Most published descriptions of the ROM BIOS call "Set CGA Palette" \r
+(Interrupt 16, Function 11) document only two palettes, obtainable by \r
+setting register BL to 0x00 or 0x01. This is equivalent to the "Palette" \r
+bit above. However, the palette intensity (equivalent to the "Intensity" \r
+bit above) can be selected using bit 4 of the BL register (0 = dim, 1 = \r
+bright). \r
+\r
+The original CGA display adapter was designed for use with NTSC composite \r
+video monitors and color televisions. The "color burst" is a periodic \r
+burst of a 3.58 MHz signal superimposed on the composite video signal to \r
+synchronize the phase of the monitor's internal 3.58 MHz oscillator. \r
+(Without synchronization, the picture has drifting color bars.) The \r
+presence or absence of the burst determines whether the image is \r
+displayed in color or monochrome. \r
+\r
+\r
+ p. 8\r
+\f\r
+The "Color Burst Enable" bit above actually indicates whether the MS-DOS \r
+video mode is to be 4 (color) or 5 (monochrome). However, the color \r
+burst signal has no meaning for RGB monitors. Video mode 5 will produce \r
+only two distinct color palettes on CGA displays adapters with RGB \r
+monitors, and three distinct palettes on EGA, VGA and SuperVGA display \r
+adapters emulating a CGA display. \r
+\r
+Under video mode 6 (640 x 200 2-color graphics), the first byte of the\r
+CGA color palette specifies the foreground color (i.e. - the color of\r
+the displayed pixels).\r
+\r
+3.2. EGA/VGA 16-Color Palettes\r
+\r
+The 16-color palette for EGA, MCGA, VGA and SuperVGA displays is an array \r
+of 16 elements, each a structure with the following members: \r
+\r
+ Name Bytes Description\r
+\r
+ Red 1 Red intensity\r
+ Green 1 Green intensity\r
+ Blue 1 Blue intensity\r
+\r
+All color map entries are stored as unsigned bytes with values ranging \r
+between 0 and 255. Where display adapters support fewer intensity \r
+levels, the value of each color map entry is interpreted by dividing its \r
+value by 256/n, where n is the number of allowable intensity levels \r
+(typically 2, 4 or 16). \r
+\r
+3.3. VGA 256-Color Palettes\r
+\r
+The 256-color palette for MCGA, VGA and SuperVGA displays is an array of \r
+256 elements, each a structure with the same members as the EGA/VGA 16-\r
+color palette, which is appended to the encoded image data portion of the \r
+file (see Figure 1). It is always preceded by a constant byte flag with\r
+the value 0x0c (12 decimal). \r
+\r
+Only Version 5 PCX-format files support 256-color palettes, and then only \r
+when the image has more than 16 colors. ZSoft recommends the following \r
+technique to determine if a 256-color palette is present: first verify \r
+that the file version number is 5, then count back 769 bytes from the end \r
+of the file. If the value of this byte is not 0x0c, the optional 256-\r
+color palette is not present and the EGA/VGA 16-color file header palette \r
+should be used. \r
+\r
+It is possible that a Version 5 PCX-format file with a valid file header \r
+palette can have the value 0x0c in the 769th byte from the end of the \r
+encoded image data. The above technique would then falsely indicate the\r
+presence of an appended 256-color palette. To avoid this problem, it is \r
+necessary to first decode the image and note the file position where the \r
+encoded image data section ends before counting back 769 bytes from the \r
+end of the file. If the supposed 256-color palette flag is located in \r
+the image data section, then the file header palette should be used \r
+instead.\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 9\r
+\f\r
+3.4. 24-Bit Color \r
+\r
+Future versions of ZSoft's Publisher's Paintbrush will support up to 16.7 \r
+million simultaneous colors. The PCX file format will be based on three \r
+color planes (red, green and blue), with 8 bits per pixel per plane. \r
+There will be no color palette, since the color of each pixel will be \r
+fully specified by the encoded image data. \r
+\r
+3.5. Disabling the Palette \r
+\r
+It is occasionally necessary to disable the color palette of a PCX file \r
+in order to correctly display the image. In other words, the current \r
+(default) setting of the display adapter's palette registers are used. \r
+This can be done by changing the PCX file version number from '5' to '3' \r
+(i.e. - PC Paintbrush Version 2.8 without palette information). The file \r
+decoding functions must then check the file version number and ignore the \r
+color palette if it is set to '3'.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 10\r
+\f\r
+4. Other Environments \r
+\r
+While the PCX file format was designed for MS-DOS machines, it is \r
+nevertheless possible to display PCX images on other machines. It will \r
+generally be necessary to map the image representation (i.e. - window \r
+dimensions, number of color planes, bits per pixel per plane, and the \r
+color palette) to the capabilities of the display hardware. \r
+\r
+It is also necessary to remember that all information in a PCX-format \r
+file is stored as either 8-bit bytes or 16-bit words. Words are stored \r
+in the big-endian format characteristic of 80x86-based machines. That \r
+is, the eight least significant bits (lower byte) are stored first, \r
+followed by the eight most significant bits (upper byte). If PCX-format \r
+files are transferred to little-endian machines (such as those based on \r
+680x0 and Z8000 processors), the order of bytes within each word will \r
+have to be reversed before they can be interpreted. (This applies to the \r
+file header only, since the encoded image data and optional 256-color \r
+palette are stored as bytes.)\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 11\r
+\f\r
+References \r
+\r
+Azer, S. [1988]. "Working With PCX Files", Microcornucopia, No. 42 \r
+(July-August), p. 42.\r
+\r
+Lindley, C.A. [1990]. Practical Image Processing in C, John Wiley & Sons \r
+Inc., New York, N.Y.\r
+\r
+Luze, M. [1991]. "Printing PCX Files", C Gazette, Vol. 5:2 (Winter 1990 -\r
+1991), pp. 11-22.\r
+\r
+Phoenix Technologies Ltd. [1989]. System BIOS for IBM PC/XT/AT Computers \r
+and Compatibles, Addison-Wesley, Reading, MA.\r
+\r
+Quirk, K. [1989]. "Translating PCX Files", Dr. Dobb's Journal, Vol. 14:8 \r
+(August), pp. 30-36, 105-108.\r
+\r
+Rimmer, S. [1990]. Bit-Mapped Graphics, Windcrest Books, Blue Ridge \r
+Summit, PA.\r
+\r
+ZSoft Corporation [1988]. PCX Technical Reference Manual Revision 4,\r
+ZSoft Corporation, Marietta, GA.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 12\r
+\f\r
+Figures\r
+\r
++--------------------------------------------+\r
+| File Header (128 bytes) |\r
++--------------------------------------------+\r
+| Encoded Image Data (variable length) |\r
++--------------------------------------------+\r
+| Optional Color Palette (769 bytes) |\r
++--------------------------------------------+\r
+\r
+Figure 1 - Basic PCX File Format\r
+\r
+\r
+Name Bytes Description \r
+\r
+PCX Flag 1 Constant flag\r
+Version 1 PCX version number\r
+Encoding 1 Run-length encoding flag\r
+Bits per Pixel 1 Number of bits per pixel per plane\r
+Window 8 Window dimensions\r
+HDPI 2 Horizontal image resolution\r
+VDPI 2 Vertical image resolution\r
+Color Map 48 Hardware R-G-B color palette\r
+Reserved 1 (Used to contain video mode)\r
+NPlanes 1 Number of color planes\r
+Bytes per Line 2 Number of bytes per scan line\r
+Palette Info 2 Palette interpretation\r
+HScreen Size 2 Horizontal screen size\r
+VScreen Size 2 Vertical screen size\r
+Filler 54 Initialized filler bytes\r
+\r
+Figure 2 - PCX File Header Structure\r
+\r
+\r
+/* Read an encoded scan line (all color planes) from a */\r
+/* PCX-format image file and write the decoded data to a scan */\r
+/* line buffer */\r
+\r
+void pcx_read_line\r
+(\r
+ unsigned char *linep, /* PCX scan line buffer pointer */\r
+ FILE *fp, /* PCX image file pointer */\r
+ int bpline /* # bytes per line (all color planes) */\r
+)\r
+{\r
+ int data; /* Image data byte */\r
+ int count; /* Image data byte repeat count */\r
+ int offset = 0; /* Scan line buffer offset */\r
+\r
+ while (offset < bpline) /* Decode current scan line */\r
+ {\r
+ data = getc(fp); /* Get next byte */\r
+\r
+ /* If top two bits of byte are set, lower six bits show how */\r
+ /* many times to duplicate next byte */\r
+\r
+\r
+\r
+\r
+ p. 13\r
+\f\r
+ if ((data & 0xc0) == 0xc0)\r
+ {\r
+ count = data & 0x3f; /* Mask off repeat count */\r
+ data = getc(fp); /* Get next byte */\r
+ memset(linep, data, count); /* Duplicate byte */\r
+ linep += count;\r
+ offset += count;\r
+ }\r
+ else\r
+ {\r
+ *linep++ = (unsigned char) data; /* Copy byte */\r
+ offset++;\r
+ }\r
+ }\r
+}\r
+\r
+Figure 3 - Decode PCX Image File Scan Line Function\r
+\r
+\r
+/* Encode a scan line and write it to a PCX file (the line is */\r
+/* assumed to contain the color plane scan lines in sequence, */\r
+/* with padding for an even number of bytes and trailing white */\r
+/* data for each line as appropriate) */\r
+\r
+void pcx_write_line\r
+(\r
+ unsigned char *linep, /* Scan line buffer pointer */\r
+ int length, /* Scan line buffer length (in bytes) */\r
+ FILE *fp /* PCX file pointer */\r
+)\r
+{\r
+ int curr_data; /* Current data byte */\r
+ int prev_data; /* Previous data byte */\r
+ int data_count; /* Data repeat count */\r
+ int line_count; /* Scan line byte count */\r
+\r
+ prev_data = *linep++; /* Initialize the previous data byte */\r
+ data_count = 1;\r
+ line_count = 1;\r
+\r
+ while (line_count < length) /* Encode scan line */\r
+ {\r
+ curr_data = *linep++; /* Get the current data byte */\r
+ line_count++; /* Increment line byte count */\r
+\r
+ if (curr_data == prev_data) /* Repeating data bytes ? */\r
+ {\r
+ data_count++; /* Increment data repeat count */\r
+\r
+ if (data_count == 0x3f) /* Max allowable repeat count ? */\r
+ {\r
+ pcx_encode(prev_data, data_count, fp); /* Encode data */\r
+ data_count = 0;\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+ p. 14\r
+\f\r
+ else /* End of repeating data bytes */\r
+ {\r
+ if (data_count > 0)\r
+ pcx_encode(prev_data, data_count, fp); /* Encode data */\r
+\r
+ prev_data = curr_data; /* Current data byte now prev */\r
+ data_count = 1;\r
+ }\r
+ }\r
+\r
+ if (data_count > 0) /* Any remaining data ? */\r
+ {\r
+ pcx_encode(prev_data, data_count, fp); /* Encode data */\r
+ }\r
+}\r
+\r
+\r
+/* Write an encoded byte pair (or single byte) to a file */\r
+\r
+void pcx_encode\r
+(\r
+ int data, /* Data byte */\r
+ int count, /* Data byte repeat count */\r
+ FILE *fp /* PCX file pointer */\r
+)\r
+{\r
+ if (((data & 0xc0) == 0xc0) || count > 1)\r
+ {\r
+ putc(0xc0 | count, fp); /* Write count byte */\r
+ }\r
+\r
+ putc(data, fp); /* Write data byte */\r
+}\r
+\r
+Figure 4 - Encode Image Scan Line Functions\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 15\r
+\r
--- /dev/null
+/* \r
+ *************************************************************************\r
+ *\r
+ * PCX_INT.H - PCX_LIB Library Internal Definitions Include File\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/07 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/* DEFINITIONS */\r
+\r
+#define _PCX_INT_H 1\r
+\r
+#ifndef _PCX_EXT_H\r
+#include "PCX_EXT.H" /* Get external PCX definitions, etc. */\r
+#endif\r
+\r
+#define PCX_HERC 0xff /* Hercules 720 x 348 monochrome mode */\r
+\r
+#define PCX_COMP_FLAG 0xc0 /* Compressed data flag mask */\r
+#define PCX_COMP_MASK 0x3f /* Data repeat count mask */\r
+\r
+#define PCX_PAL_MASK 0x03 /* Palette interpretation mask */\r
+#define PCX_EPAL_FLAG 0x0c /* Extended palette flag */\r
+\r
+#define PCX_PAL_SIZE 16 /* File header palette size */\r
+#define PCX_EPAL_SIZE 256 /* Extended palette size */\r
+\r
+#define PCX_MAXLINESZ 640 /* Maximum PCX line buffer size */\r
+\r
+/* Color graphics adapter color palette macros */\r
+\r
+#define PCX_CGA_BKGND(x) (x[0].red >> 4) /* Background color */\r
+#define PCX_CGA_BURST(x) (x[1].red & 0x80) /* Color burst */\r
+#define PCX_CGA_SELECT(x) (x[1].red & 0x40) /* Palette selector */\r
+#define PCX_CGA_INTENSITY(x) (x[1].red & 0x20) /* Intensity */\r
+\r
+typedef unsigned char BYTE; /* 8-bit data type */\r
+typedef unsigned int WORD; /* 16-bit data type */\r
+\f\r
+/* STRUCTURE DECLARATIONS */\r
+\r
+typedef struct pcx_pal /* PCX palette array element */\r
+{\r
+ BYTE red; /* Red intensity */\r
+ BYTE green; /* Green intensity */\r
+ BYTE blue; /* Blue intensity */\r
+}\r
+PCX_PAL;\r
+\r
+typedef struct pcx_hdr /* PCX file header (Version 5) */\r
+{\r
+ BYTE pcx_id; /* Always 0x0a for PCX files */\r
+ BYTE version; /* Version number */\r
+ BYTE encoding; /* 1 = PCX run length encoding */\r
+ BYTE bppixel; /* Number of bits/pixel per color plane */\r
+ WORD xul; /* X-position of upper left corner */\r
+ WORD yul; /* Y-position of upper left corner */\r
+ WORD xlr; /* X-position of lower right corner */\r
+ WORD ylr; /* Y-position of lower right corner */\r
+ WORD horz_res; /* Horizontal resolution */\r
+ WORD vert_res; /* Vertical resolution */\r
+ PCX_PAL palette[PCX_PAL_SIZE]; /* Hardware R-G-B palette */\r
+ BYTE reserved; /* Unused in Version 5 */\r
+ BYTE nplanes; /* Number of color planes */\r
+ WORD bppscan; /* Number of bytes per plane scan line */\r
+ WORD palette_type; /* Palette interpretation */\r
+ WORD scrn_width; /* Horizontal screen size in pixels */\r
+ WORD scrn_height; /* Vertical screen size in pixels */\r
+ BYTE filler[54]; /* Padding to fill out 128-byte header */\r
+\r
+ /* Notes: */\r
+ /* */\r
+ /* 1. The "version" member may be one of the following: */\r
+ /* */\r
+ /* 0 - PC Paintbrush Version 2.5 */\r
+ /* 2 - PC Paintbrush Version 2.8 (with palette information) */\r
+ /* 3 - PC Paintbrush Version 2.8 (w/o palette information) */\r
+ /* 4 - PC Paintbrush for Windows (PC Paintbrush Plus for */\r
+ /* Windows and Windows 3.0 Paintbrush use Version 5) */\r
+ /* 5 - PC Paintbrush 3.0 and greater (including PC Paintbrush */\r
+ /* Plus and Publisher's Paintbrush) */\r
+ /* */\r
+ /* 2. ZSoft Corporation has reserved the right to change the */\r
+ /* encoding method in future versions for better image */\r
+ /* compression performance. The "encoding" member value may */\r
+ /* change accordingly. */\r
+ /* */\r
+ /* 3. The value of the "bppixel" member depends on the type of */\r
+ /* video display adapter and its video mode. Typical values */\r
+ /* are 1, 2, 4 and 8. */\r
+ /* */\r
+ /* 4. The "xul", "yul", "xlr" and "ylr" members are zero-based and */\r
+ /* and inclusive values indicating the position of the image on */\r
+ /* the screen. The display functions can ignore this */\r
+ /* information if desired. */\r
+ /* */\r
+ /* 5. The "horz_res" and "vert_res" members refer to the "dots per */\r
+ /* inch" resolution of the scanning device used to create the */\r
+ /* image. For images created on video display adapters, these */\r
+ /* values typically refer to the horizontal and vertical */\r
+ /* resolutions in pixels (e.g. - 640 x 350 for an EGA display). */\r
+ /* */\r
+ /* The display function ignore these members, as some programs */\r
+ /* programs do not bother to initialize them when creating PCX */\r
+ /* image files. */\r
+ /* */\r
+ /* 6. The "palette" member is typically left uninitialized if an */\r
+ /* extended 256-color palette is appended to the PCX image */\r
+ /* file. */\r
+ /* */\r
+ /* 7. The "reserved" member used to contain the MS-DOS video mode */\r
+ /* that the PCX image was intended to be displayed under. This */\r
+ /* member is ignored in Version 5. ZSoft recommends that it be */\r
+ /* set to zero. */\r
+ /* */\r
+ /* 8. The value of the "nplanes" member depends on the type of */\r
+ /* video display adapter and its video mode. Typical values */\r
+ /* are 1, 2, 3 and 4. */\r
+ /* */\r
+ /* 9. The value of the "bppscan" member should be an even number */\r
+ /* (for compatibility with some existing commercial programs.) */\r
+ /* It indicates the number of bytes required to buffer a */\r
+ /* decoded scan line for one color plane. */\r
+ /* */\r
+ /* 10. The "palette_type" member indicates whether the palette */\r
+ /* represents a color or grayscale palette. It is a bit-mapped */\r
+ /* variable (only the lowest two bits are significant; the */\r
+ /* others are ignored) with two possible values: */\r
+ /* */\r
+ /* 0x01 - color or black & white */\r
+ /* 0x02 - grayscale */\r
+ /* */\r
+ /* If "grayscale" is indicated, the file color palette must be */\r
+ /* set to shades of gray. The file decoding functions can then */\r
+ /* either use this palette or assume a default grayscale */\r
+ /* palette if necessary. */\r
+ /* */\r
+ /* PC Paintbrush IV and IV Plus ignore this member. */\r
+ /* */\r
+ /* 11. The "scrn_width" and "scrn_height" members were added for */\r
+ /* PC Paintbrush IV Version 1.02 and IV Plus Version 1.0. They */\r
+ /* may not be initialized in some older Version 5 PCX files, or */\r
+ /* the "scrn_width" member may be initialized with the screen */\r
+ /* height and the "scrn_height" member uninitialized. ZSoft */\r
+ /* recommends that this information be ignored. */\r
+ /* */\r
+ /* 12. ZSoft recommends that the "filler" bytes be set to zero. */\r
+}\r
+PCX_HDR;\r
+\r
+typedef struct pcx_workblk /* PCX image file workblock */\r
+{\r
+ /* File header */\r
+\r
+ FILE *fp; /* PCX image file pointer */\r
+ PCX_HDR header; /* PCX image file header */\r
+ PCX_PAL *palettep; /* Color palette pointer */\r
+ BOOL epal_flag; /* Extended color palette flag */\r
+\r
+ /* Image manipulation variables */\r
+\r
+ int num_bytes; /* Number of bytes to display */\r
+ int mask; /* Unseen pixels mask */\r
+ unsigned long page_offset; /* Display page address offset */\r
+\r
+ /* Image manipulation function pointer */\r
+\r
+ void (*pcx_funcp)(struct pcx_workblk *, unsigned char _far *, int);\r
+}\r
+PCX_WORKBLK;\r
+\f\r
+/* FUNCTIONS PROTOTYPES */\r
+\r
+extern BOOL pcx_close(PCX_WORKBLK *);\r
+\r
+extern PCX_WORKBLK *pcx_open(char *, BOOL);\r
+\r
--- /dev/null
+ECHO OFF\r
+REM Batch File To Compile PCX_LIB Demonstration Programs\r
+REM Compiler: Microsoft C V6.0\r
+ECHO byHeart Software's PCX_LIB Demonstration Programs\r
+ECHO Now compiling source code files ...\r
+cl /c /W4 pcx_comm.c pcx_disp.c pcx_exam.c pcx_file.c rd_demo.c wr_demo.c\r
+ECHO Now linking PCX_EXAM ...\r
+link pcx_exam;\r
+ECHO Now linking RD_DEMO ...\r
+link rd_demo pcx_disp pcx_comm;\r
+ECHO Now linking WR_DEMO ...\r
+link wr_demo pcx_disp pcx_file pcx_comm;\r
+\r
--- /dev/null
+byHeart Software\r
+620 Ballantree Road\r
+West Vancouver, B.C.\r
+Canada V7S 1W3\r
+\r
+Tel. (604) 922-6148\r
+Fax. (604) 987-7621\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ PCX_LIB Documentation\r
+ ---------------------\r
+ Version 1.00B\r
+\r
+\r
+ by Ian Ashdown, P.Eng.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ Released into the Public Domain 91/04/01\r
+\f\r
+1. Introduction\r
+\r
+ PCX_LIB is a library of functions for displaying and storing ZSoft's \r
+ Paintbrush (R) PCX-format image files. It was developed expressly \r
+ for release into the Public Domain. Fully commented ANSI C source \r
+ code is provided for all functions, along with complete technical \r
+ specifications for ZSoft's PCX image file format.\r
+\r
+ Version 1.00B supports the display and storage of images on MS-DOS \r
+ systems equipped with the following display adapters:\r
+\r
+ Hercules - monochrome\r
+ CGA - Color Graphics Adapter\r
+ EGA - Enhanced Graphics Adapter\r
+ MCGA - MultiColor Graphics Adapter\r
+ VGA - Video Graphics Adapter\r
+\r
+ All valid MS-DOS graphic modes are supported.\r
+\r
+ SuperVGA and XGA display adapters are not supported in this release.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 1\r
+\f\r
+2. DISCLAIMER:\r
+\r
+ IN NO EVENT SHALL BYHEART SOFTWARE BE LIABLE FOR ANY DAMAGES \r
+ WHATSOEVER INCLUDING, WITHOUT LIMITATION, PERSONAL DAMAGES, DAMAGES \r
+ FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS \r
+ INFORMATION, OR OTHER PECUNIARY LOSS, ARISING OUT OF THE USE OR \r
+ INABILITY TO USE THIS PRODUCT, EVEN IF BYHEART SOFTWARE HAS BEEN \r
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 2\r
+\f\r
+3. Disk Contents\r
+\r
+ The disk includes the following files:\r
+\r
+\r
+3.1. Documentation\r
+\r
+ PCX_LIB.DOC - PCX_LIB documentation (this file)\r
+ PCX_FMT.DOC - PCX image file format specifications\r
+\r
+\r
+3.2. ANSI C Source Code\r
+\r
+ PCX_COMM.C - PCX image file common functions\r
+ PCX_DISP.C - PCX image file display functions\r
+ PCX_EXAM.C - PCX image file header examination utility\r
+ PCX_FILE.C - PCX image capture functions\r
+ RD_DEMO.C - PCX image file display demonstration program\r
+ WR_DEMO.C - PCX image file capture demonstration program\r
+\r
+ PCX_EXT.H - PCX_LIB external definitions include file\r
+ PCX_INT.H - PCX_LIB internal definitions include file\r
+\r
+\r
+3.3. MS-DOS Executables\r
+\r
+ PCX_EXAM.EXE - PCX image file header examination utility\r
+ RD_DEMO.EXE - PCX image file display demonstration program\r
+ WR_DEMO.EXE - PCX image file capture demonstration program\r
+\r
+\r
+3.4. Sample PCX Image Files\r
+\r
+ TEST_04.PCX - 320 x 200 4-color CGA test image (mode 4)\r
+ TEST_06.PCX - 640 x 200 2-color CGA test image (mode 6)\r
+ TEST_16.PCX - 640 x 350 16-color EGA test image (mode 16)\r
+ TEST_19.PCX - 320 x 200 256-color VGA test image (mode 19)\r
+\r
+\r
+3.5. Miscellaneous\r
+\r
+ PCX_LIB.BAT - Microsoft C V6.0 program build batch file\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 3\r
+\f\r
+4. Trying It Out\r
+\r
+ Four test images are included on the disk, one each for MS-DOS video \r
+ modes 4, 6, 16 and 19. \r
+\r
+\r
+4.1. PCX_EXAM\r
+\r
+ PCX_EXAM reads a PCX-format image file and displays a summary of \r
+ the information contained in the file header. A full explanation\r
+ of this information is presented in PCX_FMT.DOC.\r
+\r
+ To run PCX_EXAM with a file (e.g. - "MY_PICT.PCX"), enter:\r
+\r
+ PCX_EXAM my_pict.pcx\r
+\r
+\r
+4.2. RD_DEMO\r
+\r
+ To display any of these images, enter:\r
+\r
+ RD_DEMO test_xx.pcx xx\r
+\r
+ where "xx" is the video mode (e.g. - "RD_DEMO test_06.pcx 6"). \r
+ Your display adapter must be capable of emulating the specified \r
+ video mode in order to display the image.\r
+\r
+ Once the image is displayed, press any key to clear the screen and \r
+ return to DOS.\r
+\r
+ RD_DEMO will also display a PCX-format image if your display \r
+ adapter supports its appropriate video mode. For example, to \r
+ display a PCX-format image file "MY_PICT.PCX" that was created for \r
+ display on 320 x 200 256-color VGA displays, enter: \r
+\r
+ RD_DEMO my_pict.pcx 19\r
+\r
+\r
+4.3. WR_DEMO\r
+\r
+ The demonstration program WR_DEMO will first display a PCX-format \r
+ image file, then capture the image directly from the display \r
+ adapter's memory and create a PCX-format image file called \r
+ "PCX_DEMO.PCX".\r
+\r
+ To run WR_DEMO, enter:\r
+\r
+ WR_DEMO test_xx.pcx xx\r
+ \r
+ where "xx" is the video mode (e.g. - "WR_DEMO test_06.pcx 6"). \r
+ Your display adapter must be capable of emulating the specified \r
+ video mode in order to display and capture the image.\r
+\r
+\r
+ p. 4\r
+\f\r
+ Once the image is displayed, WR_DEMO will automatically capture \r
+ it and create the file "PCX_DEMO.PCX" before clearing the screen \r
+ and returning to DOS.\r
+\r
+ WR_DEMO will also display and capture a PCX-format image if your\r
+ display adapter supports its appropriate video mode. For example, \r
+ to capture a PCX-format image file "MY_PICT.PCX" that was created \r
+ for display on 320 x 200 256-color VGA displays, enter: \r
+\r
+ WR_DEMO my_pict.pcx 19\r
+\r
+ WR_DEMO captures the entire screen and all color planes, so the\r
+ size of the resultant PCX_DEMO.PCX file may be different than the\r
+ file it displayed.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 5\r
+\f\r
+5. Using The Library\r
+\r
+ The public functions in PCX_LIB (i.e. - those meant to be called by \r
+ application programs) are:\r
+\r
+ pcx_read - display a PCX-format image file\r
+ pcx_write - capture a displayed image to a PCX-format file\r
+\r
+ pcx_isvga - determine whether a display adapter supports\r
+ VGA BIOS calls\r
+\r
+ pcx_init_dsa - set up BIOS to capture EGA color palette\r
+ register updates\r
+ pcx_free_dsa - reset BIOS to state before call to \r
+ "pcx_inst_dsa"\r
+\r
+ All functions are fully and exhaustively documented in the source \r
+ code files. Example calls to the public functions may be found in \r
+ the source code files RD_DEMO.C and WR_DEMO.C.\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ p. 6\r
+\r
--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * RD_DEMO.C - PCX_LIB PCX Image File Read Demonstration Program\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/06 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <conio.h>\r
+#include <graph.h>\r
+#include "pcx_ext.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\f\r
+/* GLOBALS */\r
+\r
+static char *use_msg[] = /* Program usage message */\r
+{\r
+ " Synopsis: This public domain program displays a Paintbrush (R) PCX",\r
+ "-format\n image file.\n\n Usage: RD_DEMO filename vi",\r
+ "deo_mode\n\n where \"filename\" is the name of a PCX-form",\r
+ "at image file and\n \"video_mode\" is an MS-DOS video mod",\r
+ "e. Valid values are:\n\n 4 - 320 x 200 4-color CGA",\r
+ "\n 5 - 320 x 200 4-color CGA (color burst off)\n ",\r
+ " 6 - 640 x 200 2-color CGA\n 13 - 320 x ",\r
+ "200 16-color EGA/VGA\n 14 - 640 x 200 16-color EGA/VG",\r
+ "A\n 15 - 640 x 350 2-color EGA/VGA\n 16",\r
+ " - 640 x 350 16-color EGA/VGA\n 17 - 640 x 480 2-co",\r
+ "lor VGA\n 18 - 640 x 480 16-color VGA\n ",\r
+ " 19 - 320 x 200 256-color VGA\n\n The file must be comp",\r
+ "atible with the indicated video mode.\n",\r
+ (unsigned char *) NULL\r
+};\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * MAIN - Executive Function\r
+ *\r
+ * Purpose: To read and display a PCX-format image file.\r
+ *\r
+ * Setup: int main\r
+ * (\r
+ * int argc,\r
+ * char **argv\r
+ * )\r
+ *\r
+ * Where: argc is the number of command-line arguments.\r
+ * argv is a pointer to an array of command-line argument\r
+ * strings.\r
+ *\r
+ * Return: 0 if successful; otherwise 2.\r
+ *\r
+ * Note: Usage is:\r
+ *\r
+ * RD_DEMO filename video_mode\r
+ *\r
+ * where:\r
+ *\r
+ * filename is the name of a PCX-format image file.\r
+ * video_mode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * 4 - 320 x 200 4-color CGA\r
+ * 5 - 320 x 200 4-color CGA (color burst off)\r
+ * 6 - 640 x 200 2-color CGA\r
+ * 13 - 320 x 200 16-color EGA/VGA\r
+ * 14 - 640 x 200 16-color EGA/VGA\r
+ * 15 - 640 x 350 2-color EGA/VGA\r
+ * 16 - 640 x 350 16-color EGA/VGA\r
+ * 17 - 640 x 480 2-color VGA\r
+ * 18 - 640 x 480 16-color VGA\r
+ * 19 - 320 x 200 256-color VGA\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+int main\r
+(\r
+ int argc,\r
+ char **argv\r
+)\r
+{\r
+ int i; /* Scratch counter */\r
+ int vmode; /* Video mode */\r
+ BOOL status = FALSE; /* Return status */\r
+\r
+ /* Display program title */\r
+\r
+ puts("\nRD_DEMO - PCX Image File Display Demonstration Program\n");\r
+\r
+ if (argc == 3) /* Check for filename and video mode parameters */\r
+ {\r
+ vmode = atoi(argv[2]); /* Get the video mode */\r
+\r
+ /* Validate the video mode (must be valid MS-DOS graphics mode) */\r
+\r
+ if ((vmode >= 4 && vmode <= 6) || (vmode >= 13 && vmode <= 19))\r
+ status = TRUE;\r
+ }\r
+\r
+ if (status == TRUE)\r
+ {\r
+ if (_setvideomode(vmode) == 0) /* Set the video mode */\r
+ {\r
+ /* Report error */\r
+\r
+ fprintf(stderr,\r
+ "ERROR: could not set display adapter to mode %d.\n", vmode);\r
+\r
+ return (2);\r
+ }\r
+\r
+ /* Read and display the file (assume video page zero) */\r
+\r
+ if ((status = pcx_read(argv[1], vmode, 0)) == TRUE)\r
+ {\r
+ while (!kbhit()) /* Wait for a keystroke */\r
+ ;\r
+\r
+ (void) getch(); /* Clear the keyboard buffer */\r
+ }\r
+\r
+ (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */\r
+\r
+ if (status == FALSE)\r
+ {\r
+ /* Report error */\r
+\r
+ fprintf(stderr, "\nRD_DEMO - PCX Image File Display Demonstration");\r
+ fprintf(stderr, " Program\n\nERROR: Could not read file %s.\n",\r
+ argv[1]);\r
+ }\r
+ }\r
+ else /* Display usage information */\r
+ {\r
+ while (use_msg[i] != (unsigned char *) NULL)\r
+ fputs(use_msg[i++], stderr);\r
+ }\r
+\r
+ if (status == TRUE)\r
+ return (0);\r
+ else\r
+ return (2);\r
+}\r
+\r
--- /dev/null
+/*\r
+ *************************************************************************\r
+ *\r
+ * WR_DEMO.C - PCX_LIB PCX Image File Write Demonstration Program\r
+ *\r
+ * Version: 1.00B\r
+ *\r
+ * History: 91/02/14 - Created\r
+ * 91/04/01 - Release 1.00A\r
+ * 91/04/06 - Release 1.00B\r
+ *\r
+ * Compiler: Microsoft C V6.0\r
+ *\r
+ * Author: Ian Ashdown, P.Eng.\r
+ * byHeart Software\r
+ * 620 Ballantree Road\r
+ * West Vancouver, B.C.\r
+ * Canada V7S 1W3\r
+ * Tel. (604) 922-6148\r
+ * Fax. (604) 987-7621\r
+ *\r
+ * Copyright: Public Domain\r
+ *\r
+ *************************************************************************\r
+ */\r
+\f\r
+/* INCLUDE FILES */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <conio.h>\r
+#include <graph.h>\r
+#include "pcx_ext.h"\r
+\f\r
+/* FORWARD REFERENCES */\r
+\f\r
+/* GLOBALS */\r
+\r
+static char *use_msg[] = /* Program usage message */\r
+{\r
+ " Synopsis: This public domain program displays a Paintbrush (R) PCX",\r
+ "-format\n image file, then captures the image directly fr",\r
+ "om the display\n and writes it to the file PCX_DEMO.PCX.",\r
+ "\n\n Usage: WR_DEMO filename video_mode\n\n where \"",\r
+ "filename\" is the name of the PCX-format image file to be\n ",\r
+ " written and \"video_mode\" is an MS-DOS video mode. Valid values",\r
+ "\n are:\n\n 4 - 320 x 200 4-color CGA\n ",\r
+ " 5 - 320 x 200 4-color CGA (color burst off)\n ",\r
+ " 6 - 640 x 200 2-color CGA\n 13 - 320 x 200",\r
+ " 16-color EGA/VGA\n 14 - 640 x 200 16-color EGA/VGA\n",\r
+ " 15 - 640 x 350 2-color EGA/VGA\n 16 ",\r
+ "- 640 x 350 16-color EGA/VGA\n 17 - 640 x 480 2-color",\r
+ " VGA\n 18 - 640 x 480 16-color VGA\n 19",\r
+ " - 320 x 200 256-color VGA\n",\r
+ (unsigned char *) NULL\r
+};\r
+\f\r
+/* PUBLIC FUNCTIONS */\r
+\r
+/*\r
+ *************************************************************************\r
+ *\r
+ * MAIN - Executive Function\r
+ *\r
+ * Purpose: To write a PCX-format image file.\r
+ *\r
+ * Setup: int main\r
+ * (\r
+ * int argc,\r
+ * char **argv\r
+ * )\r
+ *\r
+ * Where: argc is the number of command-line arguments.\r
+ * argv is a pointer to an array of command-line argument\r
+ * strings.\r
+ *\r
+ * Return: 0 if successful; otherwise 2.\r
+ *\r
+ * Note: Usage is:\r
+ *\r
+ * WR_DEMO filename video_mode\r
+ *\r
+ * where:\r
+ *\r
+ * filename is the name of a PCX-format image file.\r
+ * video_mode is the MS-DOS video mode. Valid values are:\r
+ *\r
+ * 4 - 320 x 200 4-color CGA\r
+ * 5 - 320 x 200 4-color CGA (color burst off)\r
+ * 6 - 640 x 200 2-color CGA\r
+ * 13 - 320 x 200 16-color EGA/VGA\r
+ * 14 - 640 x 200 16-color EGA/VGA\r
+ * 15 - 640 x 350 2-color EGA/VGA\r
+ * 16 - 640 x 350 16-color EGA/VGA\r
+ * 17 - 640 x 480 2-color VGA\r
+ * 18 - 640 x 480 16-color VGA\r
+ * 19 - 320 x 200 256-color VGA\r
+ *\r
+ *************************************************************************\r
+ */\r
+\r
+int main\r
+(\r
+ int argc,\r
+ char **argv\r
+)\r
+{\r
+ int i; /* Scratch counter */\r
+ int vmode; /* Video mode */\r
+ BOOL status = FALSE; /* Return status */\r
+ PCX_VSB *vsbp; /* Video services data save buffer ptr */\r
+\r
+ vsbp = (PCX_VSB *) NULL; /* Initialize video services buffer ptr */\r
+\r
+ /* Display program title */\r
+\r
+ puts("\nWR_DEMO - PCX Image File Write Demonstration Program\n");\r
+\r
+ if (argc == 3) /* Check for filename and video mode parameters */\r
+ {\r
+ vmode = atoi(argv[2]); /* Get the video mode */\r
+\r
+ /* Validate the video mode (must be valid MS-DOS graphics mode) */\r
+\r
+ if ((vmode >= 4 && vmode <= 6) || (vmode >= 13 && vmode <= 19))\r
+ status = TRUE;\r
+ }\r
+\r
+ if (status == TRUE)\r
+ {\r
+ if (_setvideomode(vmode) == 0) /* Set the video mode */\r
+ {\r
+ /* Report error */\r
+\r
+ fprintf(stderr,\r
+ "ERROR: could not set display adapter to mode %d.\n", vmode);\r
+\r
+ return (2);\r
+ }\r
+\r
+ if (vmode >= 13 && vmode <= 18) /* EGA-compatible video mode ? */\r
+ {\r
+ if (pcx_isvga() == TRUE) /* Is a VGA display present ? */\r
+ {\r
+ /* An EGA display adapter is present - instantiate a Dynamic */\r
+ /* Save Area buffer to capture the color palette settings each */\r
+ /* time the palette is updated */\r
+\r
+ status = pcx_init_dsa(&vsbp);\r
+ }\r
+ }\r
+\r
+ if (status == TRUE)\r
+ {\r
+ /* Read and display the file (assume video page zero) */\r
+\r
+ if ((status = pcx_read(argv[1], vmode, 0)) == TRUE)\r
+ {\r
+ /* Capture the entire screen as a PCX-format file */\r
+\r
+ status = pcx_write("PCX_DEMO.PCX", vmode, 0, 640, 480);\r
+\r
+ (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */\r
+\r
+ if (status == FALSE)\r
+ {\r
+ /* Report error */\r
+\r
+ fprintf(stderr,\r
+ "\nWR_DEMO - PCX Image File Write Demonstration");\r
+ fprintf(stderr,\r
+ " Program\n\nERROR: Could not write file %s.\n", argv[1]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */\r
+\r
+ /* Report error */\r
+\r
+ fprintf(stderr, "\nWR_DEMO - PCX Image File Write Demonstration");\r
+ fprintf(stderr, " Program\n\nERROR: Could not read file %s.\n",\r
+ argv[1]);\r
+ }\r
+\r
+ /* Free the Dynamic Save Area (if necessary) */\r
+\r
+ if (vsbp != (PCX_VSB *) NULL)\r
+ pcx_free_dsa(vsbp);\r
+ }\r
+ else\r
+ {\r
+ (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */\r
+\r
+ fputs("ERROR: out of memory.\n", stderr); /* Report error */\r
+ }\r
+ }\r
+ else /* Display usage information */\r
+ {\r
+ while (use_msg[i] != (unsigned char *) NULL)\r
+ fputs(use_msg[i++], stderr);\r
+ }\r
+\r
+ if (status == TRUE)\r
+ return (0);\r
+ else\r
+ return (2);\r
+}\r
+\r
--- /dev/null
+MASM modex,modex,modex,nul
\ No newline at end of file
--- /dev/null
+DEFINT A-Z\r
+DECLARE SUB PRINT.STRING (Text$, Xpos%, Ypos%, Colour%)\r
+DECLARE FUNCTION MakePal$ (Red%, Green%, Blue%)\r
+DECLARE SUB LOAD.FONT (FontFile$, FontNum%)\r
+DECLARE SUB ERROR.OUT (Text$)\r
+\r
+ REM $INCLUDE: 'MODEX.BI'\r
+\r
+ REM $INCLUDE: 'UTILS.BI'\r
+\r
+TYPE FONT\r
+ SetData AS STRING * 1024\r
+END TYPE\r
+\r
+\r
+TYPE VGAPalette\r
+ PalData AS STRING * 768\r
+END TYPE\r
+\r
+\r
+ ' Alternate form of LOAD_DAC_REGISTERS so we can pass an offset into\r
+ ' a String instead of the Address of the String\r
+\r
+DECLARE SUB LOAD.DACS ALIAS "LOAD_DAC_REGISTERS" (BYVAL Addr&, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%)\r
+\r
+\r
+ '\r
+ 'MODE X DEMO of Multiple Character Sets and Block Color Cycling\r
+ '\r
+ 'By Matt Pritchard\r
+ '\r
+\r
+COMMON SHARED CharSet() AS FONT\r
+\r
+DIM Pal AS VGAPalette\r
+\r
+ REM $DYNAMIC\r
+\r
+DIM SHARED CharSet(0 TO 3) AS FONT\r
+\r
+\r
+ LOAD.FONT "SYSTEM.FNT", 0\r
+ LOAD.FONT "ROM_8x8.FNT", 1\r
+ LOAD.FONT "SPACEAGE.FNT", 2\r
+\r
+\r
+ IF SET.MODEX(Mode320x240) = False THEN\r
+ ERROR.OUT "ERROR SETTING MODE X"\r
+ END IF\r
+\r
+\r
+ A$ = "": B$ = ""\r
+ FOR X = 0 TO 31: A$ = A$ + MakePal$(31 - X, X, 0): NEXT X\r
+ FOR X = 0 TO 31: A$ = A$ + MakePal$(0, 31 - X, X): NEXT X\r
+ FOR X = 0 TO 31: A$ = A$ + MakePal$(X, 0, 31 - X): NEXT X\r
+ \r
+ FOR X = 0 TO 31: B$ = B$ + MakePal$(31 - X, X, X): NEXT X\r
+ FOR X = 0 TO 31: B$ = B$ + MakePal$(X, 31 - X, X): NEXT X\r
+ FOR X = 0 TO 31: B$ = B$ + MakePal$(X, X, 31 - X): NEXT X\r
+\r
+ Black$ = STRING$(192, 0)\r
+ White$ = STRING$(128 * 3, 48)\r
+\r
+ Pal1$ = Black$ + A$ + A$ + B$ + B$ + A$\r
+\r
+ LOAD.DACS SSEGADD(Black$), 64, 127, 1\r
+ LOAD.DACS SSEGADD(Black$), 20, 63, 0\r
+\r
+ LOAD.DACS SSEGADD(White$), 128, 255, 0\r
+\r
+ '*** Background ***\r
+\r
+ FOR X = 0 TO 319\r
+ FOR Y = 0 TO 239\r
+ IF ((X + Y) AND 1) = 1 THEN SET.POINT X, Y, 64 + X \ 5 ELSE SET.POINT X, Y, 20 + Y \ 6\r
+ NEXT Y\r
+ NEXT X\r
+\r
+ '*** Draw Font Displays ***\r
+\r
+ PRINT.STRING "FONT: SYSTEM.FNT", 11, 7, 15\r
+ PRINT.STRING "FONT: ROM_8x8.FNT", 11, 17, 15\r
+ PRINT.STRING "FONT: SPACEAGE.FNT", 11, 27, 15\r
+ PRINT.STRING "PRESS ANY KEY TO CONTINUE", 8, 29, 14\r
+ \r
+\r
+ FOR F = 0 TO 2\r
+ SET.DISPLAY.FONT CharSet(F), 1\r
+ Yp = F * 80 + 10\r
+ FOR Y = 0 TO 96 STEP 32\r
+ FOR X = 0 TO 31\r
+ TGPRINTC 128 + Y + X, X * 10 + 1, Yp, 128 + Y\r
+ NEXT X\r
+ Yp = Yp + 10\r
+ NEXT Y\r
+ NEXT F\r
+\r
+ DO\r
+ LOOP UNTIL SCAN.KEYBOARD\r
+\r
+ Offset = 0\r
+ Restart = 192\r
+ MaxOfs = 192 + 96 * 6\r
+\r
+ Delay = 100\r
+\r
+ Offset2 = 0\r
+ Offset2Dir = 3\r
+ Offset2Min = 192\r
+ Offset2Max = Offset2Min + 192 * 6\r
+\r
+ DO\r
+ LOAD.DACS SSEGADD(Pal1$) + Offset, 64, 127, 1\r
+ Offset = Offset + 3\r
+ IF Offset >= MaxOfs THEN Offset = Restart\r
+ IF Delay THEN\r
+ Delay = Delay - 1\r
+ ELSE\r
+ LOAD.DACS SSEGADD(Pal1$) + Offset2, 20, 60, 0\r
+ IF Offset2 = Offset2Max THEN Offset2Dir = -3\r
+ IF Offset2 = Offset2Min THEN Offset2Dir = 3\r
+ Offset2 = Offset2 + Offset2Dir\r
+ END IF\r
+\r
+ LOOP UNTIL SCAN.KEYBOARD\r
+\r
+ ERROR.OUT "DEMO OVER"\r
+\r
+REM $STATIC\r
+SUB ERROR.OUT (Text$)\r
+\r
+ SET.VIDEO.MODE 3\r
+\r
+ DOS.PRINT Text$\r
+\r
+ END\r
+\r
+END SUB\r
+\r
+SUB LOAD.FONT (FontFile$, FontNum) STATIC\r
+\r
+ IF LEN(DIR$(FontFile$)) = 0 THEN ERROR.OUT "FILE NOT FOUND: " + FontFile$\r
+\r
+ OPEN FontFile$ FOR BINARY AS #1\r
+\r
+ SEEK #1, 1\r
+ GET #1, , CharSet(FontNum)\r
+\r
+ CLOSE #1\r
+\r
+END SUB\r
+\r
+FUNCTION MakePal$ (Red, Green, Blue) STATIC\r
+\r
+ MakePal$ = CHR$(Red) + CHR$(Green) + CHR$(Blue)\r
+\r
+END FUNCTION\r
+\r
+SUB PRINT.STRING (Text$, Xpos, Ypos, Colour)\r
+\r
+ TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos * 8, Ypos * 8, Colour\r
+\r
+END SUB\r
+\r
--- /dev/null
+ECHO ... Building MODEX.QLB for BASIC PDS 7.1\r
+LIB MODEX -+MODEX,,\r
+LIB MODEX -+UTILS,,\r
+DEL MODEX.BAK\r
+LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\BC7\LIB\QBXQLB.LIB;\1a\r
--- /dev/null
+ \r
+ ' ===== SCREEN RESOLUTIONS =====\r
+ \r
+CONST Mode320x200 = 0, Mode320x400 = 1\r
+CONST Mode360x200 = 2, Mode360x400 = 3\r
+CONST Mode320x240 = 4, Mode320x480 = 5\r
+CONST Mode360x240 = 6, Mode360x480 = 7\r
+ \r
+ ' ===== MODE X SETUP ROUTINES =====\r
+ \r
+DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%)\r
+DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%)\r
+ \r
+ ' ===== BASIC GRAPHICS PRIMITIVES =====\r
+ \r
+DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%)\r
+DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%)\r
+DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%)\r
+DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+ \r
+ ' ===== DAC COLOR REGISTER ROUTINES =====\r
+ \r
+DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%)\r
+DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%)\r
+DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%)\r
+DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%)\r
+ \r
+ \r
+ ' ===== PAGE FLIPPING AND SCROLLING ROUTINES =====\r
+ \r
+DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE"\r
+DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE"\r
+DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%)\r
+DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" ()\r
+DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" ()\r
+DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY"\r
+ \r
+ ' ===== TEXT DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%)\r
+ \r
+ ' ===== BITMAP (SPRITE) DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+ \r
+ ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====\r
+ \r
+DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%)\r
+DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%)\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
--- /dev/null
+'File: TEST6.BAS\r
+'Descp.: A Mode "X" demonstration\r
+'Author: Matt Pritchard\r
+'Date: 14 April, 1993\r
+'\r
+DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%)\r
+DECLARE SUB ERROR.OUT (Message$)\r
+DECLARE FUNCTION GET.KEY% ()\r
+DECLARE SUB LOAD.SHAPES ()\r
+DECLARE SUB PAGE.DEMO ()\r
+DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%)\r
+DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%)\r
+DEFINT A-Z\r
+\r
+\r
+TYPE ShapeType\r
+ ImgData AS STRING * 512\r
+ xWidth AS INTEGER\r
+ yWidth AS INTEGER\r
+END TYPE\r
+\r
+TYPE Sprite\r
+ Xpos AS INTEGER\r
+ Ypos AS INTEGER\r
+ XDir AS INTEGER\r
+ YDir AS INTEGER\r
+ Shape AS INTEGER\r
+END TYPE\r
+\r
+\r
+CONST MaxShapes = 32\r
+\r
+ REM $INCLUDE: 'UTILS.BI'\r
+ REM $INCLUDE: 'MODEX.BI'\r
+\r
+DIM SHARED Img(32) AS ShapeType\r
+COMMON SHARED Img() AS ShapeType\r
+\r
+\r
+ CALL INIT.RANDOM\r
+\r
+ CALL LOAD.SHAPES\r
+\r
+ CALL DEMO.RES(Mode320x200, 320, 200)\r
+ CALL DEMO.RES(Mode320x400, 320, 400)\r
+\r
+ CALL DEMO.RES(Mode360x200, 360, 200)\r
+ CALL DEMO.RES(Mode360x400, 360, 400)\r
+\r
+ CALL DEMO.RES(Mode320x240, 320, 240)\r
+ CALL DEMO.RES(Mode320x480, 320, 480)\r
+\r
+ CALL DEMO.RES(Mode360x240, 360, 240)\r
+ CALL DEMO.RES(Mode360x480, 360, 480)\r
+\r
+ CALL PAGE.DEMO\r
+\r
+ SET.VIDEO.MODE 3\r
+ DOS.PRINT "THIS MODE X DEMO IS FINISHED"\r
+ END\r
+\r
+SUB DEMO.RES (Mode, Xmax, Ymax)\r
+\r
+ IF SET.MODEX%(Mode) = 0 THEN\r
+ ERROR.OUT "Unable to SET_MODEX" + STR$(Mode)\r
+ END IF\r
+\r
+ XCenter = Xmax \ 2\r
+ \r
+ X1 = 10\r
+ Y1 = 10\r
+ X2 = Xmax - 1\r
+ Y2 = Ymax - 1\r
+\r
+ FOR Z = 0 TO 3\r
+ Colr = 31 - Z * 2\r
+ DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr\r
+ DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr\r
+ DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr\r
+ DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr\r
+ NEXT Z\r
+\r
+ XChars = Xmax \ 10\r
+ YChars = Ymax \ 10\r
+\r
+ FOR X = 0 TO XChars - 1\r
+ TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7)\r
+ DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15\r
+ NEXT X\r
+\r
+ FOR Y = 0 TO YChars - 1\r
+ TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7)\r
+ DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15\r
+ NEXT Y\r
+\r
+ ' Draw Lines\r
+\r
+ FOR X = 0 TO 63\r
+ N = 15 + X * .75\r
+ SET.DAC.REGISTER 64 + X, N, N, N\r
+ SET.DAC.REGISTER 128 + X, 0, N, N\r
+\r
+ DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X\r
+ DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X\r
+\r
+ NEXT X\r
+ TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE\r
+\r
+ Y = 60: Gap = 0\r
+ FOR X = 0 TO 9\r
+ FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X\r
+ FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X\r
+ FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X\r
+ Y = Y + Gap + 2\r
+ Gap = Gap + 1\r
+ NEXT X\r
+ TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN\r
+\r
+\r
+ FOR X = 190 TO 250 STEP 2\r
+ FOR Y = 60 TO 122 STEP 2\r
+ SET.POINT X, Y, X + Y + X + Y\r
+ NEXT Y\r
+ NEXT X\r
+\r
+ TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED\r
+\r
+ FOR X = 190 TO 250 STEP 2\r
+ FOR Y = 60 TO 122 STEP 2\r
+ IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN\r
+ ERROR.OUT "READ.PIXEL Failure"\r
+ END IF\r
+ NEXT Y\r
+ NEXT X\r
+\r
+\r
+\r
+ Msg$ = " This is a MODE X demo "\r
+ PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE\r
+ Msg$ = "Screen Resolution is by "\r
+ Xp = XCenter - (LEN(Msg$) * 4)\r
+ PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK\r
+\r
+ PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK\r
+ PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK\r
+\r
+ FOR X = 0 TO 15\r
+ SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3\r
+ DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X\r
+ NEXT X\r
+ TPRINT.TEXT "Press <ANY KEY> to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW\r
+\r
+ X = GET.KEY%\r
+ IF X = KyESC THEN ERROR.OUT "ABORT"\r
+\r
+END SUB\r
+\r
+SUB ERROR.OUT (Message$)\r
+\r
+ SET.VIDEO.MODE 3\r
+ DOS.PRINT Message$\r
+ END\r
+\r
+END SUB\r
+\r
+FUNCTION GET.KEY%\r
+\r
+ DO\r
+ X = SCAN.KEYBOARD\r
+ LOOP UNTIL X\r
+\r
+ GET.KEY% = X\r
+\r
+END FUNCTION\r
+\r
+SUB LOAD.SHAPES\r
+\r
+DIM Grid(1 TO 32, 1 TO 32)\r
+\r
+ FOR Shape = 0 TO MaxShapes - 1\r
+\r
+ FOR Y = 1 TO 32\r
+ FOR X = 1 TO 32\r
+ Grid(X, Y) = 0\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ Style = RANDOM.INT(6)\r
+ Colour = 1 + RANDOM.INT(15)\r
+ \r
+ SELECT CASE Style\r
+\r
+ CASE 0: ' Solid Box\r
+\r
+ DO\r
+ xWidth = 3 + RANDOM.INT(30)\r
+ yWidth = 3 + RANDOM.INT(30)\r
+ LOOP UNTIL ((xWidth * yWidth) <= 512)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ Grid(X, Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 1: ' Hollow Box\r
+\r
+ DO\r
+ xWidth = 5 + RANDOM.INT(28)\r
+ yWidth = 5 + RANDOM.INT(28)\r
+ LOOP UNTIL ((xWidth * yWidth) <= 512)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ Grid(X, Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1)\r
+ HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1)\r
+\r
+ FOR Y = HollowY + 1 TO yWidth - HollowY\r
+ FOR X = HollowX + 1 TO xWidth - HollowX\r
+ Grid(X, Y) = nil\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 2: ' Solid Diamond\r
+\r
+ xWidth = 3 + 2 * RANDOM.INT(10)\r
+ yWidth = xWidth\r
+ Centre = xWidth \ 2\r
+\r
+ FOR Y = 0 TO Centre\r
+ FOR X = 0 TO Y\r
+ Grid(Centre - X + 1, Y + 1) = Colour\r
+ Grid(Centre + X + 1, Y + 1) = Colour\r
+ Grid(Centre - X + 1, yWidth - Y) = Colour\r
+ Grid(Centre + X + 1, yWidth - Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+\r
+ CASE 3: ' Hollow Diamond\r
+\r
+\r
+ xWidth = 3 + 2 * RANDOM.INT(10)\r
+ yWidth = xWidth\r
+ Centre = xWidth \ 2\r
+ sWidth = RANDOM.INT(Centre)\r
+\r
+ FOR Y = 0 TO Centre\r
+ FOR X = 0 TO Y\r
+ IF X + (Centre - Y) >= sWidth THEN\r
+ Grid(Centre - X + 1, Y + 1) = Colour\r
+ Grid(Centre + X + 1, Y + 1) = Colour\r
+ Grid(Centre - X + 1, yWidth - Y) = Colour\r
+ Grid(Centre + X + 1, yWidth - Y) = Colour\r
+ END IF\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 4: ' Ball\r
+\r
+ xWidth = 7 + 2 * RANDOM.INT(8)\r
+ yWidth = xWidth\r
+ Centre = 1 + xWidth \ 2\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y)))\r
+ IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 5: ' Ball\r
+\r
+\r
+ xWidth = 7 + 2 * RANDOM.INT(8)\r
+ yWidth = xWidth\r
+ Centre = 1 + xWidth \ 2\r
+ sWidth = RANDOM.INT(xWidth)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y)))\r
+ IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ END SELECT\r
+\r
+ Img(Shape).xWidth = xWidth\r
+ Img(Shape).yWidth = yWidth\r
+\r
+ A$ = STRING$(xWidth * yWidth, nil)\r
+\r
+ c = 1\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ MID$(A$, c, 1) = CHR$(Grid(X, Y))\r
+ c = c + 1\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ Img(Shape).ImgData = A$\r
+ \r
+\r
+ NEXT Shape\r
+\r
+END SUB\r
+\r
+SUB PAGE.DEMO\r
+\r
+CONST MaxSprites = 64\r
+\r
+DIM Obj(MaxSprites) AS Sprite\r
+DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1)\r
+DIM LastObjects(1)\r
+\r
+ ScreenX = 360: ScreenY = 240\r
+\r
+ IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN\r
+ ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode)\r
+ END IF\r
+\r
+ SET.ACTIVE.PAGE 0\r
+\r
+ CLEAR.VGA.SCREEN c.BLACK\r
+ \r
+ PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK\r
+\r
+ DRAW.LINE 10, 18, 350, 18, c.YELLOW\r
+ PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK\r
+ PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK\r
+ PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK\r
+ PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK\r
+\r
+ PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK\r
+ PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK\r
+ PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK\r
+\r
+ PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK\r
+ PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK\r
+ PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK\r
+\r
+ PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK\r
+ PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK\r
+ PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK\r
+ PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK\r
+ PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK\r
+\r
+\r
+ FOR X = 0 TO 60\r
+ SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X\r
+ SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X\r
+ NEXT X\r
+\r
+ c = 0: DC = 1\r
+ FOR X = 0 TO ScreenX \ 2\r
+ DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50\r
+ DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50\r
+ c = c + DC\r
+ IF c = 0 OR c = 60 THEN DC = -DC\r
+ NEXT X\r
+ \r
+ TPRINT.TEXT "Press <ANY KEY> to Continue", 72, 190, c.bWHITE\r
+ TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN\r
+ TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN\r
+\r
+ TGPRINTC 43, 80, 204, c.YELLOW\r
+ TGPRINTC 45, 200, 204, c.YELLOW\r
+\r
+ TGPRINTC 25, 40, 218, c.YELLOW\r
+ TGPRINTC 24, 200, 218, c.YELLOW\r
+\r
+ COPY.PAGE 0, 1\r
+ COPY.PAGE 0, 2\r
+\r
+ FOR X = 1 TO MaxSprites\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+\r
+ Obj(X).Shape = X MOD MaxShapes\r
+\r
+ SpriteX = Img(Obj(X).Shape).xWidth\r
+ SpriteY = Img(Obj(X).Shape).yWidth\r
+\r
+ Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2)\r
+ Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2)\r
+\r
+ LastX(X, 0) = Obj(X).Xpos\r
+ LastX(X, 1) = Obj(X).Xpos\r
+ LastY(X, 0) = Obj(X).Ypos\r
+ LastY(X, 1) = Obj(X).Ypos\r
+ NEXT X\r
+\r
+ CurrentPage = 0\r
+\r
+ 'View Shift...\r
+\r
+ ViewX = 0\r
+ ViewY = 0\r
+ ViewMax = 3\r
+ ViewCnt = 0\r
+ ViewXD = 1\r
+ ViewYD = 1\r
+\r
+ SetColor = 3: SDir = 1\r
+ PrevColor = 0: PDir = 1\r
+\r
+ VisObjects = MaxSprites \ 2\r
+ LastObjects(0) = 0\r
+ LastObjects(1) = 0\r
+\r
+DRAW.LOOP:\r
+\r
+\r
+ SET.ACTIVE.PAGE CurrentPage\r
+\r
+ ' Erase Old Images\r
+\r
+ FOR X = 1 TO LastObjects(CurrentPage)\r
+ \r
+ X1 = LastX(X, CurrentPage) AND &HFFFC\r
+ Y1 = LastY(X, CurrentPage)\r
+ X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3\r
+ Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1\r
+\r
+ COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1\r
+ \r
+ NEXT X\r
+\r
+ ' Draw new images\r
+\r
+ FOR X = 1 TO VisObjects\r
+\r
+ SpriteX = Img(Obj(X).Shape).xWidth\r
+ SpriteY = Img(Obj(X).Shape).yWidth\r
+\r
+ ' Move Sprite\r
+\r
+REDOX:\r
+ NewX = Obj(X).Xpos + Obj(X).XDir\r
+ IF NewX < 0 OR NewX + SpriteX > ScreenX THEN\r
+ Obj(X).XDir = -Obj(X).XDir\r
+ IF RANDOM.INT(20) = 1 THEN\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+ GOTO REDOX\r
+ END IF\r
+ END IF\r
+ Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir\r
+\r
+REDOY:\r
+ NewY = Obj(X).Ypos + Obj(X).YDir\r
+ IF NewY < 0 OR NewY + SpriteY > ScreenY THEN\r
+ Obj(X).YDir = -Obj(X).YDir\r
+ IF RANDOM.INT(20) = 1 THEN\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+ GOTO REDOY\r
+ END IF\r
+ END IF\r
+ Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir\r
+\r
+ 'Draw Sprite\r
+\r
+ TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY\r
+\r
+ LastX(X, CurrentPage) = Obj(X).Xpos\r
+ LastY(X, CurrentPage) = Obj(X).Ypos\r
+\r
+ NEXT X\r
+\r
+ LastObjects(CurrentPage) = VisObjects\r
+\r
+ ' Pan Screen Back & Forth\r
+\r
+ ViewCnt = ViewCnt + 1\r
+ IF ViewCnt >= ViewMax THEN\r
+ ViewX = ViewX + ViewXD\r
+ IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD\r
+ IF ViewXD < 0 THEN\r
+ ViewY = ViewY + ViewYD\r
+ IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD\r
+ END IF\r
+ \r
+ SET.WINDOW CurrentPage, ViewX, ViewY\r
+\r
+ ViewCnt = 0\r
+ ELSE\r
+ SET.DISPLAY.PAGE CurrentPage\r
+ END IF\r
+\r
+ ' Cycle Colors\r
+\r
+ SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor\r
+ SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor\r
+\r
+ SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor\r
+ SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor\r
+\r
+ SetColor = SetColor + SDir\r
+ IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir\r
+\r
+ PrevColor = PrevColor + PDir\r
+ IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir\r
+\r
+ CurrentPage = 1 - CurrentPage\r
+\r
+ Code = SCAN.KEYBOARD\r
+\r
+ IF Code = False THEN GOTO DRAW.LOOP\r
+\r
+ IF Code = KyPlus THEN\r
+ IF ViewMax < 12 THEN ViewMax = ViewMax + 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+ IF Code = KyMinus THEN\r
+ IF ViewMax > 1 THEN ViewMax = ViewMax - 1\r
+ IF ViewCnt >= ViewMax THEN ViewCnt = 0\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+ IF Code = KyUp THEN\r
+ IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+ \r
+ IF Code = KyDown THEN\r
+ IF VisObjects > 1 THEN VisObjects = VisObjects - 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+\r
+END SUB\r
+\r
+SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB)\r
+\r
+ IF LEN(Text$) = 0 THEN EXIT SUB\r
+\r
+ PRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB\r
+\r
+\r
+END SUB\r
+\r
+SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF)\r
+\r
+ IF LEN(Text$) = 0 THEN EXIT SUB\r
+\r
+ TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF\r
+\r
+END SUB\r
+\r
--- /dev/null
+MASM /DFARSTRINGS utils, utils, utils, nul;
\ No newline at end of file
--- /dev/null
+;=======================================================\r
+;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 ===\r
+;=======================================================\r
+\r
+ PAGE 255, 132\r
+\r
+ .MODEL Medium\r
+ .286\r
+\r
+ ; ==== MACROS ====\r
+\r
+ ; macros to PUSH and POP multiple registers\r
+\r
+PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ push R1 ; Save R1\r
+ PUSHx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ pop R1 ; Restore R1\r
+ POPx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+ ; Macro to Clear a Register to 0\r
+\r
+CLR MACRO Register\r
+ xor Register, Register ; Set Register = 0\r
+ENDM\r
+\r
+ ; Macros to Decrement Counter & Jump on Condition\r
+\r
+LOOPx MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jnz Destination ; Jump if not 0\r
+ENDM\r
+\r
+LOOPjz MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jz Destination ; Jump if 0\r
+ENDM\r
+\r
+\r
+ ; ==== General Constants ====\r
+\r
+ False EQU 0\r
+ True EQU -1\r
+ nil EQU 0\r
+\r
+ b EQU BYTE PTR\r
+ w EQU WORD PTR\r
+ d EQU DWORD PTR\r
+ o EQU OFFSET\r
+ f EQU FAR PTR\r
+ s EQU SHORT\r
+ ?x4 EQU <?,?,?,?>\r
+ ?x3 EQU <?,?,?>\r
+\r
+\r
+IFDEF FARSTRINGS\r
+\r
+ EXTRN stringaddress:far\r
+ EXTRN stringlength:far\r
+\r
+ENDIF\r
+\r
+\r
+ .Data\r
+\r
+ EVEN\r
+\r
+RND_Seed DW 7397, 29447, 802\r
+RND_Mult DW 179, 183, 182\r
+RND_ModV DW 32771, 32779, 32783\r
+\r
+CR_LF DB 13, 10 ; the CRLF data\r
+\r
+ .Code\r
+\r
+;=================\r
+;DOS_PRINT (Text$)\r
+;=================\r
+;\r
+; Prints Text Directly to DOS console w/ CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINT\r
+\r
+DP_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ DP_Text DW ? ; Address of Text$ Descriptor\r
+DP_Stack ENDS\r
+\r
+\r
+DOS_PRINT PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+ push SI ; Push Addr of BC7 Decriptor Ptr\r
+ call stringaddress ; Get Address + Len of string!!!\r
+ ; DX:AX = Addr CX = Len\r
+ mov DS, DX ; DS = DX = Segment of string\r
+ mov DX, AX ; DX = AX = Offset of String\r
+ELSE\r
+ mov CX, [SI] ; put its length into CX\r
+ mov DX, [SI+02] ; now DS:DX points to the String\r
+ENDIF\r
+\r
+ jcxz @No_Print ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@No_Print:\r
+ mov AX, SEG DGROUP ; Restore DGroup\r
+ mov DS, AX\r
+\r
+ mov DX, o CR_LF ; Get Addr of CR/LF pair\r
+ mov CX, 2 ; 2 Characters to Write \r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINT ENDP\r
+\r
+\r
+;==================\r
+;DOS_PRINTS (Text$)\r
+;==================\r
+; \r
+; Print Text$ Directly to DOS console \r
+; without a trailing CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINTS\r
+\r
+DOS_PRINTS PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+ push SI ; Push Addr of BC7 Decriptor Ptr\r
+ call stringaddress ; Get Address + Len of string!!!\r
+ ; DX:AX = Addr CX = Len\r
+ mov DS, DX ; DS = DX = Segment of string\r
+ mov DX, AX ; DX = AX = Offset of String\r
+ELSE\r
+ mov CX, [SI] ; put its length into CX\r
+ mov DX, [SI+02] ; now DS:DX points to the String\r
+ENDIF\r
+\r
+ jcxz @DPS_Exit ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@DPS_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINTS ENDP\r
+\r
+\r
+;======================\r
+;SET_VIDEO_MODE (Mode%) \r
+;======================\r
+;\r
+; Sets the Video Mode through the BIOS\r
+;\r
+\r
+ PUBLIC SET_VIDEO_MODE\r
+\r
+SVM_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ SVM_Mode DB ?,? ; Desired Video Mode\r
+SVM_Stack ENDS\r
+\r
+\r
+SET_VIDEO_MODE PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR AH ; Function 0\r
+ mov AL, [BP].SVM_Mode ; Get Mode #\r
+\r
+ int 10H ; Change Video Modes\r
+\r
+@SVM_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+SET_VIDEO_MODE ENDP\r
+\r
+\r
+;==============\r
+;SCAN_KEYBOARD%\r
+;==============\r
+;\r
+; Function to scan keyboard for a pressed key\r
+;\r
+\r
+ PUBLIC SCAN_KEYBOARD\r
+\r
+SCAN_KEYBOARD PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+\r
+ mov AH, 01H ; Function #1\r
+ int 16H ; Call Keyboard Driver\r
+ jz @SK_NO_KEY ; Exit if Zero flag set\r
+\r
+ mov AH, 00H ; Remove Key from Buffer\r
+ int 16H ; Get Keycode in AX\r
+\r
+ or AL, AL ; Low Byte Set (Ascii?)\r
+ jz @SK_Exit ; if not, it's a F-Key\r
+\r
+ CLR AH ; Clear ScanCode if Ascii\r
+ jmp s @SK_Exit ; Return Key in AX\r
+\r
+@SK_NO_KEY:\r
+ CLR AX ; Return Nil (no Keypress)\r
+\r
+@SK_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret ; Exit & Clean Up Stack\r
+\r
+SCAN_KEYBOARD ENDP\r
+\r
+\r
+;====================\r
+;RANDOM_INT (MaxInt%)\r
+;====================\r
+;\r
+; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
+;\r
+\r
+\r
+ PUBLIC RANDOM_INT\r
+\r
+RI_Stack STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ RI_MaxVal DW ? ; Maximum Value to Return + 1\r
+RI_Stack ENDS\r
+\r
+\r
+RANDOM_INT PROC FAR\r
+\r
+ push BP ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR BX ; BX is the data index\r
+ CLR CX ; CX is the accumulator\r
+\r
+REPT 3\r
+ mov AX, RND_Seed[BX] ; load the initial seed\r
+ mul RND_Mult[BX] ; multiply it\r
+ div RND_ModV[BX] ; and obtain the Mod value\r
+ mov RND_Seed[BX], DX ; save that for the next time\r
+\r
+ add CX, DX ; add it into the accumulator\r
+ inc BX\r
+ inc BX ; point to the next set of values\r
+ENDM\r
+\r
+ mov AX, CX ; AX = Random #\r
+ CLR DX ; DX = 0\r
+ div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder\r
+\r
+ mov AX, DX\r
+\r
+ pop BP ; Restore BP\r
+ ret 2 ; back to BASIC with AX holding the result\r
+\r
+RANDOM_INT ENDP\r
+\r
+\r
+;===========\r
+;INIT_RANDOM\r
+;===========\r
+;\r
+; Scrambles the psuedo-random number sequence\r
+; (XOR's the seed value with the timer)\r
+;\r
+\r
+ PUBLIC INIT_RANDOM\r
+\r
+INIT_RANDOM PROC FAR\r
+\r
+ clr AX ; Segment = 0000\r
+ mov ES, AX\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+\r
+ xor RND_Seed, AX ; Scramble 1st Seed\r
+\r
+ ret ; Exit & Clean Up Stack\r
+\r
+INIT_RANDOM ENDP\r
+\r
+\r
+;====================\r
+;INT_SQR (X%, Round%)\r
+;====================\r
+;\r
+; Returns the Integer Square Root of (X)\r
+; Round allows the return value to be rounded to the \r
+; nearest integer value by passing 0x80. Passing 0\r
+; return the Integer Portion only. The rounding amound is\r
+; a number from 0 to 1 multiplied by 256, thus \r
+; 0.5 * 0x100 = 0x80!\r
+;\r
+\r
+ISQ_Stack STRUC\r
+ DW ?,? ; BP, DI\r
+ DD ? ; Caller\r
+ ISQ_Round DW ? ; Amount to Round Result * 256\r
+ ISQ_X DW ? ; "X"\r
+ISQ_Stack ENDS\r
+\r
+ PUBLIC INT_SQR\r
+\r
+INT_SQR PROC FAR\r
+\r
+ PUSHx BP, DI ; Save BP\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ xor AX, AX ; {xor eax,eax}\r
+ xor DX, DX ; {xor edx,edx}\r
+ mov DI, [BP].ISQ_X ; {mov edi,x}\r
+\r
+ mov CX, 16 ; {mov cx, 32}\r
+\r
+@ISQ_L:\r
+\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl AX, 1 ; {shl eax,1}\r
+ mov BX, AX ; {mov ebx,eax}\r
+ shl BX, 1 ; {shl ebx,1}\r
+ inc BX ; {inc ebx}\r
+ cmp DX, BX ; {cmp edx,ebx}\r
+ jl @ISQ_S\r
+\r
+ sub DX, BX ; {sub edx,ebx}\r
+ inc AX ; {inc eax}\r
+\r
+@ISQ_S: \r
+ loop @ISQ_L\r
+\r
+ add ax, [BP].ISQ_Round ; {add eax,$00008000} \r
+ ; {*round* result in hi word: ie. +0.5}\r
+ shr ax, 8 ; {shr eax,16} {to ax (result)}\r
+\r
+ POPx DI, BP ; Restore Registers \r
+ ret 4 ; Exit\r
+\r
+INT_SQR ENDP\r
+\r
+\r
+;============\r
+;TIMER_COUNT&\r
+;============\r
+;\r
+; Returns the current timer value as an integer/long integer\r
+;\r
+\r
+\r
+ PUBLIC TIMER_COUNT\r
+\r
+TIMER_COUNT PROC FAR\r
+\r
+ clr AX ; Segment = 0000\r
+ mov ES, AX ; use ES to get at data\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+ mov DX, ES:[046Eh] ; Get Timer Hi Word\r
+ ret ; Exit & Return value in DX:AX\r
+\r
+TIMER_COUNT ENDP\r
+\r
+\r
+ END\r
--- /dev/null
+\r
+ ' Misc Constants\r
+\r
+CONST True = -1, False = 0, nil = 0\r
+\r
+ ' Keyboard Codes: Extended\r
+\r
+CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00\r
+CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400\r
+\r
+CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000\r
+CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000\r
+\r
+CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100\r
+CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100\r
+\r
+CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00\r
+CONST KySIns = &HC200, KySDel = &HC300\r
+\r
+CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000\r
+CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300\r
+CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600\r
+CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900\r
+CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400\r
+CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00\r
+CONST KyAltY = &H1500, KyAltZ = &H2C00\r
+\r
+ ' Keyboard Codes: Ascii\r
+\r
+CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F\r
+CONST KyPlus = 45, KyMinus = 43\r
+\r
+ ' Color Constants\r
+\r
+CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3\r
+CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7\r
+CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11\r
+CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15\r
+CONST c.BRIGHT = 8\r
+\r
+ ' From UTILS.ASM\r
+\r
+DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$)\r
+DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$)\r
+DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%)\r
+DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD"\r
+DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%)\r
+DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM"\r
+DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT"\r
+DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%)\r
+\r
--- /dev/null
+;=======================================================\r
+;=== C_UTILS.ASM - Asm Utilities for C/C++ ===\r
+;=======================================================\r
+\r
+ PAGE 255, 132\r
+\r
+ .MODEL Medium\r
+ .286\r
+\r
+ ; ==== MACROS ====\r
+\r
+ ; macros to PUSH and POP multiple registers\r
+\r
+PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ push R1 ; Save R1\r
+ PUSHx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ pop R1 ; Restore R1\r
+ POPx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+ ; Macro to Clear a Register to 0\r
+\r
+CLR MACRO Register\r
+ xor Register, Register ; Set Register = 0\r
+ENDM\r
+\r
+ ; Macros to Decrement Counter & Jump on Condition\r
+\r
+LOOPx MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jnz Destination ; Jump if not 0\r
+ENDM\r
+\r
+LOOPjz MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jz Destination ; Jump if 0\r
+ENDM\r
+\r
+\r
+ ; ==== General Constants ====\r
+\r
+ False EQU 0\r
+ True EQU -1\r
+ nil EQU 0\r
+\r
+ b EQU BYTE PTR\r
+ w EQU WORD PTR\r
+ d EQU DWORD PTR\r
+ o EQU OFFSET\r
+ f EQU FAR PTR\r
+ s EQU SHORT\r
+ ?x4 EQU <?,?,?,?>\r
+ ?x3 EQU <?,?,?>\r
+\r
+\r
+ .Data\r
+\r
+ EVEN\r
+\r
+RND_Seed DW 7397, 29447, 802\r
+RND_Mult DW 179, 183, 182\r
+RND_ModV DW 32771, 32779, 32783\r
+\r
+CR_LF DB 13, 10 ; the CRLF data\r
+\r
+ .Code\r
+\r
+;===========================================\r
+;void far pascal dos_print (far char *Text)\r
+;===========================================\r
+;\r
+; - Print Text Directly to DOS console w/ CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINT\r
+\r
+DP_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ DP_Text DD ? ; Far Address of Text to print\r
+DP_Stack ENDS\r
+\r
+\r
+DOS_PRINT PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+ ; Compute Length of string\r
+\r
+ CLR CX ; Length = 0\r
+ mov SI, DX ; DS:SI = String data\r
+\r
+@@DP_Scan_it:\r
+ \r
+ cmp b [SI], 0 ; Null Byte found?\r
+ je @@DP_Got_Len ; exit loop if so\r
+\r
+ inc CX ; Len++\r
+ inc SI ; Point to next char\r
+ jmp s @@DP_Scan_it ; check again...\r
+\r
+@@DP_Got_len:\r
+\r
+ jcxz @No_Print ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@No_Print:\r
+ mov AX, SEG DGROUP ; Restore DGroup\r
+ mov DS, AX\r
+\r
+ mov DX, o CR_LF ; Get Addr of CR/LF pair\r
+ mov CX, 2 ; 2 Characters to Write \r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 4 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINT ENDP\r
+\r
+\r
+;===========================================\r
+;void far pascal dos_prints (char far *Text)\r
+;===========================================\r
+; \r
+; Print Text Directly to DOS console \r
+; without a trailing CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINTS\r
+\r
+DOS_PRINTS PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+ ; Compute Length of string\r
+\r
+ CLR CX ; Length = 0\r
+ mov SI, DX ; DS:SI = String data\r
+\r
+@@DPS_Scan_it:\r
+ \r
+ cmp b [SI], 0 ; Null Byte found?\r
+ je @@DPS_Got_Len ; exit loop if so\r
+\r
+ inc CX ; Len++\r
+ inc SI ; Point to next char\r
+ jmp s @@DPS_Scan_it ; check again...\r
+\r
+@@DPS_Got_len:\r
+\r
+ jcxz @DPS_Exit ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@DPS_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINTS ENDP\r
+\r
+\r
+;=========================================\r
+;void far pascal set_video_mode (int Mode)\r
+;=========================================\r
+;\r
+; Sets the Video Mode through the BIOS\r
+;\r
+\r
+ PUBLIC SET_VIDEO_MODE\r
+\r
+SVM_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ SVM_Mode DB ?,? ; Desired Video Mode\r
+SVM_Stack ENDS\r
+\r
+\r
+SET_VIDEO_MODE PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR AH ; Function 0\r
+ mov AL, [BP].SVM_Mode ; Get Mode #\r
+\r
+ int 10H ; Change Video Modes\r
+\r
+@SVM_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+SET_VIDEO_MODE ENDP\r
+\r
+\r
+;===================================\r
+;int far pascal scan_keyboard (void)\r
+;===================================\r
+;\r
+; Function to scan keyboard for a pressed key\r
+;\r
+\r
+ PUBLIC SCAN_KEYBOARD\r
+\r
+SCAN_KEYBOARD PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+\r
+ mov AH, 01H ; Function #1\r
+ INT 16H ; Call Keyboard Driver\r
+ JZ @SK_NO_KEY ; Exit if Zero flag set\r
+\r
+ mov AH, 00H ; Remove Key from Buffer\r
+ INT 16H ; Get Keycode in AX\r
+\r
+ OR AL, AL ; Low Byte Set (Ascii?)\r
+ JZ @SK_Exit ; if not, it's a F-Key\r
+\r
+ CLR AH ; Clear ScanCode if Ascii\r
+ JMP s @SK_Exit ; Return Key in AX\r
+\r
+@SK_NO_KEY:\r
+ CLR AX ; Return Nil (no Keypress)\r
+\r
+@SK_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret ; Exit & Clean Up Stack\r
+\r
+SCAN_KEYBOARD ENDP\r
+\r
+\r
+;========================================\r
+;int far pascal random_int (int MaxValue)\r
+;========================================\r
+;\r
+; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
+;\r
+\r
+\r
+ PUBLIC RANDOM_INT\r
+\r
+RI_Stack STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ RI_MaxVal DW ? ; Maximum Value to Return + 1\r
+RI_Stack ENDS\r
+\r
+\r
+RANDOM_INT PROC FAR\r
+\r
+ push BP ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR BX ; BX is the data index\r
+ CLR CX ; CX is the accumulator\r
+\r
+REPT 3\r
+ mov AX, RND_Seed[BX] ; load the initial seed\r
+ mul RND_Mult[BX] ; multiply it\r
+ div RND_ModV[BX] ; and obtain the Mod value\r
+ mov RND_Seed[BX], DX ; save that for the next time\r
+\r
+ add CX, DX ; add it into the accumulator\r
+ inc BX\r
+ inc BX ; point to the next set of values\r
+ENDM\r
+\r
+ mov AX, CX ; AX = Random #\r
+ CLR DX ; DX = 0\r
+ div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder\r
+\r
+ mov AX, DX\r
+\r
+ pop BP ; Restore BP\r
+ ret 2 ; back to BASIC with AX holding the result\r
+\r
+RANDOM_INT ENDP\r
+\r
+\r
+;==================================\r
+;void far pascal init_random (void)\r
+;==================================\r
+;\r
+; Scrambles the psuedo-random number sequence\r
+; (XOR's the seed value with the timer)\r
+;\r
+\r
+ PUBLIC INIT_RANDOM\r
+\r
+INIT_RANDOM PROC FAR\r
+\r
+ CLR AX ; Segment = 0000\r
+ mov ES, AX\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+\r
+ xor RND_Seed, AX ; Scramble 1st Seed\r
+\r
+ ret ; Exit & Clean Up Stack\r
+\r
+INIT_RANDOM ENDP\r
+\r
+;=========================================\r
+;int far pascal int_sqr (int X, int Round)\r
+;=========================================\r
+;\r
+; Returns the Integer Square Root of (X)\r
+; Round allows the return value to be rounded to the \r
+; nearest integer value by passing 0x80. Passing 0\r
+; return the Integer Portion only. The rounding amound is\r
+; a number from 0 to 1 multiplied by 256, thus \r
+; 0.5 * 0x100 = 0x80!\r
+;\r
+\r
+ISQ_Stack STRUC\r
+ DW ?,? ; BP, DI\r
+ DD ? ; Caller\r
+ ISQ_Round DW ? ; Amount to Round Result * 256\r
+ ISQ_X DW ? ; "X"\r
+ISQ_Stack ENDS\r
+\r
+ PUBLIC INT_SQR\r
+\r
+INT_SQR PROC FAR\r
+\r
+ PUSHx BP, DI ; Save BP\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ xor AX, AX ; {xor eax,eax}\r
+ xor DX, DX ; {xor edx,edx}\r
+ mov DI, [BP].ISQ_X ; {mov edi,x}\r
+\r
+ mov CX, 16 ; {mov cx, 32}\r
+\r
+@ISQ_L:\r
+\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl AX, 1 ; {shl eax,1}\r
+ mov BX, AX ; {mov ebx,eax}\r
+ shl BX, 1 ; {shl ebx,1}\r
+ inc BX ; {inc ebx}\r
+ cmp DX, BX ; {cmp edx,ebx}\r
+ jl @ISQ_S\r
+\r
+ sub DX, BX ; {sub edx,ebx}\r
+ inc AX ; {inc eax}\r
+\r
+@ISQ_S: \r
+ loop @ISQ_L\r
+\r
+ add ax, [BP].ISQ_Round ; {add eax,$00008000} \r
+ ; {*round* result in hi word: ie. +0.5}\r
+ shr ax, 8 ; {shr eax,16} {to ax (result)}\r
+\r
+ POPx DI, BP ; Restore Registers \r
+ ret 4 ; Exit\r
+\r
+INT_SQR ENDP\r
+\r
+;=================================\r
+;int far pascal timer_count (void)\r
+;=================================\r
+;\r
+; Returns the current timer value as an integer/long integer\r
+;\r
+\r
+ PUBLIC TIMER_COUNT\r
+\r
+TIMER_COUNT PROC FAR\r
+\r
+ CLR AX ; Segment = 0000\r
+ mov ES, AX\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+ mov DX, ES:[046Eh] ; Get Timer Hi Word\r
+ ret ; Exit & Clean Up Stack\r
+\r
+TIMER_COUNT ENDP\r
+\r
+\r
+ END\r
--- /dev/null
+\r
+#ifndef __C_UTILS_H\r
+#define __C_UTILS_H\r
+\r
+\r
+ /* Misc Constants */\r
+\r
+#define True -1\r
+#define False 0\r
+#define nil 0\r
+\r
+ /* Color Constants */\r
+\r
+#define c_BLACK 0\r
+#define c_BLUE 1\r
+#define c_GREEN 2\r
+#define c_CYAN 3\r
+#define c_RED 4\r
+#define c_PURPLE 5\r
+#define c_BROWN 6\r
+#define c_WHITE 7\r
+#define c_GREY 8\r
+#define c_bBLUE 9\r
+#define c_bGREEN 10\r
+#define c_bCYAN 11\r
+#define c_bRED 12\r
+#define c_bPURPLE 13\r
+#define c_YELLOW 14\r
+#define c_bWHITE 15\r
+#define c_BRIGHT 16\r
+\r
+\r
+#define Ky_F1 0x3B00\r
+#define Ky_F2 0x3C00\r
+#define Ky_F3 0x3D00\r
+#define Ky_F4 0x3E00\r
+#define Ky_F5 0x3F00\r
+#define Ky_F6 0x4000\r
+#define Ky_F7 0x4100\r
+#define Ky_F8 0x4200\r
+#define Ky_F9 0x4300\r
+#define Ky_F10 0x4400\r
+\r
+#define Ky_Up 0x4800\r
+#define Ky_Left 0x4B00\r
+#define Ky_Right 0x4D00\r
+#define Ky_Down 0x5000\r
+#define Ky_SUp 0xC800\r
+#define Ky_SLeft 0xCB00\r
+#define Ky_SRight 0xCD00\r
+#define Ky_SDown 0xD000\r
+\r
+#define Ky_Home 0x4700\r
+#define Ky_End 0x4F00\r
+#define Ky_PgUp 0x4900\r
+#define Ky_PgDn 0x5100\r
+#define Ky_SHome 0xC700\r
+#define Ky_SEnd 0xCF00\r
+#define Ky_SPgUp 0xC900\r
+#define Ky_SPgDn 0xD100\r
+\r
+#define Ky_Ins 0x5200\r
+#define Ky_Del 0x5300\r
+#define Ky_SIns 0xC200\r
+#define Ky_SDel 0xC300\r
+\r
+#define Ky_Tab 0x0009\r
+#define Ky_RvsTab 0x8F00\r
+#define Ky_STab 0x8F00\r
+\r
+#define Ky_BS 0x0008\r
+#define Ky_CR 0x000D\r
+#define Ky_ESC 0x001B\r
+#define Ky_Clr 0x007F\r
+\r
+#define Ky_Plus 0x002D\r
+#define Ky_Minus 0x002B\r
+\r
+#define Ky_AltA 0x1E00\r
+#define Ky_AltB 0x3000\r
+#define Ky_AltC 0x2E00\r
+#define Ky_AltD 0x2000\r
+#define Ky_AltE 0x1200\r
+#define Ky_AltF 0x2100\r
+#define Ky_AltG 0x2200\r
+#define Ky_AltH 0x2300\r
+#define Ky_AltI 0x1700\r
+#define Ky_AltJ 0x2400\r
+#define Ky_AltK 0x2500\r
+#define Ky_AltL 0x2600\r
+#define Ky_AltM 0x3200\r
+#define Ky_AltN 0x3100\r
+#define Ky_AltO 0x1800\r
+#define Ky_AltP 0x1900\r
+#define Ky_AltQ 0x1000\r
+#define Ky_AltR 0x1300\r
+#define Ky_AltS 0x1F00\r
+#define Ky_AltT 0x1400\r
+#define Ky_AltU 0x1600\r
+#define Ky_AltV 0x2F00\r
+#define Ky_AltW 0x1100\r
+#define Ky_AltX 0x2D00\r
+#define Ky_AltY 0x1500\r
+#define Ky_AltZ 0x2C00\r
+\r
+ /* .ASM Functions From C_UTILS.ASM */\r
+\r
+void far pascal dos_print (char far *Text);\r
+void far pascal dos_prints (char far *Text);\r
+void far pascal set_video_mode (int Mode);\r
+int far pascal scan_keyboard (void);\r
+int far pascal random_int (int MaxValue);\r
+void far pascal init_random (void);\r
+int far pascal int_sqr (int X, int Round);\r
+int far pascal timer_count (void);\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+ \r
+#ifndef __MODEX_H\r
+#define __MODEX_H\r
+ \r
+ /* ===== SCREEN RESOLUTIONS ===== */\r
+ \r
+#define Mode_320x200 0\r
+#define Mode_320x400 1\r
+#define Mode_360x200 2\r
+#define Mode_360x400 3\r
+#define Mode_320x240 4\r
+#define Mode_320x480 5\r
+#define Mode_360x240 6\r
+#define Mode_360x480 7\r
+ \r
+ /* ===== MODE X SETUP ROUTINES ===== */\r
+ \r
+int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages);\r
+int far pascal set_modex (int Mode);\r
+ \r
+ /* ===== BASIC GRAPHICS PRIMITIVES ===== */\r
+ \r
+void far pascal clear_vga_screen (int Color);\r
+void far pascal set_point (int Xpos, int Ypos, int Color);\r
+int far pascal read_point (int Xpos, int Ypos);\r
+void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2,\r
+ int Color);\r
+void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2,\r
+ int Color);\r
+ \r
+ /* ===== DAC COLOR REGISTER ROUTINES ===== */\r
+ \r
+void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue);\r
+void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue);\r
+void far pascal load_dac_registers (char far *PalData, int StartReg,\r
+ int EndReg, int VSync);\r
+void far pascal readd_dac_registers (char far *PalData, int StartReg,\r
+ int EndReg);\r
+ \r
+ /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */\r
+ \r
+void far pascal set_active_page (int PageNo);\r
+int far pascal get_active_page (void);\r
+void far pascal set_display_page (int PageNo);\r
+int far pascal get_display_page (void);\r
+void far pascal set_window (int DisplayPage, int XOffset, int YOffset);\r
+int far pascal get_x_offset (void);\r
+int far pascal get_y_offset (void);\r
+void far pascal sync_display (void);\r
+ \r
+ /* ===== TEXT DISPLAY ROUTINES ===== */\r
+ \r
+void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF,\r
+ int ColorB);\r
+void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF);\r
+void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos,\r
+ int ColorF, int ColorB);\r
+void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos,\r
+ int ColorF);\r
+void far pascal set_display_font (char far *FontData, int FontNumber);\r
+ \r
+ /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */\r
+ \r
+void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos,\r
+ int Width, int Height);\r
+void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos,\r
+ int Width, int Height);\r
+ \r
+ /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */\r
+ \r
+void far pascal copy_page (int SourcePage, int DestPage);\r
+void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2,\r
+ int DestPage, int DestX1, int DestY1);\r
+ \r
+ \r
+#endif\r
--- /dev/null
+MASM c_utils, c_utils, c_utils, nul;
\ No newline at end of file
--- /dev/null
+/* X-DEMO.C - a Mode "X" Demo */\r
+/* By Matt Pritchard, 14 Apr, 1993 */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+\r
+#include "modex.h"\r
+#include "c_utils.h"\r
+\r
+#define MAX_SHAPES 32\r
+#define MAX_SPRITES 64\r
+\r
+ /* routines in this file */\r
+\r
+void demo_res (int, int, int);\r
+int get_key (void);\r
+void error_out (char*);\r
+void load_shapes (void);\r
+int int_sqrt (int, int);\r
+void page_demo (void);\r
+\r
+ /* Structures for Sprites */\r
+\r
+struct Shape\r
+{\r
+ unsigned char Image[512];\r
+ int X_Width;\r
+ int Y_Width;\r
+} Img [MAX_SHAPES];\r
+\r
+struct Sprite\r
+{\r
+ int X_pos;\r
+ int Y_pos;\r
+ int X_Dir;\r
+ int Y_Dir;\r
+ int Shape;\r
+ int Last_X [2];\r
+ int Last_Y [2];\r
+} Obj [MAX_SPRITES];\r
+\r
+\r
+ /* MAIN */\r
+\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+\r
+ /* if (argc > 0)\r
+ {\r
+ while (argc > 0)\r
+ {\r
+ dos_print ("Unknown Argument: ");\r
+ dos_print (makefp argv[argc]);\r
+ argc--;\r
+ }\r
+ return (0);\r
+\r
+ }\r
+ */\r
+\r
+ init_random ();\r
+\r
+ load_shapes ();\r
+\r
+ demo_res ( Mode_320x200, 320, 200 );\r
+ demo_res ( Mode_320x400, 320, 400 );\r
+\r
+ demo_res ( Mode_360x200, 360, 200 );\r
+ demo_res ( Mode_360x400, 360, 400 );\r
+\r
+ demo_res ( Mode_320x240, 320, 240 );\r
+ demo_res ( Mode_320x480, 320, 480 );\r
+\r
+ demo_res ( Mode_360x240, 360, 240 );\r
+ demo_res ( Mode_360x480, 360, 480 );\r
+\r
+ page_demo ();\r
+\r
+ set_video_mode (3);\r
+ dos_print ("This Mode X Demo is Finished");\r
+ return (0);\r
+\r
+}\r
+\r
+\r
+ /* Demonstrate a given resolution */\r
+\r
+\r
+void demo_res (int Screen_Mode, int X_max, int Y_max)\r
+{\r
+\r
+char *Error1 = "Failure while calling SET_MODEX";\r
+char *Error2 = "Failure during READ_PIXEL test";\r
+\r
+char *Abort_Msg = "Demo aborted by User";\r
+\r
+char *Demo_Msg = " This is a MODE X demo ";\r
+char *Scrn_Msg = "Screen Resolution is by ";\r
+char *Cont_Msg = "Press <ANY KEY> to Continue";\r
+\r
+char *Line_Msg = "LINE TEST";\r
+char *Fill_Msg = "FILL TEST";\r
+char *Pixel_Msg = "PIXEL TEST";\r
+\r
+char Text[10];\r
+\r
+int x1, y1, x2, y2 = 0;\r
+int x, y, z = 0;\r
+int X_Center, gap = 0;\r
+\r
+\r
+ if (set_modex (Screen_Mode) == 0)\r
+ {\r
+ error_out (Error1);\r
+ }\r
+\r
+ X_Center = X_max / 2;\r
+\r
+ x1 = 10;\r
+ y1 = 10;\r
+ x2 = X_max - 1;\r
+ y2 = Y_max - 1;\r
+\r
+ for (z = 0; z <= 3; z++)\r
+ {\r
+ y = 31 - z -z;\r
+ draw_line (x1+z, y1+z, x2-z, y1+z, y);\r
+ draw_line (x1+z, y1+z, x1+z, y2-z, y);\r
+ draw_line (x1+z, y2-z, x2-z, y2-z, y);\r
+ draw_line (x2-z, y1+z, x2-z, y2-z, y);\r
+ }\r
+\r
+ for (x = 0; x < (X_max / 10); x++)\r
+ {\r
+ tgprintc (48 + ((x+1) % 10), x*10+1, 1, 9 + ((x/8) % 7) );\r
+ draw_line (x*10+9, 0, x*10+9, 3, c_bWHITE);\r
+ }\r
+\r
+ for (y = 0; y < (Y_max / 10); y++)\r
+ {\r
+ tgprintc (48 + ((y+1) % 10), 1, y*10+1, 9 + ((y/10) % 7) );\r
+ draw_line (0, y*10+9, 3, y*10+9, c_bWHITE);\r
+ }\r
+\r
+ for (x = 0; x <= 63; x++)\r
+ {\r
+ z = 15 + (x * 3 / 4);\r
+ set_dac_register (64+x, z, z, z);\r
+ set_dac_register (128+x, 0, z, z);\r
+\r
+ draw_line (103-x, 60, 40+x, 123, 64+x);\r
+ draw_line (40, 60+x, 103, 123-x, 128+x);\r
+\r
+ }\r
+\r
+ tprint_str (Line_Msg, 9, 37, 130, c_BLUE);\r
+\r
+ y = 60;\r
+ gap = 0;\r
+ for (x = 0; x <= 9; x++)\r
+ {\r
+ fill_block (120, y, 120+x, y+gap, 64+x);\r
+ fill_block (140 - (15-x), y, 150+x, y+gap, 230+x);\r
+ fill_block (170 - (15-x), y, 170, y+gap, 128+x);\r
+ y = y + gap + 2;\r
+ gap++;\r
+ }\r
+\r
+ tprint_str (Fill_Msg, 9, 110, 46, c_GREEN);\r
+\r
+ for (x = 190; x <= 250; x+=2)\r
+ {\r
+ for (y = 60; y <= 122; y+=2)\r
+ {\r
+ z = (x+x+y+y) & 0xff;\r
+ set_point (x, y, z);\r
+ }\r
+ }\r
+\r
+ tprint_str (Pixel_Msg, 10, 182, 130, c_RED);\r
+\r
+ for (x = 190; x <= 250; x+=2)\r
+ {\r
+ for (y = 60; y <= 122; y+=2)\r
+ {\r
+ z = (x+x+y+y) & 0xff;\r
+ if (read_point(x, y) != z)\r
+ {\r
+ error_out (Error2);\r
+ }\r
+ }\r
+ }\r
+\r
+ print_str (Demo_Msg, 23, X_Center - 92, 20, c_bRED, c_BLUE);\r
+\r
+ x = X_Center - 124;\r
+ print_str (Scrn_Msg, 28, x, 30, c_bGREEN, c_BLACK);\r
+\r
+ sprintf (Text, "%3d", X_max);\r
+ print_str (Text, 3, x+168, 30, c_bPURPLE, c_BLACK);\r
+\r
+ sprintf (Text, "%3d", Y_max);\r
+ print_str (Text, 3, x + 224, 30, c_bWHITE, c_BLACK);\r
+\r
+ for (x = 0; x <= 15; x++)\r
+ {\r
+ set_dac_register (230+x, 63-x*4, 0, 15+x*3);\r
+ draw_line (30+x, Y_max-6-x, X_max-20-x, Y_max-6-x, 230+x);\r
+ }\r
+\r
+ tprint_str (Cont_Msg, 27, X_Center - 103, Y_max-18, c_YELLOW);\r
+\r
+ if (get_key () == Ky_ESC)\r
+ {\r
+ error_out (Abort_Msg);\r
+ }\r
+\r
+ return ;\r
+\r
+}\r
+\r
+\r
+ /* Wait for a Keystroke */\r
+\r
+\r
+int get_key(void)\r
+{\r
+\r
+int c = 0;\r
+\r
+ while (c == 0)\r
+ {\r
+ c = scan_keyboard ();\r
+ }\r
+\r
+ return (c);\r
+\r
+}\r
+\r
+\r
+ /* Error Handling Routine */\r
+\r
+\r
+void error_out (char * text)\r
+{\r
+\r
+ set_video_mode (3);\r
+ dos_print (text);\r
+ exit (EXIT_SUCCESS);\r
+\r
+}\r
+\r
+\r
+ /* Routine to generate random sprites */\r
+\r
+\r
+void load_shapes ()\r
+{\r
+\r
+unsigned char Grid[33][33];\r
+\r
+char *Error1 = "Bad Shape Selected Error";\r
+\r
+int Shape;\r
+int x, y, z;\r
+int Style, Color;\r
+int X_Width, Y_Width, Center, S_Width;\r
+int Hollow_X, Hollow_Y;\r
+\r
+ for (Shape = 0; Shape < MAX_SHAPES; Shape++)\r
+ {\r
+ for (y = 0; y <= 32; y++)\r
+ {\r
+ for (x = 0; x <= 32; x++)\r
+ {\r
+ Grid[x][y] = c_BLACK;\r
+ }\r
+ }\r
+\r
+ Style = random_int (6);\r
+ Color = 1 + random_int (15);\r
+\r
+ switch (Style)\r
+\r
+ {\r
+ /* SOLID BOXES */\r
+\r
+ case 0:\r
+\r
+ {\r
+ do\r
+ {\r
+ X_Width = 3 + random_int(30);\r
+ Y_Width = 3 + random_int(30);\r
+\r
+ } while ( (X_Width * Y_Width) >= 512);\r
+\r
+ for (x = 1; x <= X_Width; x++)\r
+ {\r
+ for (y = 1; y <= Y_Width; y++)\r
+ {\r
+ Grid[x][y] = Color;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ }\r
+ /* HOLLOW BOXES */\r
+\r
+ case 1:\r
+\r
+ {\r
+ do {\r
+ X_Width = 6 + random_int(27);\r
+ Y_Width = 6 + random_int(27);\r
+ } while ( (X_Width * Y_Width) >= 512);\r
+\r
+ for (y = 1; y <= Y_Width; y++)\r
+ {\r
+ for (x = 1; x <= X_Width; x++)\r
+ {\r
+ Grid[x][y] = Color;\r
+ }\r
+ }\r
+\r
+ Hollow_X = 1 + random_int ((X_Width / 2) -1);\r
+ Hollow_Y = 1 + random_int ((Y_Width / 2) -1);\r
+\r
+ for (y = Hollow_Y+1; y <= Y_Width-Hollow_Y; y++)\r
+ {\r
+ for (x = Hollow_X+1; x <= X_Width-Hollow_X; x++)\r
+ {\r
+ Grid[x][y] = c_BLACK;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ }\r
+\r
+ /* SOLID DIAMOND */\r
+\r
+ case 2:\r
+\r
+ {\r
+\r
+ X_Width = 3 + 2 * random_int(10);\r
+ Y_Width = X_Width;\r
+ Center = X_Width / 2;\r
+\r
+ for (y = 0; y <= Center; y++)\r
+ {\r
+ for (x = 0; x <= y; x++)\r
+ {\r
+ Grid [Center-x+1][y+1] = Color;\r
+ Grid [Center+x+1][y+1] = Color;\r
+ Grid [Center-x+1][Y_Width-y] = Color;\r
+ Grid [Center+x+1][Y_Width-y] = Color;\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ }\r
+\r
+ /* HOLLOW DIAMOND */\r
+\r
+ case 3:\r
+\r
+ {\r
+\r
+ X_Width = 3 + 2 * random_int(10);\r
+ Y_Width = X_Width;\r
+ Center = X_Width / 2;\r
+ S_Width = random_int (Center);\r
+\r
+ for (y = 0; y <= Center; y++)\r
+ {\r
+ for (x = 0; x <= y; x++)\r
+ {\r
+ if ( x+(Center-y) >= S_Width )\r
+ {\r
+ Grid [Center-x+1][y+1] = Color;\r
+ Grid [Center+x+1][y+1] = Color;\r
+ Grid [Center-x+1][Y_Width-y] = Color;\r
+ Grid [Center+x+1][Y_Width-y] = Color;\r
+ }\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ }\r
+\r
+ /* BALL */\r
+\r
+ case 4:\r
+\r
+ {\r
+\r
+ X_Width = 7 + 2 * random_int (8);\r
+ Y_Width = X_Width;\r
+ Center = 1 + X_Width / 2;\r
+\r
+ for (y = 1; y <= Y_Width; y++)\r
+ {\r
+ for (x = 1; x <= X_Width; x++)\r
+ {\r
+ z = int_sqrt(Center-x, Center-y);\r
+ if (z < Center)\r
+ {\r
+ Grid[x][y] = 150 + Color * 2 + z * 3;\r
+ }\r
+ }\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ /* HOLLOW BALLS */\r
+\r
+ case 5:\r
+\r
+ {\r
+ X_Width = 7 + 2 * random_int (8);\r
+ Y_Width = X_Width;\r
+ Center = 1 + X_Width / 2;\r
+ S_Width = random_int (X_Width);\r
+\r
+ for (y = 1; y <= Y_Width; y++)\r
+ {\r
+ for (x = 1; x <= X_Width; x++)\r
+ {\r
+ z = int_sqrt(Center-x, Center-y);\r
+ if ( (z < Center) && (z >= S_Width) )\r
+ {\r
+ Grid[x][y] = 150 + Color * 2 + z * 3;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ break;\r
+ }\r
+\r
+ default:\r
+\r
+ {\r
+ error_out (Error1);\r
+ break;\r
+\r
+ }\r
+\r
+ }\r
+\r
+ z = 0;\r
+ for (y = 1; y <= Y_Width; y++)\r
+ {\r
+ for (x = 1; x <= X_Width; x++)\r
+ {\r
+ Img[Shape].Image[z] = Grid[x][y];\r
+ z++;\r
+ }\r
+ }\r
+\r
+ Img[Shape].X_Width = X_Width;\r
+ Img[Shape].Y_Width = Y_Width;\r
+\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+\r
+ /* Quickie Psuedo Integer Square Root Routine */\r
+\r
+\r
+int int_sqrt ( int x, int y )\r
+{\r
+\r
+int Sqr_Table[12] = {1, 4, 9, 6, 25, 36, 49, 64, 81, 100, 121, 144};\r
+\r
+int r, d;\r
+\r
+ d = (x * x) + (y * y);\r
+ r = 0;\r
+\r
+ while ( d >= Sqr_Table[r] )\r
+ {\r
+ r++;\r
+ }\r
+\r
+ return (r);\r
+\r
+}\r
+\r
+\r
+ /* The Bit Sprite Demo */\r
+\r
+\r
+void page_demo ()\r
+{\r
+\r
+char *Error1 = "Failure during SET_VGA_MODEX (0, 360, 240, 3) call";\r
+\r
+int Last_Objects[2], Visible_Objects;\r
+\r
+int Screen_X = 360;\r
+int Screen_Y = 240;\r
+\r
+int x, y, z;\r
+int c, dc;\r
+int x1, y1, x2, y2;\r
+\r
+int Sprite_X, Sprite_Y;\r
+int Current_Page;\r
+int New_X, New_Y;\r
+\r
+int View_X, View_Y, View_Max, View_Cnt, View_XD, View_YD;\r
+int Set_Color, Prev_Color, S_Dir, P_Dir;\r
+\r
+int Demo_Running = True;\r
+int redo, code;\r
+\r
+ if (set_vga_modex(Mode_320x200, Screen_X, Screen_Y, 3) == 0)\r
+ {\r
+ error_out (Error1);\r
+ }\r
+\r
+ set_active_page (0);\r
+ clear_vga_screen (c_BLACK);\r
+\r
+ print_str ("This is a Test of the Following Functions:", 99, 10, 9, c_bWHITE, c_BLACK);\r
+\r
+ draw_line (10, 18, 350, 18, c_YELLOW);\r
+ print_str ("SET_ACTIVE_PAGE", 99, 10, 20, c_bBLUE, c_BLACK);\r
+ print_str ("SET_DISPLAY_PAGE", 99, 10, 30, c_GREEN, c_BLACK);\r
+ print_str ("SET_DAC_REGISTER", 99, 10, 40, c_RED, c_BLACK);\r
+ print_str ("CLEAR_VGA_SCREEN", 99, 10, 50, c_CYAN, c_BLACK);\r
+\r
+ print_str ("TDRAW_BITMAP", 99, 10, 60, c_PURPLE, c_BLACK);\r
+ print_str ("COPY_PAGE", 99, 10, 70, c_GREEN, c_BLACK);\r
+ print_str ("COPY_BITMAP", 99, 10, 80, c_CYAN, c_BLACK);\r
+\r
+ print_str ("GPRINTC", 99, 10, 90, c_BLUE, c_BLACK);\r
+ print_str ("TGPRINTC", 99, 10, 100, c_GREEN, c_BLACK);\r
+ print_str ("SET_WINDOW", 99, 10, 110, c_RED, c_BLACK);\r
+\r
+ print_str ("VIRTUAL SCREEN SIZES", 20, 190, 20, c_bBLUE, c_BLACK);\r
+ print_str (" SMOOTH SCROLLING", 20, 190, 30, c_GREEN, c_BLACK);\r
+ print_str (" SPRITE ANIMATION", 20, 190, 40, c_CYAN, c_BLACK);\r
+ print_str (" PAGE FLIPPING", 20, 190, 50, c_RED, c_BLACK);\r
+ print_str (" COLOR CYCLING", 20, 190, 60, c_PURPLE, c_BLACK);\r
+\r
+ for (x = 0; x <=60; x++)\r
+ {\r
+ set_dac_register (50 + x, 3 + x, 0, 60 - x);\r
+ set_dac_register (150 + x, 3 + x, 0, 60 - x);\r
+ }\r
+\r
+ c = 0;\r
+ dc = 1;\r
+ for (x = 0; x <= (Screen_X / 2); x++)\r
+ {\r
+ draw_line (Screen_X / 2 - 1, Screen_Y / 4, x, Screen_Y - 1, c + 50);\r
+ draw_line (Screen_X / 2, Screen_Y / 4, Screen_X - x - 1, Screen_Y - 1, c + 50);\r
+ c+= dc;\r
+ if ((c == 0) || (c == 60) ) { dc = -dc;}\r
+ }\r
+\r
+ tprint_str ("Press <ANY KEY> to Continue", 99, 72, 190, c_bWHITE);\r
+ tprint_str ("< > = Faster < > = Slower", 99, 72, 204, c_bGREEN);\r
+ tprint_str ("< > = Fewer Shapes < > = More Shapes", 99, 32, 218, c_bCYAN);\r
+\r
+ tgprintc (43, 80, 204, c_YELLOW);\r
+ tgprintc (45, 200, 204, c_YELLOW);\r
+\r
+ tgprintc (25, 40, 218, c_YELLOW);\r
+ tgprintc (24, 200, 218, c_YELLOW);\r
+\r
+ copy_page (0, 1);\r
+ copy_page (0, 2);\r
+\r
+ for (x = 0; x < MAX_SPRITES; x++)\r
+ {\r
+ do {\r
+ Obj[x].X_Dir = random_int(7) - 3;\r
+ Obj[x].Y_Dir = random_int(7) - 3;\r
+ } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) );\r
+\r
+ Obj[x].Shape = x % MAX_SHAPES;\r
+\r
+ Sprite_X = Img[Obj[x].Shape].X_Width;\r
+ Sprite_Y = Img[Obj[x].Shape].Y_Width;\r
+\r
+ Obj[x].X_pos = 1 + random_int(Screen_X - Sprite_X - 2);\r
+ Obj[x].Y_pos = 1 + random_int(Screen_Y - Sprite_Y - 2);\r
+\r
+ Obj[x].Last_X[0] = Obj[x].X_pos;\r
+ Obj[x].Last_X[1] = Obj[x].X_pos;\r
+ Obj[x].Last_Y[0] = Obj[x].Y_pos;\r
+ Obj[x].Last_Y[1] = Obj[x].Y_pos;\r
+\r
+ }\r
+\r
+ Current_Page = 0;\r
+\r
+ View_X = 0;\r
+ View_Y = 0;\r
+ View_Max = 3;\r
+ View_Cnt = 0;\r
+ View_XD = 1;\r
+ View_YD = 1;\r
+\r
+ Set_Color = 3;\r
+ S_Dir = 1;\r
+ Prev_Color = 0;\r
+ P_Dir = 1;\r
+\r
+ Visible_Objects = MAX_SPRITES / 2;\r
+ Last_Objects[0] = 0;\r
+ Last_Objects[1] = 0;\r
+\r
+ while (Demo_Running)\r
+ {\r
+\r
+ set_active_page (Current_Page);\r
+\r
+ /* Erase Old Images */\r
+\r
+ for (x = 0; x <= Last_Objects[Current_Page]; x++)\r
+ {\r
+ z = 2;\r
+ y = Obj[x].Shape;\r
+ x1 = Obj[x].Last_X[Current_Page];\r
+ y1 = Obj[x].Last_Y[Current_Page];\r
+ x2 = x1 + Img[y].X_Width -1;\r
+ y2 = y1 + Img[y].Y_Width -1;\r
+\r
+ x1 = x1 & 0xfffc;\r
+ x2 = x2 | 0x0003;\r
+\r
+ copy_bitmap (z, x1, y1, x2, y2, Current_Page, x1, y1);\r
+ }\r
+\r
+ /* Draw new images */\r
+\r
+ for (x = 0; x <= Visible_Objects; x++)\r
+ {\r
+ Sprite_X = Img[Obj[x].Shape].X_Width;\r
+ Sprite_Y = Img[Obj[x].Shape].Y_Width;\r
+\r
+ /* Move Sprite */\r
+\r
+ do\r
+ {\r
+ redo = False;\r
+ New_X = Obj[x].X_pos + Obj[x].X_Dir;\r
+\r
+ if (( New_X < 0 ) || (New_X + Sprite_X > Screen_X) )\r
+ {\r
+ Obj[x].X_Dir = -Obj[x].X_Dir;\r
+ if (random_int(20) == 1)\r
+ {\r
+ do\r
+ {\r
+ Obj[x].X_Dir = random_int(7) - 3;\r
+ Obj[x].Y_Dir = random_int(7) - 3;\r
+ } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) );\r
+ redo = True;\r
+ }\r
+ }\r
+ } while (redo);\r
+ Obj[x].X_pos = Obj[x].X_pos + Obj[x].X_Dir;\r
+\r
+\r
+ do\r
+ {\r
+ redo = False;\r
+ New_Y = Obj[x].Y_pos + Obj[x].Y_Dir;\r
+\r
+ if ( (New_Y < 0) || (New_Y + Sprite_Y > Screen_Y) )\r
+ {\r
+ Obj[x].Y_Dir = -Obj[x].Y_Dir;\r
+ if (random_int(20) == 1)\r
+ {\r
+ do\r
+ {\r
+ Obj[x].X_Dir = random_int(7) - 3;\r
+ Obj[x].Y_Dir = random_int(7) - 3;\r
+ } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) );\r
+ redo = True;\r
+ }\r
+ }\r
+ } while (redo);\r
+\r
+ Obj[x].Y_pos = Obj[x].Y_pos + Obj[x].Y_Dir;\r
+\r
+ /* Draw Sprite */\r
+\r
+ tdraw_bitmap ((char far*) &Img[Obj[x].Shape], Obj[x].X_pos, Obj[x].Y_pos, Sprite_X, Sprite_Y);\r
+\r
+ Obj[x].Last_X[Current_Page] = Obj[x].X_pos;\r
+ Obj[x].Last_Y[Current_Page] = Obj[x].Y_pos;\r
+\r
+ }\r
+\r
+ Last_Objects[Current_Page] = Visible_Objects;\r
+\r
+\r
+ /* Pan Screen Back & Forth */\r
+\r
+ View_Cnt++;\r
+ if (View_Cnt >= View_Max)\r
+ {\r
+ View_X+= View_XD;\r
+ if ( (View_X == 0) || (View_X == 39) ) {View_XD = -View_XD;}\r
+ if (View_XD < 0)\r
+ {\r
+ View_Y+= View_YD;\r
+ if ( (View_Y == 0) || (View_Y == 39) ) {View_YD = -View_YD;}\r
+ }\r
+\r
+ set_window (Current_Page, View_X, View_Y);\r
+\r
+ View_Cnt = 0;\r
+ }\r
+ else\r
+ {\r
+ set_display_page (Current_Page);\r
+ }\r
+\r
+ /* Cycle Colors */\r
+\r
+ set_dac_register (50 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color);\r
+ set_dac_register (50 + Set_Color, Set_Color, 10, 63 - Set_Color);\r
+\r
+ set_dac_register (150 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color);\r
+ set_dac_register (150 + Set_Color, 63, 63, Set_Color);\r
+\r
+ Set_Color+= S_Dir;\r
+ if ( (Set_Color == 60) || (Set_Color == 0) ) {S_Dir = -S_Dir;}\r
+\r
+ Prev_Color+= P_Dir;\r
+ if ( (Prev_Color == 60) || (Prev_Color == 0) ) {P_Dir = -P_Dir;}\r
+\r
+ /* Check for Keystroke */\r
+\r
+ Current_Page = Current_Page ^ 0x01;\r
+\r
+ code = scan_keyboard ();\r
+\r
+ if (code == Ky_ESC) {Demo_Running = False;}\r
+\r
+ if (code == Ky_Plus)\r
+ {\r
+ if (View_Max < 12) {View_Max++;}\r
+ }\r
+\r
+ if (code == Ky_Minus)\r
+ {\r
+ if (View_Max > 1) {View_Max--;}\r
+ if (View_Cnt >= View_Max) {View_Cnt = 0;}\r
+ }\r
+\r
+ if (code == Ky_Up)\r
+ {\r
+ if (Visible_Objects < MAX_SPRITES-1) {Visible_Objects++;}\r
+ }\r
+\r
+ if (code == Ky_Down)\r
+ {\r
+ if (Visible_Objects > 0) {Visible_Objects--;}\r
+ }\r
+\r
+ }\r
+\r
+}\r
--- /dev/null
+{ ModeX Turbo Pascal Demo Program }\r
+{ Converted to Turbo Pascal by Scott Wyatt }\r
+{ Original program written in QuickBasic by Matt Prichard }\r
+{ Released to the Public Domain }\r
+{ }\r
+{ Thanks to Matt Prichard for his *EXCELLENT* ModeX Library }\r
+{ Additional Comments by Matt Pritchard }\r
+\r
+Uses Crt;\r
+\r
+{$L modex2.obj} { This file is the external ModeX Library .OBJ }\r
+{$F+}\r
+\r
+ { Mode Setting Routines }\r
+\r
+Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer; external;\r
+Function SET_MODEX (Mode:integer) : Integer; external;\r
+\r
+ { Graphics Primitives }\r
+\r
+Procedure CLEAR_VGA_SCREEN (Color:integer); external;\r
+Procedure SET_POINT (Xpos,Ypos,Color : integer); external;\r
+Function READ_POINT (Xpos,Ypos:integer) : integer; external;\r
+Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;\r
+Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external;\r
+\r
+ { VGA DAC Routines }\r
+\r
+Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;\r
+Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external;\r
+\r
+ { Page and Window Control Routines }\r
+\r
+Procedure SET_ACTIVE_PAGE (PageNo:integer); external;\r
+Function GET_ACTIVE_PAGE : integer; external;\r
+Procedure SET_DISPLAY_PAGE (PageNo:integer); external;\r
+Function GET_DISPLAY_PAGE : integer; external;\r
+Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer); external;\r
+Function GET_X_OFFSET : integer; external;\r
+Function GET_Y_OFFSET : integer; external;\r
+Procedure SYNC_DISPLAY; external;\r
+\r
+ { Text Display Routines }\r
+\r
+Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer); external;\r
+Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer); external;\r
+Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer); external;\r
+Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer); external;\r
+Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer); external;\r
+\r
+ { Sprite and VGA memory -> Vga memory Copy Routines }\r
+\r
+Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;\r
+Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external;\r
+Procedure COPY_PAGE (SourcePage,DestPage:integer); external;\r
+Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer); external;\r
+\r
+{$F-}\r
+\r
+\r
+TYPE Sprite = Record\r
+ Xpos : INTEGER;\r
+ Ypos : INTEGER;\r
+ XDir : INTEGER;\r
+ YDir : INTEGER;\r
+ Shape : INTEGER;\r
+ LastX : INTEGER;\r
+ LastY : INTEGER;\r
+ END;\r
+\r
+\r
+CONST MaxShapes = 32;\r
+ Circle_16 : Array[1..16,1..16] of byte =\r
+ (( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0),\r
+ ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0),\r
+ ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0),\r
+ ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0),\r
+ ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0),\r
+ ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0),\r
+ ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20),\r
+ ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20),\r
+ ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20),\r
+ ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20),\r
+ ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0),\r
+ ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0),\r
+ ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0),\r
+ ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0),\r
+ ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0),\r
+ ( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0));\r
+ Square_16 : Array[1..16,1..16] of byte =\r
+ (( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21),\r
+ ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21));\r
+ Diamond : Array[1..8,1..8] of byte =\r
+ (( 0, 0, 0, 22, 22, 0, 0, 0),\r
+ ( 0, 0, 22, 22, 22, 22, 0, 0),\r
+ ( 0, 22, 22, 0, 0, 22, 22, 0),\r
+ ( 22, 22, 0, 0, 0, 0, 22, 22),\r
+ ( 22, 22, 0, 0, 0, 0, 22, 22),\r
+ ( 0, 22, 22, 0, 0, 22, 22, 0),\r
+ ( 0, 0, 22, 22, 22, 22, 0, 0),\r
+ ( 0, 0, 0, 22, 22, 0, 0, 0));\r
+ Rectangle : Array[1..8,1..3] of byte =\r
+ (( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23),\r
+ ( 23, 23, 23));\r
+\r
+ { Global Variables ? }\r
+\r
+Var\r
+ XCenter,X1,Y1,X2,Y2,Z,Colr,XChars,YChars,X,Y,N,Gap : Integer;\r
+ s : string;\r
+ s1 : Array[1..35] of Char;\r
+ ch : Char;\r
+ obj : Array[1..64] of Sprite;\r
+ ScreenX,ScreenY : Integer;\r
+ c, dc, SpriteX, SpriteY, CurrentPage, LastPage : Integer;\r
+ SetColor, SDir, PrevColor, PDir : Byte;\r
+ XView, YView : Integer;\r
+ XView_Change, YView_Change : Integer;\r
+ Right : Boolean;\r
+ Number_Of_Shapes : Byte;\r
+\r
+\r
+ { Error Handler - Returns to Text Mode & Displays Error }\r
+\r
+Procedure ERROR_OUT(s : string);\r
+ Begin\r
+ asm\r
+ mov ah,0\r
+ mov al,3\r
+ int 10h\r
+ end;\r
+ WriteLn(s);\r
+ Halt(0);\r
+END;\r
+\r
+ { Routine to Print a PASCAL string using Print_Str }\r
+\r
+Procedure Print_Text(s : string; X,Y,BColor,FColor : integer);\r
+Var\r
+ s1 : Array[1..135] of Char;\r
+ i : byte;\r
+Begin\r
+ For i := 1 to Length(s) DO\r
+ s1[i] := s[i];\r
+ Print_Str(s1,Length(s),X,Y,BColor,FColor);\r
+End;\r
+\r
+ { Routine to Transparently Print a PASCAL string using TPrint_Str }\r
+\r
+Procedure TPrint_Text(s : string; X,Y,Color : integer);\r
+Var\r
+ s1 : Array[1..135] of Char;\r
+ i : byte;\r
+Begin\r
+ For i := 1 to Length(s) DO\r
+ s1[i] := s[i];\r
+ TPrint_Str(s1,Length(s),X,Y,Color);\r
+End;\r
+\r
+ { Routines to show test patterns for a given mode }\r
+\r
+Procedure Demo_Res(Mode, Xmax, Ymax : integer);\r
+Begin\r
+\r
+ Str(mode,s);\r
+ If Set_ModeX(Mode) = 0 Then\r
+ Error_Out('Unable to SET_MODEX '+s);\r
+ Clear_VGA_Screen(0);\r
+\r
+ XCenter := Xmax div 2;\r
+ X1 := 10;\r
+ Y1 := 10;\r
+ X2 := Xmax - 1;\r
+ Y2 := Ymax - 1;\r
+\r
+ FOR Z := 0 TO 3 DO\r
+ Begin\r
+ Colr := 31 - Z * 2;\r
+ Draw_Line(X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr);\r
+ Draw_Line(X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr);\r
+ Draw_Line(X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr);\r
+ Draw_Line(X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr);\r
+ End;\r
+\r
+ XChars := Xmax div 10;\r
+ YChars := Ymax div 10;\r
+\r
+ FOR X := 0 TO XChars - 1 DO\r
+ Begin\r
+ TGPRINTC(48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X div 8) MOD 7));\r
+ DRAW_LINE(X * 10 + 9, 0, X * 10 + 9, 3, 15);\r
+ End;\r
+ FOR Y := 0 TO YChars - 1 DO\r
+ Begin\r
+ TGPRINTC(48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y div 10) MOD 7));\r
+ DRAW_LINE(0, Y * 10 + 9, 3, Y * 10 + 9, 15);\r
+ End;\r
+\r
+ { Test Line Drawing }\r
+\r
+ FOR X := 0 TO 63 DO\r
+ Begin\r
+ N := 15 + ((X * 3) div 4);\r
+ SET_DAC_REGISTER(64 + X, N, N, N);\r
+ SET_DAC_REGISTER(128 + X, 0, N, N);\r
+ DRAW_LINE(103 - X, 60, 40 + X, 123, 64 + X);\r
+ DRAW_LINE(40, 60 + X, 103, 123 - X, 128 + X);\r
+ End;\r
+ s := 'Line Test';\r
+ PRINT_Text(s,37,130,1,0);\r
+\r
+ { Test Block Fills }\r
+\r
+ Y := 60;\r
+ Gap := 0;\r
+ FOR X := 0 TO 9 DO\r
+ Begin\r
+ FILL_BLOCK(120, Y, 120 + X, Y + Gap, 64 + X);\r
+ FILL_BLOCK(140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X);\r
+ FILL_BLOCK(170 - (15 - X), Y, 170, Y + Gap, 128 + X);\r
+ Y := Y + Gap + 2;\r
+ Gap := Gap + 1;\r
+ End;\r
+ s := 'Fill Test';\r
+ Print_Text(s,110, 46, 2,0);\r
+\r
+ { Test Pixel Write and Read }\r
+\r
+ FOR X := 190 TO 250 DO\r
+ FOR Y := 60 TO 122 DO\r
+ SET_POINT( X, Y, X + Y + X + Y);\r
+\r
+ s := 'Pixel Test';\r
+ Print_Text(s,182, 130, 3,0);\r
+\r
+ FOR X := 190 TO 250 DO\r
+ FOR Y := 60 TO 122 DO\r
+ IF READ_POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN\r
+ WriteLn('READ_PIXEL Failure');\r
+\r
+ { Display rest of screen }\r
+\r
+ s := ' This is a MODE X demo ';\r
+ Print_Text(s,XCenter - (Length(s) * 4), 20, 3, 1);\r
+ s := 'Screen Resolution is by ';\r
+ X := XCenter - (Length(s) * 4);\r
+ Print_Text(s,X,30,4,0);\r
+ Str(XMax,s);\r
+ Print_Text(s, X + 8 * 21, 30, 8, 0);\r
+ Str(YMax,s);\r
+ Print_Text(s, X + 8 * 28, 30, 15, 0);\r
+\r
+ FOR X := 0 TO 15 DO\r
+ Begin\r
+ SET_DAC_REGISTER( 230 + X, 63 - X * 4, 0, 15 + X * 3);\r
+ DRAW_LINE(30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X);\r
+ End;\r
+ s := 'Press <ANY KEY> to Continue';\r
+ For x := 1 to length(s) DO\r
+ s1[x] := s[x];\r
+ TPrint_Str(s1, length(s), XCenter - (26 * 4), Ymax - 18, 5);\r
+\r
+ Ch := ReadKey;\r
+ IF Ch = #27 Then\r
+ Error_Out('Abort');\r
+\r
+End;\r
+\r
+\r
+ { Initialize Sprites for Sprite Demo }\r
+\r
+Procedure Init_Sprites;\r
+Var i : byte;\r
+Begin\r
+ For i := 1 to 64 DO\r
+ Begin\r
+ Obj[i].XPos := Random(300)+10;\r
+ Obj[i].YPos := Random(200)+20;\r
+ Obj[i].XDir := Random(10)-5;\r
+ Obj[i].YDir := Random(10)-5;\r
+ If (Obj[i].XDir = 0) AND (Obj[i].YDir = 0) Then\r
+ Begin\r
+ Obj[i].XDir := Random(5) + 1;\r
+ Obj[i].YDir := Random(5) + 1;\r
+ End;\r
+ Obj[i].Shape := Random(4)+1;\r
+ Obj[i].LastX := obj[i].XPos;\r
+ Obj[i].LastY := obj[i].YPos;\r
+ End;\r
+End;\r
+\r
+Procedure Set_Sprites(number : byte);\r
+Var i : Byte;\r
+Begin\r
+ For i := 1 to number DO\r
+ Begin\r
+ obj[i].LastX := obj[i].XPos;\r
+ obj[i].LastY := obj[i].YPos;\r
+ obj[i].XPos := obj[i].XPos + obj[i].XDir;\r
+ obj[i].YPos := obj[i].YPos + obj[i].YDir;\r
+ If (obj[i].XPos > 335) OR (obj[i].XPos < 5 ) Then\r
+ obj[i].XDir := -(obj[i].XDir);\r
+ If (obj[i].YPos > 220) OR (obj[i].YPos < 5) Then\r
+ obj[i].YDir := -(obj[i].YDir);\r
+ End;\r
+ For i := 1 to number DO\r
+ Case obj[i].Shape of\r
+ 1 : TDraw_Bitmap(Circle_16,obj[i].XPos,obj[i].YPos,16,16);\r
+ 2 : TDraw_Bitmap(Square_16,obj[i].XPos,obj[i].YPos,16,16);\r
+ 3 : TDraw_Bitmap(Diamond,obj[i].XPos,obj[i].YPos,8,8);\r
+ 4 : TDraw_Bitmap(Rectangle,obj[i].XPos,obj[i].YPos,3,8);\r
+ End;\r
+End;\r
+\r
+Procedure Remove_Sprites(p,number : byte);\r
+Var i : byte;\r
+Begin\r
+ For i := 1 to number DO\r
+ Copy_Bitmap(2,obj[i].LastX,obj[i].LastY,obj[i].LastX+16,obj[i].LastY+16,p,Obj[i].LastX,Obj[i].LastY);\r
+End;\r
+\r
+Procedure Page_Demo;\r
+Begin\r
+ Number_Of_Shapes := 64;\r
+ XView_Change := 1;\r
+ YView_Change := 1;\r
+ XView := 1;\r
+ YView := 1;\r
+ Right := TRUE;\r
+ ScreenX := 360;\r
+ ScreenY := 240;\r
+ PrevColor := 0;\r
+ SetColor := 3;\r
+ SDir := 1;\r
+ PDir := 1;\r
+ Str(0,s);\r
+\r
+ IF SET_VGA_MODEX(0, ScreenX, ScreenY, 3) = 0 THEN\r
+ ERROR_OUT('Unable to SET_VGA_MODEX' + S);\r
+\r
+ SET_ACTIVE_PAGE(0);\r
+ CLEAR_VGA_SCREEN(0);\r
+ PRINT_TEXT('This is a Test of the Following Functions:', 10, 9, 15, 0);\r
+ DRAW_LINE( 10, 18, 350, 18, 4);\r
+ Print_Text('SET_ACTIVE_PAGE', 10, 20, 1, 0);\r
+ Print_Text('SET_DISPLAY_PAGE', 10, 30, 3,0);\r
+ Print_Text('SET_DAC_REGISTER', 10, 40, 3, 0);\r
+ Print_Text('CLEAR_VGA_SCREEN', 10, 50, 13, 0);\r
+ Print_Text('TDRAW_BITMAP', 10, 60, 14, 0);\r
+ Print_Text('COPY_PAGE', 10, 70, 3, 0);\r
+ Print_Text('COPY_BITMAP', 10, 80, 13, 0);\r
+ Print_Text('GPRINTC', 10, 90, 1, 0);\r
+ Print_Text('TGPRINTC', 10, 100, 3, 0);\r
+ Print_Text('SYNC_DISPLAY', 10, 110, 3, 0);\r
+ Print_Text('SET_WINDOW', 10, 120, 14, 0);\r
+ Print_Text('VIRTUAL SCREEN SIZES', 190, 20, 1, 0);\r
+ Print_Text(' SMOOTH SCROLLING', 190, 30, 3, 0);\r
+ Print_Text(' SPRITE ANIMATION', 190, 40, 13, 0);\r
+ Print_Text(' PAGE FLIPPING', 190, 50, 3, 0);\r
+ Print_Text(' COLOR CYCLING', 190, 60, 14, 0);\r
+\r
+ FOR X := 0 TO 60 DO\r
+ Begin\r
+ SET_DAC_REGISTER( 50 + X, 3 + X, 0, 60 - X);\r
+ SET_DAC_REGISTER( 150 + X, 3 + X, 0, 60 - X);\r
+ End;\r
+\r
+ c := 0;\r
+ DC := 1;\r
+ FOR X := 0 TO ScreenX div 2 DO\r
+ Begin\r
+ DRAW_LINE( ScreenX div 2 - 1, ScreenY div 4, X, ScreenY - 1, c + 50);\r
+ DRAW_LINE( ScreenX div 2, ScreenY div 4, ScreenX - X - 1, ScreenY - 1, c + 50);\r
+ c := c + DC;\r
+ IF (c = 0) OR (c = 60) THEN DC := -DC;\r
+ End;\r
+\r
+ TPrint_Text('Press <ESC> to Continue', 82, 190, 15);\r
+ TPrint_Text('<+> = Fewer Shapes <-> = More Shapes', 32, 204, 12);\r
+ COPY_PAGE( 0, 1);\r
+ COPY_PAGE( 0, 2);\r
+\r
+ Ch := #0;\r
+ CurrentPage := 1;\r
+ LastPage := 0;\r
+ Set_Sprites(Number_Of_Shapes);\r
+ For c := 1 to 4 DO\r
+ Set_Dac_Register(19+c,63-(c*10),0,0);\r
+\r
+ While Ch <> #27 DO\r
+ Begin\r
+ Set_Active_Page(currentpage);\r
+ Set_Sprites(Number_Of_Shapes);\r
+ If Right Then\r
+ Begin\r
+ XView := XView + XView_Change;\r
+ If (XView > 38) OR (XView < 2) Then\r
+ Begin\r
+ XView_Change := -(XView_Change);\r
+ Right := FALSE;\r
+ End;\r
+ End\r
+ Else\r
+ Begin\r
+ YView := YView + YView_Change;\r
+ If (YView > 38) OR (YView < 2) Then\r
+ Begin\r
+ YView_Change := -(YView_Change);\r
+ Right := TRUE;\r
+ End;\r
+ End;\r
+\r
+ Set_Window(currentpage,XView,YView);\r
+ Set_Display_Page(currentpage);\r
+ Set_Dac_Register(50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);\r
+ Set_Dac_Register(50 + SetColor, SetColor, 10, 63 - SetColor);\r
+ Set_Dac_Register(150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor);\r
+ Set_Dac_Register(150 + SetColor, 63, 63, SetColor);\r
+ SetColor := SetColor + SDir;\r
+ IF (SetColor = 60) OR (SetColor = 0) THEN SDir := -SDir;\r
+ PrevColor := PrevColor + PDir;\r
+ IF (PrevColor = 60) OR (PrevColor = 0) THEN PDir := -PDir;\r
+ Remove_Sprites(lastpage,Number_Of_Shapes);\r
+\r
+ If Keypressed Then\r
+ Begin\r
+ Ch := ReadKey;\r
+ Case Ch of\r
+ '-' : If Number_Of_Shapes > 1 Then\r
+ Begin\r
+ c := Number_Of_Shapes;\r
+ Copy_Bitmap(2,obj[c].XPos,obj[c].YPos,obj[c].XPos+16,obj[c].YPos+16,\r
+ currentpage,obj[c].XPos,obj[c].YPos);\r
+ Dec(Number_Of_Shapes);\r
+ End;\r
+ '+' : If Number_Of_Shapes < 64 Then Inc(Number_Of_Shapes);\r
+ End;\r
+ End;\r
+ lastpage := (lastpage+1) MOD 2;\r
+ currentpage := (currentpage+1) MOD 2;\r
+ End;\r
+END;\r
+\r
+ { MAIN ROUTINE - Run Through Demos and Exit }\r
+\r
+Begin\r
+\r
+ Randomize;\r
+ Init_Sprites;\r
+\r
+ Demo_Res(0, 320, 200);\r
+ Demo_Res(1, 320, 400);\r
+ Demo_Res(2, 360, 200);\r
+ Demo_Res(3, 360, 400);\r
+ Demo_Res(4, 320, 240);\r
+ Demo_Res(5, 320, 480);\r
+ Demo_Res(6, 360, 240);\r
+ Demo_Res(7, 360, 480);\r
+ Page_Demo;\r
+\r
+ asm\r
+ mov ah,0\r
+ mov al,3\r
+ int 10h\r
+ end;\r
+ WriteLn('THIS MODE X DEMO IS FINISHED');\r
+\r
+END.
\ No newline at end of file
--- /dev/null
+ECHO ... Building MODEX.QLB for QUICKBASIC 4.5\r
+LIB MODEX -+MODEX,,\r
+LIB MODEX -+UTILS,,\r
+DEL MODEX.BAK\r
+LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\QB45\BQLB45.LIB;\1a\r
--- /dev/null
+ \r
+ ' ===== SCREEN RESOLUTIONS =====\r
+ \r
+CONST Mode320x200 = 0, Mode320x400 = 1\r
+CONST Mode360x200 = 2, Mode360x400 = 3\r
+CONST Mode320x240 = 4, Mode320x480 = 5\r
+CONST Mode360x240 = 6, Mode360x480 = 7\r
+ \r
+ ' ===== MODE X SETUP ROUTINES =====\r
+ \r
+DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%)\r
+DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%)\r
+ \r
+ ' ===== BASIC GRAPHICS PRIMITIVES =====\r
+ \r
+DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%)\r
+DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%)\r
+DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%)\r
+DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+ \r
+ ' ===== DAC COLOR REGISTER ROUTINES =====\r
+ \r
+DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%)\r
+DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%)\r
+DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%)\r
+DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%)\r
+ \r
+ \r
+ ' ===== PAGE FLIPPING AND SCROLLING ROUTINES =====\r
+ \r
+DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE"\r
+DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE"\r
+DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%)\r
+DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" ()\r
+DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" ()\r
+DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY"\r
+ \r
+ ' ===== TEXT DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%)\r
+ \r
+ ' ===== BITMAP (SPRITE) DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+ \r
+ ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====\r
+ \r
+DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%)\r
+DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%)\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
--- /dev/null
+'File: TEST6A.BAS\r
+'Descp.: A Mode "X" demonstration for Quickbasic 4.5\r
+'Author: Matt Pritchard\r
+'Date: 14 April, 1993\r
+'\r
+DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%)\r
+DECLARE SUB ERROR.OUT (Message$)\r
+DECLARE FUNCTION GET.KEY% ()\r
+DECLARE SUB LOAD.SHAPES ()\r
+DECLARE SUB PAGE.DEMO ()\r
+DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%)\r
+DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%)\r
+DEFINT A-Z\r
+\r
+\r
+TYPE ShapeType\r
+ ImgData AS STRING * 512\r
+ xWidth AS INTEGER\r
+ yWidth AS INTEGER\r
+END TYPE\r
+\r
+TYPE Sprite\r
+ Xpos AS INTEGER\r
+ Ypos AS INTEGER\r
+ XDir AS INTEGER\r
+ YDir AS INTEGER\r
+ Shape AS INTEGER\r
+END TYPE\r
+\r
+\r
+CONST MaxShapes = 32\r
+\r
+ REM $INCLUDE: 'UTILS.BI'\r
+ REM $INCLUDE: 'MODEX.BI'\r
+\r
+DIM SHARED Img(32) AS ShapeType\r
+COMMON SHARED Img() AS ShapeType\r
+\r
+\r
+ CALL INIT.RANDOM\r
+\r
+ CALL LOAD.SHAPES\r
+\r
+ CALL DEMO.RES(Mode320x200, 320, 200)\r
+ CALL DEMO.RES(Mode320x400, 320, 400)\r
+\r
+ CALL DEMO.RES(Mode360x200, 360, 200)\r
+ CALL DEMO.RES(Mode360x400, 360, 400)\r
+\r
+ CALL DEMO.RES(Mode320x240, 320, 240)\r
+ CALL DEMO.RES(Mode320x480, 320, 480)\r
+\r
+ CALL DEMO.RES(Mode360x240, 360, 240)\r
+ CALL DEMO.RES(Mode360x480, 360, 480)\r
+\r
+ CALL PAGE.DEMO\r
+\r
+ SET.VIDEO.MODE 3\r
+ DOS.PRINT "THIS MODE X DEMO IS FINISHED"\r
+ END\r
+\r
+SUB DEMO.RES (Mode, Xmax, Ymax)\r
+\r
+ IF SET.MODEX%(Mode) = 0 THEN\r
+ ERROR.OUT "Unable to SET_MODEX" + STR$(Mode)\r
+ END IF\r
+\r
+ XCenter = Xmax \ 2\r
+ \r
+ X1 = 10\r
+ Y1 = 10\r
+ X2 = Xmax - 1\r
+ Y2 = Ymax - 1\r
+\r
+ FOR Z = 0 TO 3\r
+ Colr = 31 - Z * 2\r
+ DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr\r
+ DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr\r
+ DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr\r
+ DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr\r
+ NEXT Z\r
+\r
+ XChars = Xmax \ 10\r
+ YChars = Ymax \ 10\r
+\r
+ FOR X = 0 TO XChars - 1\r
+ TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7)\r
+ DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15\r
+ NEXT X\r
+\r
+ FOR Y = 0 TO YChars - 1\r
+ TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7)\r
+ DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15\r
+ NEXT Y\r
+\r
+ ' Draw Lines\r
+\r
+ FOR X = 0 TO 63\r
+ N = 15 + X * .75\r
+ SET.DAC.REGISTER 64 + X, N, N, N\r
+ SET.DAC.REGISTER 128 + X, 0, N, N\r
+\r
+ DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X\r
+ DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X\r
+\r
+ NEXT X\r
+ TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE\r
+\r
+ Y = 60: Gap = 0\r
+ FOR X = 0 TO 9\r
+ FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X\r
+ FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X\r
+ FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X\r
+ Y = Y + Gap + 2\r
+ Gap = Gap + 1\r
+ NEXT X\r
+ TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN\r
+\r
+\r
+ FOR X = 190 TO 250 STEP 2\r
+ FOR Y = 60 TO 122 STEP 2\r
+ SET.POINT X, Y, X + Y + X + Y\r
+ NEXT Y\r
+ NEXT X\r
+\r
+ TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED\r
+\r
+ FOR X = 190 TO 250 STEP 2\r
+ FOR Y = 60 TO 122 STEP 2\r
+ IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN\r
+ ERROR.OUT "READ.PIXEL Failure"\r
+ END IF\r
+ NEXT Y\r
+ NEXT X\r
+\r
+\r
+\r
+ Msg$ = " This is a MODE X demo "\r
+ PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE\r
+ Msg$ = "Screen Resolution is by "\r
+ Xp = XCenter - (LEN(Msg$) * 4)\r
+ PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK\r
+\r
+ PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK\r
+ PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK\r
+\r
+ FOR X = 0 TO 15\r
+ SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3\r
+ DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X\r
+ NEXT X\r
+ TPRINT.TEXT "Press <ANY KEY> to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW\r
+\r
+ X = GET.KEY%\r
+ IF X = KyESC THEN ERROR.OUT "ABORT"\r
+\r
+END SUB\r
+\r
+SUB ERROR.OUT (Message$)\r
+\r
+ SET.VIDEO.MODE 3\r
+ DOS.PRINT Message$\r
+ END\r
+\r
+END SUB\r
+\r
+FUNCTION GET.KEY%\r
+\r
+ DO\r
+ X = SCAN.KEYBOARD\r
+ LOOP UNTIL X\r
+\r
+ GET.KEY% = X\r
+\r
+END FUNCTION\r
+\r
+SUB LOAD.SHAPES\r
+\r
+DIM Grid(1 TO 32, 1 TO 32)\r
+\r
+ FOR Shape = 0 TO MaxShapes - 1\r
+\r
+ FOR Y = 1 TO 32\r
+ FOR X = 1 TO 32\r
+ Grid(X, Y) = 0\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ Style = RANDOM.INT(6)\r
+ Colour = 1 + RANDOM.INT(15)\r
+ \r
+ SELECT CASE Style\r
+\r
+ CASE 0: ' Solid Box\r
+\r
+ DO\r
+ xWidth = 3 + RANDOM.INT(30)\r
+ yWidth = 3 + RANDOM.INT(30)\r
+ LOOP UNTIL ((xWidth * yWidth) <= 512)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ Grid(X, Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 1: ' Hollow Box\r
+\r
+ DO\r
+ xWidth = 5 + RANDOM.INT(28)\r
+ yWidth = 5 + RANDOM.INT(28)\r
+ LOOP UNTIL ((xWidth * yWidth) <= 512)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ Grid(X, Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1)\r
+ HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1)\r
+\r
+ FOR Y = HollowY + 1 TO yWidth - HollowY\r
+ FOR X = HollowX + 1 TO xWidth - HollowX\r
+ Grid(X, Y) = nil\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 2: ' Solid Diamond\r
+\r
+ xWidth = 3 + 2 * RANDOM.INT(10)\r
+ yWidth = xWidth\r
+ Centre = xWidth \ 2\r
+\r
+ FOR Y = 0 TO Centre\r
+ FOR X = 0 TO Y\r
+ Grid(Centre - X + 1, Y + 1) = Colour\r
+ Grid(Centre + X + 1, Y + 1) = Colour\r
+ Grid(Centre - X + 1, yWidth - Y) = Colour\r
+ Grid(Centre + X + 1, yWidth - Y) = Colour\r
+ NEXT X\r
+ NEXT Y\r
+\r
+\r
+ CASE 3: ' Hollow Diamond\r
+\r
+\r
+ xWidth = 3 + 2 * RANDOM.INT(10)\r
+ yWidth = xWidth\r
+ Centre = xWidth \ 2\r
+ sWidth = RANDOM.INT(Centre)\r
+\r
+ FOR Y = 0 TO Centre\r
+ FOR X = 0 TO Y\r
+ IF X + (Centre - Y) >= sWidth THEN\r
+ Grid(Centre - X + 1, Y + 1) = Colour\r
+ Grid(Centre + X + 1, Y + 1) = Colour\r
+ Grid(Centre - X + 1, yWidth - Y) = Colour\r
+ Grid(Centre + X + 1, yWidth - Y) = Colour\r
+ END IF\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 4: ' Ball\r
+\r
+ xWidth = 7 + 2 * RANDOM.INT(8)\r
+ yWidth = xWidth\r
+ Centre = 1 + xWidth \ 2\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y)))\r
+ IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ CASE 5: ' Ball\r
+\r
+\r
+ xWidth = 7 + 2 * RANDOM.INT(8)\r
+ yWidth = xWidth\r
+ Centre = 1 + xWidth \ 2\r
+ sWidth = RANDOM.INT(xWidth)\r
+\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y)))\r
+ IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ END SELECT\r
+\r
+ Img(Shape).xWidth = xWidth\r
+ Img(Shape).yWidth = yWidth\r
+\r
+ A$ = STRING$(xWidth * yWidth, nil)\r
+\r
+ c = 1\r
+ FOR Y = 1 TO yWidth\r
+ FOR X = 1 TO xWidth\r
+ MID$(A$, c, 1) = CHR$(Grid(X, Y))\r
+ c = c + 1\r
+ NEXT X\r
+ NEXT Y\r
+\r
+ Img(Shape).ImgData = A$\r
+ \r
+\r
+ NEXT Shape\r
+\r
+END SUB\r
+\r
+SUB PAGE.DEMO\r
+\r
+CONST MaxSprites = 64\r
+\r
+DIM Obj(MaxSprites) AS Sprite\r
+DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1)\r
+DIM LastObjects(1)\r
+\r
+ ScreenX = 360: ScreenY = 240\r
+\r
+ IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN\r
+ ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode)\r
+ END IF\r
+\r
+ SET.ACTIVE.PAGE 0\r
+\r
+ CLEAR.VGA.SCREEN c.BLACK\r
+ \r
+ PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK\r
+\r
+ DRAW.LINE 10, 18, 350, 18, c.YELLOW\r
+ PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK\r
+ PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK\r
+ PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK\r
+ PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK\r
+\r
+ PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK\r
+ PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK\r
+ PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK\r
+\r
+ PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK\r
+ PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK\r
+ PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK\r
+\r
+ PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK\r
+ PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK\r
+ PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK\r
+ PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK\r
+ PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK\r
+\r
+\r
+ FOR X = 0 TO 60\r
+ SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X\r
+ SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X\r
+ NEXT X\r
+\r
+ c = 0: DC = 1\r
+ FOR X = 0 TO ScreenX \ 2\r
+ DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50\r
+ DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50\r
+ c = c + DC\r
+ IF c = 0 OR c = 60 THEN DC = -DC\r
+ NEXT X\r
+ \r
+ TPRINT.TEXT "Press <ANY KEY> to Continue", 72, 190, c.bWHITE\r
+ TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN\r
+ TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN\r
+\r
+ TGPRINTC 43, 80, 204, c.YELLOW\r
+ TGPRINTC 45, 200, 204, c.YELLOW\r
+\r
+ TGPRINTC 25, 40, 218, c.YELLOW\r
+ TGPRINTC 24, 200, 218, c.YELLOW\r
+\r
+ COPY.PAGE 0, 1\r
+ COPY.PAGE 0, 2\r
+\r
+ FOR X = 1 TO MaxSprites\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+\r
+ Obj(X).Shape = X MOD MaxShapes\r
+\r
+ SpriteX = Img(Obj(X).Shape).xWidth\r
+ SpriteY = Img(Obj(X).Shape).yWidth\r
+\r
+ Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2)\r
+ Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2)\r
+\r
+ LastX(X, 0) = Obj(X).Xpos\r
+ LastX(X, 1) = Obj(X).Xpos\r
+ LastY(X, 0) = Obj(X).Ypos\r
+ LastY(X, 1) = Obj(X).Ypos\r
+ NEXT X\r
+\r
+ CurrentPage = 0\r
+\r
+ 'View Shift...\r
+\r
+ ViewX = 0\r
+ ViewY = 0\r
+ ViewMax = 3\r
+ ViewCnt = 0\r
+ ViewXD = 1\r
+ ViewYD = 1\r
+\r
+ SetColor = 3: SDir = 1\r
+ PrevColor = 0: PDir = 1\r
+\r
+ VisObjects = MaxSprites \ 2\r
+ LastObjects(0) = 0\r
+ LastObjects(1) = 0\r
+\r
+DRAW.LOOP:\r
+\r
+\r
+ SET.ACTIVE.PAGE CurrentPage\r
+\r
+ ' Erase Old Images\r
+\r
+ FOR X = 1 TO LastObjects(CurrentPage)\r
+ \r
+ X1 = LastX(X, CurrentPage) AND &HFFFC\r
+ Y1 = LastY(X, CurrentPage)\r
+ X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3\r
+ Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1\r
+\r
+ COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1\r
+ \r
+ NEXT X\r
+\r
+ ' Draw new images\r
+\r
+ FOR X = 1 TO VisObjects\r
+\r
+ SpriteX = Img(Obj(X).Shape).xWidth\r
+ SpriteY = Img(Obj(X).Shape).yWidth\r
+\r
+ ' Move Sprite\r
+\r
+REDOX:\r
+ NewX = Obj(X).Xpos + Obj(X).XDir\r
+ IF NewX < 0 OR NewX + SpriteX > ScreenX THEN\r
+ Obj(X).XDir = -Obj(X).XDir\r
+ IF RANDOM.INT(20) = 1 THEN\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+ GOTO REDOX\r
+ END IF\r
+ END IF\r
+ Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir\r
+\r
+REDOY:\r
+ NewY = Obj(X).Ypos + Obj(X).YDir\r
+ IF NewY < 0 OR NewY + SpriteY > ScreenY THEN\r
+ Obj(X).YDir = -Obj(X).YDir\r
+ IF RANDOM.INT(20) = 1 THEN\r
+ DO\r
+ Obj(X).XDir = RANDOM.INT(7) - 3\r
+ Obj(X).YDir = RANDOM.INT(7) - 3\r
+ LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0)\r
+ GOTO REDOY\r
+ END IF\r
+ END IF\r
+ Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir\r
+\r
+ 'Draw Sprite\r
+\r
+ TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY\r
+\r
+ LastX(X, CurrentPage) = Obj(X).Xpos\r
+ LastY(X, CurrentPage) = Obj(X).Ypos\r
+\r
+ NEXT X\r
+\r
+ LastObjects(CurrentPage) = VisObjects\r
+\r
+ ' Pan Screen Back & Forth\r
+\r
+ ViewCnt = ViewCnt + 1\r
+ IF ViewCnt >= ViewMax THEN\r
+ ViewX = ViewX + ViewXD\r
+ IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD\r
+ IF ViewXD < 0 THEN\r
+ ViewY = ViewY + ViewYD\r
+ IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD\r
+ END IF\r
+ \r
+ SET.WINDOW CurrentPage, ViewX, ViewY\r
+\r
+ ViewCnt = 0\r
+ ELSE\r
+ SET.DISPLAY.PAGE CurrentPage\r
+ END IF\r
+\r
+ ' Cycle Colors\r
+\r
+ SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor\r
+ SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor\r
+\r
+ SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor\r
+ SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor\r
+\r
+ SetColor = SetColor + SDir\r
+ IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir\r
+\r
+ PrevColor = PrevColor + PDir\r
+ IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir\r
+\r
+ CurrentPage = 1 - CurrentPage\r
+\r
+ Code = SCAN.KEYBOARD\r
+\r
+ IF Code = False THEN GOTO DRAW.LOOP\r
+\r
+ IF Code = KyPlus THEN\r
+ IF ViewMax < 12 THEN ViewMax = ViewMax + 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+ IF Code = KyMinus THEN\r
+ IF ViewMax > 1 THEN ViewMax = ViewMax - 1\r
+ IF ViewCnt >= ViewMax THEN ViewCnt = 0\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+ IF Code = KyUp THEN\r
+ IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+ \r
+ IF Code = KyDown THEN\r
+ IF VisObjects > 1 THEN VisObjects = VisObjects - 1\r
+ GOTO DRAW.LOOP\r
+ END IF\r
+\r
+\r
+END SUB\r
+\r
+SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB)\r
+\r
+ IF LEN(Text$) = 0 THEN EXIT SUB\r
+ PRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB\r
+\r
+\r
+END SUB\r
+\r
+SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF)\r
+\r
+ IF LEN(Text$) = 0 THEN EXIT SUB\r
+\r
+ TPRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF\r
+\r
+END SUB\r
+\r
--- /dev/null
+MASM utils, utils, utils, nul;
\ No newline at end of file
--- /dev/null
+;=======================================================\r
+;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 ===\r
+;=======================================================\r
+\r
+ PAGE 255, 132\r
+\r
+ .MODEL Medium\r
+ .286\r
+\r
+ ; ==== MACROS ====\r
+\r
+ ; macros to PUSH and POP multiple registers\r
+\r
+PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ push R1 ; Save R1\r
+ PUSHx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ pop R1 ; Restore R1\r
+ POPx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+\r
+ ; Macro to Clear a Register to 0\r
+\r
+CLR MACRO Register\r
+ xor Register, Register ; Set Register = 0\r
+ENDM\r
+\r
+ ; Macros to Decrement Counter & Jump on Condition\r
+\r
+LOOPx MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jnz Destination ; Jump if not 0\r
+ENDM\r
+\r
+LOOPjz MACRO Register, Destination\r
+ dec Register ; Counter--\r
+ jz Destination ; Jump if 0\r
+ENDM\r
+\r
+\r
+ ; ==== General Constants ====\r
+\r
+ False EQU 0\r
+ True EQU -1\r
+ nil EQU 0\r
+\r
+ b EQU BYTE PTR\r
+ w EQU WORD PTR\r
+ d EQU DWORD PTR\r
+ o EQU OFFSET\r
+ f EQU FAR PTR\r
+ s EQU SHORT\r
+ ?x4 EQU <?,?,?,?>\r
+ ?x3 EQU <?,?,?>\r
+\r
+\r
+IFDEF FARSTRINGS\r
+\r
+ EXTRN stringaddress:far\r
+ EXTRN stringlength:far\r
+\r
+ENDIF\r
+\r
+\r
+ .Data\r
+\r
+ EVEN\r
+\r
+RND_Seed DW 7397, 29447, 802\r
+RND_Mult DW 179, 183, 182\r
+RND_ModV DW 32771, 32779, 32783\r
+\r
+CR_LF DB 13, 10 ; the CRLF data\r
+\r
+ .Code\r
+\r
+;=================\r
+;DOS_PRINT (Text$)\r
+;=================\r
+;\r
+; Prints Text Directly to DOS console w/ CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINT\r
+\r
+DP_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ DP_Text DW ? ; Address of Text$ Descriptor\r
+DP_Stack ENDS\r
+\r
+\r
+DOS_PRINT PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+ push SI ; Push Addr of BC7 Decriptor Ptr\r
+ call stringaddress ; Get Address + Len of string!!!\r
+ ; DX:AX = Addr CX = Len\r
+ mov DS, DX ; DS = DX = Segment of string\r
+ mov DX, AX ; DX = AX = Offset of String\r
+ELSE\r
+ mov CX, [SI] ; put its length into CX\r
+ mov DX, [SI+02] ; now DS:DX points to the String\r
+ENDIF\r
+\r
+ jcxz @No_Print ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@No_Print:\r
+ mov AX, SEG DGROUP ; Restore DGroup\r
+ mov DS, AX\r
+\r
+ mov DX, o CR_LF ; Get Addr of CR/LF pair\r
+ mov CX, 2 ; 2 Characters to Write \r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINT ENDP\r
+\r
+\r
+;==================\r
+;DOS_PRINTS (Text$)\r
+;==================\r
+; \r
+; Print Text$ Directly to DOS console \r
+; without a trailing CR/LF\r
+;\r
+\r
+ PUBLIC DOS_PRINTS\r
+\r
+DOS_PRINTS PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor\r
+\r
+IFDEF FARSTRINGS\r
+ push SI ; Push Addr of BC7 Decriptor Ptr\r
+ call stringaddress ; Get Address + Len of string!!!\r
+ ; DX:AX = Addr CX = Len\r
+ mov DS, DX ; DS = DX = Segment of string\r
+ mov DX, AX ; DX = AX = Offset of String\r
+ELSE\r
+ mov CX, [SI] ; put its length into CX\r
+ mov DX, [SI+02] ; now DS:DX points to the String\r
+ENDIF\r
+\r
+ jcxz @DPS_Exit ; Don't Print if empty\r
+\r
+ mov BX, 1 ; 1= DOS Handle for Display\r
+ mov AH, 40h ; Write Text Function\r
+ int 21h ; Call DOS to do it\r
+\r
+@DPS_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+DOS_PRINTS ENDP\r
+\r
+\r
+;======================\r
+;SET_VIDEO_MODE (Mode%) \r
+;======================\r
+;\r
+; Sets the Video Mode through the BIOS\r
+;\r
+\r
+ PUBLIC SET_VIDEO_MODE\r
+\r
+SVM_Stack STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ SVM_Mode DB ?,? ; Desired Video Mode\r
+SVM_Stack ENDS\r
+\r
+\r
+SET_VIDEO_MODE PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR AH ; Function 0\r
+ mov AL, [BP].SVM_Mode ; Get Mode #\r
+\r
+ int 10H ; Change Video Modes\r
+\r
+@SVM_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret 2 ; Exit & Clean Up Stack\r
+\r
+SET_VIDEO_MODE ENDP\r
+\r
+\r
+;==============\r
+;SCAN_KEYBOARD%\r
+;==============\r
+;\r
+; Function to scan keyboard for a pressed key\r
+;\r
+\r
+ PUBLIC SCAN_KEYBOARD\r
+\r
+SCAN_KEYBOARD PROC FAR\r
+\r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+\r
+ mov AH, 01H ; Function #1\r
+ int 16H ; Call Keyboard Driver\r
+ jz @SK_NO_KEY ; Exit if Zero flag set\r
+\r
+ mov AH, 00H ; Remove Key from Buffer\r
+ int 16H ; Get Keycode in AX\r
+\r
+ or AL, AL ; Low Byte Set (Ascii?)\r
+ jz @SK_Exit ; if not, it's a F-Key\r
+\r
+ CLR AH ; Clear ScanCode if Ascii\r
+ jmp s @SK_Exit ; Return Key in AX\r
+\r
+@SK_NO_KEY:\r
+ CLR AX ; Return Nil (no Keypress)\r
+\r
+@SK_Exit:\r
+ cld ; Reset Direction Flag \r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ ret ; Exit & Clean Up Stack\r
+\r
+SCAN_KEYBOARD ENDP\r
+\r
+\r
+;====================\r
+;RANDOM_INT (MaxInt%)\r
+;====================\r
+;\r
+; Returns a pseudo-random number in the range of (0.. MaxInt-1)\r
+;\r
+\r
+\r
+ PUBLIC RANDOM_INT\r
+\r
+RI_Stack STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ RI_MaxVal DW ? ; Maximum Value to Return + 1\r
+RI_Stack ENDS\r
+\r
+\r
+RANDOM_INT PROC FAR\r
+\r
+ push BP ; Preserve Important Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ CLR BX ; BX is the data index\r
+ CLR CX ; CX is the accumulator\r
+\r
+REPT 3\r
+ mov AX, RND_Seed[BX] ; load the initial seed\r
+ mul RND_Mult[BX] ; multiply it\r
+ div RND_ModV[BX] ; and obtain the Mod value\r
+ mov RND_Seed[BX], DX ; save that for the next time\r
+\r
+ add CX, DX ; add it into the accumulator\r
+ inc BX\r
+ inc BX ; point to the next set of values\r
+ENDM\r
+\r
+ mov AX, CX ; AX = Random #\r
+ CLR DX ; DX = 0\r
+ div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder\r
+\r
+ mov AX, DX\r
+\r
+ pop BP ; Restore BP\r
+ ret 2 ; back to BASIC with AX holding the result\r
+\r
+RANDOM_INT ENDP\r
+\r
+\r
+;===========\r
+;INIT_RANDOM\r
+;===========\r
+;\r
+; Scrambles the psuedo-random number sequence\r
+; (XOR's the seed value with the timer)\r
+;\r
+\r
+ PUBLIC INIT_RANDOM\r
+\r
+INIT_RANDOM PROC FAR\r
+\r
+ clr AX ; Segment = 0000\r
+ mov ES, AX\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+\r
+ xor RND_Seed, AX ; Scramble 1st Seed\r
+\r
+ ret ; Exit & Clean Up Stack\r
+\r
+INIT_RANDOM ENDP\r
+\r
+\r
+;====================\r
+;INT_SQR (X%, Round%)\r
+;====================\r
+;\r
+; Returns the Integer Square Root of (X)\r
+; Round allows the return value to be rounded to the \r
+; nearest integer value by passing 0x80. Passing 0\r
+; return the Integer Portion only. The rounding amound is\r
+; a number from 0 to 1 multiplied by 256, thus \r
+; 0.5 * 0x100 = 0x80!\r
+;\r
+\r
+ISQ_Stack STRUC\r
+ DW ?,? ; BP, DI\r
+ DD ? ; Caller\r
+ ISQ_Round DW ? ; Amount to Round Result * 256\r
+ ISQ_X DW ? ; "X"\r
+ISQ_Stack ENDS\r
+\r
+ PUBLIC INT_SQR\r
+\r
+INT_SQR PROC FAR\r
+\r
+ PUSHx BP, DI ; Save BP\r
+ mov BP, SP ; Set up Stack Frame\r
+\r
+ xor AX, AX ; {xor eax,eax}\r
+ xor DX, DX ; {xor edx,edx}\r
+ mov DI, [BP].ISQ_X ; {mov edi,x}\r
+\r
+ mov CX, 16 ; {mov cx, 32}\r
+\r
+@ISQ_L:\r
+\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl DI, 1 ; {shl edi,1}\r
+ rcl DX, 1 ; {rcl edx,1}\r
+ shl AX, 1 ; {shl eax,1}\r
+ mov BX, AX ; {mov ebx,eax}\r
+ shl BX, 1 ; {shl ebx,1}\r
+ inc BX ; {inc ebx}\r
+ cmp DX, BX ; {cmp edx,ebx}\r
+ jl @ISQ_S\r
+\r
+ sub DX, BX ; {sub edx,ebx}\r
+ inc AX ; {inc eax}\r
+\r
+@ISQ_S: \r
+ loop @ISQ_L\r
+\r
+ add ax, [BP].ISQ_Round ; {add eax,$00008000} \r
+ ; {*round* result in hi word: ie. +0.5}\r
+ shr ax, 8 ; {shr eax,16} {to ax (result)}\r
+\r
+ POPx DI, BP ; Restore Registers \r
+ ret 4 ; Exit\r
+\r
+INT_SQR ENDP\r
+\r
+\r
+;============\r
+;TIMER_COUNT&\r
+;============\r
+;\r
+; Returns the current timer value as an integer/long integer\r
+;\r
+\r
+\r
+ PUBLIC TIMER_COUNT\r
+\r
+TIMER_COUNT PROC FAR\r
+\r
+ clr AX ; Segment = 0000\r
+ mov ES, AX ; use ES to get at data\r
+ mov AX, ES:[046Ch] ; Get Timer Lo Word\r
+ mov DX, ES:[046Eh] ; Get Timer Hi Word\r
+ ret ; Exit & Return value in DX:AX\r
+\r
+TIMER_COUNT ENDP\r
+\r
+\r
+ END\r
--- /dev/null
+\r
+ ' Misc Constants\r
+\r
+CONST True = -1, False = 0, nil = 0\r
+\r
+ ' Keyboard Codes: Extended\r
+\r
+CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00\r
+CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400\r
+\r
+CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000\r
+CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000\r
+\r
+CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100\r
+CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100\r
+\r
+CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00\r
+CONST KySIns = &HC200, KySDel = &HC300\r
+\r
+CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000\r
+CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300\r
+CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600\r
+CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900\r
+CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400\r
+CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00\r
+CONST KyAltY = &H1500, KyAltZ = &H2C00\r
+\r
+ ' Keyboard Codes: Ascii\r
+\r
+CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F\r
+CONST KyPlus = 45, KyMinus = 43\r
+\r
+ ' Color Constants\r
+\r
+CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3\r
+CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7\r
+CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11\r
+CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15\r
+CONST c.BRIGHT = 8\r
+\r
+ ' From UTILS.ASM\r
+\r
+DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$)\r
+DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$)\r
+DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%)\r
+DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD"\r
+DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%)\r
+DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM"\r
+DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT"\r
+DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%)\r
+\r
--- /dev/null
+\r
+CSEDIT - A Simple Font Editor by Matt Pritchard\r
+ \r
+ \r
+CSEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X\r
+Library for VGA Graphics.\r
+ \r
+WHAT YOU NEED TO RUN CSEDIT:\r
+ \r
+ * A Vga Monitor\r
+ * A Microsoft Compatible Mouse\r
+ \r
+ A Mouse is most definitely required, as the keyboard is used for\r
+ nothing except entering file names.\r
+ \r
+FILES NEEDED IN THE CURRENT DIRECTORY:\r
+ \r
+ CSEDIT.EXE - The Font Editor Program\r
+ CHARSETS.CS - The Font Editor's Internal Fonts\r
+ PALETTE.CS - The Font Editor's Palette\r
+ MOUSEIMG.CS - The Font Editor's Mouse Pointer\r
+ \r
+SAMPLE FONT FILE THAT SHOULD BE INCLUDED:\r
+ \r
+ SYSTEM.FNT - The Font used by CSEDIT.EXE\r
+ INVERSE.FNT - An Inverted version of SYSTEM.FNT\r
+ SPACEAGE.FNT - A Futuristic, Tech style font\r
+ ROM_8X8.FNT - The Lower 128 characters from the VGA BIOS Rom\r
+ \r
+WHAT IT EDITS:\r
+ \r
+ 8 by 8 character fonts, 128 characters at a time. 2 fonts at a time.\r
+ \r
+HOW IT WORKS/FEATURES:\r
+ \r
+ CSEDIT allows the user to edit 2 different font groups at a time,\r
+ which may be loaded and saved separately.\r
+ \r
+ A enlarged character grid allows the user to edit individual pixels\r
+ on a selected character.\r
+ \r
+ The Following operations can be performed on a single character or\r
+ simultaneously on a selected block of characters.\r
+ \r
+ * Shift the selected character(s) in any direction\r
+ with or without clipping at the edges.\r
+ * Vertically Flip the selected character(s)\r
+ * Horizontally Flip the selected character(s)\r
+ * Rotate the selected character(s) 90 Degrees Clockwise\r
+ * Rotate the selected character(s) 90 Degrees Counterclockwise\r
+ * Clear the selected character(s)\r
+ * Invert the selected character(s)\r
+ * XOR the selected character(s) with other character(s)\r
+ * AND the selected character(s) with other character(s)\r
+ * OR the selected character(s) with other character(s)\r
+ * Copy the selected character(s) to another position or font.\r
+ \r
+ An UNDO feature allows the reversal of the most recent operation.\r
+ \r
+DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN:\r
+ \r
+ Character Grid: (RED) Box in Upper Left corner of screen. This is\r
+ where you edit an individual character. The Left Button sets the\r
+ pixel the mouse pointer is on, while the Right Button clears that\r
+ pixel.\r
+ \r
+ Scroll Buttons: The Four Scroll Buttons are labeled with directional\r
+ arrows, and arranged in a diamond pattern. Left Clicking on a\r
+ directional button will scroll the currently selected character\r
+ in that direction, with the pixels on the edge rolling off and\r
+ appearing on the other size. Right Clicking will prevent the\r
+ pixels from rolling to the other side.\r
+ \r
+ Vertical Flip Button:\r
+ Horizontal Flip Button: Clicking these buttons will flip the pattern\r
+ of the currently selected character(s) around the indicated axis.\r
+ i.e. the top row will be swapped with the bottom row, etc. or the\r
+ left row column will be swapped with right column, etc.\r
+ depending upon which button you push.\r
+ \r
+ Invert Button: Clicking this button causes all pixels in the selected\r
+ character(s) to flip flop between on and off.\r
+ \r
+ Clear Button: Clicking this button erases the selected characters\r
+ \r
+ Rotate Buttons: Clicking these buttons will rotate the pattern in the\r
+ selected character(s) 90 degrees in the indicated direction.\r
+ \r
+ XOR Button: Clicking this button will let you XOR the currently\r
+ selected character(s) with other character(s) in either font.\r
+ The Button will turn RED, indicating that it is waiting for\r
+ you to click on the desired character (or upper left corner\r
+ of the desired block of characters) in either the Red or Green\r
+ Character Set Displays. Clicking anywhere else will abort this\r
+ process without doing anything. If you click on (any of) the\r
+ selected character(s) the operation is aborted. If a block is\r
+ selected and the character you click on is in a position where\r
+ it can't represent the upper left corner of a block of the same\r
+ size, then the operation is not performed.\r
+ \r
+ AND Button & OR Button: These buttons work just like the XOR Button\r
+ except that the Binary operation performed is either an AND or OR\r
+ depending upon which button you have selected.\r
+ \r
+ COPY Button: This button lets you copy a character or selected block\r
+ of characters to another area in the current font or the other\r
+ font. After clicking, the button turns RED and works much like\r
+ the XOR Button. Clicking on a valid position in either font\r
+ window will copy the selected character(s) to that location.\r
+ \r
+ MODE Button: Clicking this button toggles the editor between BLOCK\r
+ mode and CHARACTER mode. The current mode is displayed on a plate\r
+ at the top of the screen, just to the right of the enlarged\r
+ character grid. In character mode the plate will read "CHAR" and\r
+ the currently selected character is displayed just to the right\r
+ of the plate. In Block mode the plate will read "BLOCK" and the\r
+ enlarged character grid is disabled.\r
+ \r
+ UNDO Button: Clicking this Button will UNDO or reverse the effects of\r
+ the most recent operation.\r
+ \r
+ QUIT Button: Clicking this button will return you to DOS. Any loaded\r
+ fonts are not saved, and no confirmation is given.\r
+ \r
+ \r
+ GREEN FONT AREA: This area displays one of the current fonts which\r
+ can be edited. The characters are display in order from #0 to #127\r
+ from the upper left, going right, then down. The Font Box is 32\r
+ characters wide and 4 characters Tall. When the editor is in\r
+ character mode, just point at and Left Click on the character you\r
+ wish to edit and a Cyan box will appear around that character.\r
+\r
+ * If you Right Click on a character, the last current character,\r
+ which will still appear in the enlarged character grid, will be\r
+ copied onto the character you pointed at, replacing it. This is\r
+ a shortcut for copying characters: You can hold the right button\r
+ down an fill in a large area with a single character pattern.\r
+ When the editor is in Block Mode, you select an area by clicking\r
+ on any corner of the desired block. Then drag the mouse to the\r
+ opposite corner while holding down the left button. A Cyan Box\r
+ will stretch to surround the selected block of characters.\r
+ \r
+ GREEN FONT FILE NAME BOX: This Text Box is used to enter the name\r
+ of a font file to load or the name to save the current Green font\r
+ as. Just click on the Box, and it will change color and a\r
+ flashing cursor will appear. Now you type in a filename or edit\r
+ the existing filename. Press <RETURN> or click outside the text\r
+ box to end editing.\r
+ \r
+ GREEN FONT LOAD BUTTON: Clicking this button will load the font file\r
+ that is named in the Green File name box. If no name is given or\r
+ no such file exists, then nothing will be loaded.\r
+ \r
+ GREEN FONT SAVE BUTTON: Clicking this button will save the current\r
+ font in the Green Font Area under the name given in the File Name\r
+ Box. If a Valid name is not provided, nothing will be saved.\r
+ \r
+ RED FONT AREA: This is just the same as the GREEN FONT AREA; providing\r
+ you with the ability to copy and edit between multiple fonts.\r
+ \r
+ RED FONT FILE NAME BOX: This works just like the GREEN FONT FILE\r
+ NAME BOX.\r
+ \r
+ RED FONT LOAD BUTTON: This works just like the GREEN FONT LOAD BUTTON.\r
+ \r
+ RED FONT SAVE BUTTON: This works just like the GREEN FONT SAVE BUTTON.\r
+ \r
+ Message Bar: At the very bottom of the screen, this Bar will display\r
+ information and messages for various functions.\r
+ \r
+ \r
+FONT FILE FORMAT:\r
+ \r
+ BINARY Image, in order of character. The format is identical to that\r
+ used by the VGA ROM. The Files will be exactly 1024 (128 * 8) bytes\r
+ long.\r
+ \r
+ CHARACTER: 8 Bytes\r
+ \r
+ FONT: Array (0 to 127) of CHARACTER\r
+ \r
+ \r
+COMMENTS, QUESTIONS, BUG REPORTS, etc:\r
+ \r
+ Send the to the Author: Matt Pritchard\r
+ \r
+ Through the 80xxx Fidonet Echo or\r
+ \r
+ Matt Pritchard\r
+ P.O. Box 140264\r
+ Irving, TX 75014\r
+ \r
+CREDITS:\r
+ \r
+ This Font Editor was written in QuickBASIC 4.5\r
+ \r
--- /dev/null
+The following is a FAQ (Frequently Asked Question) summary of \r
+information and assembly routines for Mode "X" Graphics.\r
+\r
+An overview of Mode "X" for the VGA Adaptor:\r
+\r
+1) Mode "X" is a 256 color graphics mode that is available on *ANY* VGA\r
+card with the minimum of 256K video RAM. It is capable of providing\r
+higher resoultions than the only "Official" 256 color mode, mode 13h.\r
+(In quickbasic that is mode 13)\r
+\r
+2) Mode "X" comes in 8 different flavors: 320 or 360 pixels\r
+horizontally, and 200, 240, 400, and 480 pixels vertically.\r
+\r
+3) Since mode X is not supported by the VGA BIOS, there is no built in\r
+support for it. A program must provide its own routines for *ALL*\r
+operations in Mode "X", including setting up the video mode.\r
+\r
+4) Unlike Mode 13h, which has one display page, Mode "X" allows from 1\r
+to 4 video pages, depending upon the resoultion selected. The reason\r
+that Mode 13h has but one page is that it activates a VGA hardware\r
+feature known as CHAIN4, which prevents access to all but 64K of VGA's\r
+video RAM. CHAIN4 is what provides mode 13h's linear addres space.\r
+\r
+5) Unlike Mode 13h, where each 256 color (1-byte) pixel has a unique\r
+address in the E000: segement, in Mode X there are Four (4) Pixels\r
+at each address in E000: segment. The VGA's control registers allow you\r
+to control which of the 4 pixels is currently available at an address.\r
+\r
+6) It is possible to use the VGA's control registers to operate on 2 or\r
+more of the Pixels at the same address at the same time. The CPU can\r
+write one color value, and set up to 4 pixels with that value at the\r
+same time.\r
+\r
+7) Video RAM that is not being used for the current screen display can\r
+be used to store images and patterns. These images and patterns can be\r
+copied to other parts of the Video RAM 4 bytes (32 bits) at a time,\r
+which is much faster than the 8 bits (1 byte) at time that is possible\r
+over the ISA BUS. (16 Bit BUS operations can produce erroneous results)\r
+\r
+If anything is unclear, inadequate, or you just plain want to know more \r
+or have other specific questions, please send me a message.\r
+\r
+\r
+-Matt Pritchard\r
--- /dev/null
+;========================================================\r
+; MODEX.ASM - A Complete Mode X Library\r
+;\r
+; Version 1.04 Release, 3 May 1993, By Matt Pritchard\r
+; With considerable input from Michael Abrash\r
+;\r
+; The following information is donated to the public domain in\r
+; the hopes that save other programmers much frustration.\r
+;\r
+; If you do use this code in a product, it would be nice if\r
+; you include a line like "Mode X routines by Matt Pritchard"\r
+; in the credits.\r
+;\r
+; =========================================================\r
+;\r
+; All of this code is designed to be assembled with MASM 5.10a\r
+; but TASM 3.0 could be used as well.\r
+;\r
+; The routines contained are designed for use in a MEDIUM model\r
+; program. All Routines are FAR, and is assumed that a DGROUP\r
+; data segment exists and that DS will point to it on entry.\r
+;\r
+; For all routines, the AX, BX, CX, DX, ES and FLAGS registers\r
+; will not be preserved, while the DS, BP, SI and DI registers\r
+; will be preserved.\r
+;\r
+; Unless specifically noted, All Parameters are assumed to be\r
+; "PASSED BY VALUE". That is, the actual value is placed on\r
+; the stack. When a reference is passed it is assumed to be\r
+; a near pointer to a variable in the DGROUP segment.\r
+;\r
+; Routines that return a single 16-Bit integer value will\r
+; return that value in the AX register.\r
+;\r
+; This code will *NOT* run on an 8086/8088 because 80286+\r
+; specific instructions are used. If you have an 8088/86\r
+; and VGA, you can buy an 80386-40 motherboard for about\r
+; $160 and move into the 90's.\r
+;\r
+; This code is reasonably optimized: Most drawing loops have\r
+; been unrolled once and memory references are minimized by\r
+; keeping stuff in registers when possible.\r
+;\r
+; Error Trapping varies by Routine. No Clipping is performed\r
+; so the caller should verify that all coordinates are valid.\r
+;\r
+; Several Macros are used to simplify common 2 or 3 instruction\r
+; sequences. Several Single letter Text Constants also\r
+; simplify common assembler expressions like "WORD PTR".\r
+;\r
+; ------------------ Mode X Variations ------------------\r
+;\r
+; Mode # Screen Size Max Pages Aspect Ratio (X:Y)\r
+;\r
+; 0 320 x 200 4 Pages 1.2:1\r
+; 1 320 x 400 2 Pages 2.4:1\r
+; 2 360 x 200 3 Pages 1.35:1\r
+; 3 360 x 400 1 Page 2.7:1\r
+; 4 320 x 240 3 Pages 1:1\r
+; 5 320 x 480 1 Page 2:1\r
+; 6 360 x 240 3 Pages 1.125:1\r
+; 7 360 x 480 1 Page 2.25:1\r
+;\r
+; -------------------- The Legal Stuff ------------------\r
+;\r
+; No warranty, either written or implied, is made as to\r
+; the accuracy and usability of this code product. Use\r
+; at your own risk. Batteries not included. Pepperoni\r
+; and extra cheese available for an additional charge.\r
+;\r
+; ----------------------- The Author --------------------\r
+;\r
+; Matt Pritchard is a paid programmer who'd rather be\r
+; writing games. He can be reached at: P.O. Box 140264,\r
+; Irving, TX 75014 USA. Michael Abrash is a living\r
+; god, who now works for Bill Gates (Microsoft).\r
+;\r
+; -------------------- Revision History -----------------\r
+; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI\r
+; SET_MODEX now saves SI\r
+; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and\r
+; READ_DAC_REGISTERS. Expanded CLR Macro\r
+; to handle multiple registers\r
+;\r
+ \r
+ PAGE 255, 132\r
+ \r
+ .MODEL Medium\r
+ .286\r
+ \r
+ ; ===== MACROS =====\r
+ \r
+ ; Macro to OUT a 16 bit value to an I/O port\r
+ \r
+OUT_16 MACRO Register, Value\r
+ IFDIFI <Register>, <DX> ; If DX not setup\r
+ MOV DX, Register ; then Select Register\r
+ ENDIF\r
+ IFDIFI <Value>, <AX> ; If AX not setup\r
+ MOV AX, Value ; then Get Data Value\r
+ ENDIF\r
+ OUT DX, AX ; Set I/O Register(s)\r
+ENDM\r
+ \r
+ ; Macro to OUT a 8 bit value to an I/O Port\r
+ \r
+OUT_8 MACRO Register, Value\r
+ IFDIFI <Register>, <DX> ; If DX not setup\r
+ MOV DX, Register ; then Select Register\r
+ ENDIF\r
+ IFDIFI <Value>, <AL> ; If AL not Setup\r
+ MOV AL, Value ; then Get Data Value\r
+ ENDIF\r
+ OUT DX, AL ; Set I/O Register\r
+ENDM\r
+ \r
+ ; macros to PUSH and POP multiple registers\r
+ \r
+PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ PUSH R1 ; Save R1\r
+ PUSHx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+ \r
+POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
+ IFNB <R1>\r
+ POP R1 ; Restore R1\r
+ POPx R2, R3, R4, R5, R6, R7, R8\r
+ ENDIF\r
+ENDM\r
+ \r
+ ; Macro to Clear Registers to 0\r
+ \r
+CLR MACRO Register, R2, R3, R4, R5, R6\r
+ IFNB <Register>\r
+ XOR Register, Register ; Set Register = 0\r
+ CLR R2, R3, R4, R5, R6\r
+ ENDIF\r
+ENDM\r
+ \r
+ ; Macros to Decrement Counter & Jump on Condition\r
+ \r
+LOOPx MACRO Register, Destination\r
+ DEC Register ; Counter--\r
+ JNZ Destination ; Jump if not 0\r
+ENDM\r
+ \r
+LOOPjz MACRO Register, Destination\r
+ DEC Register ; Counter--\r
+ JZ Destination ; Jump if 0\r
+ENDM\r
+ \r
+ \r
+ ; ===== General Constants =====\r
+ \r
+ False EQU 0\r
+ True EQU -1\r
+ nil EQU 0\r
+ \r
+ b EQU BYTE PTR\r
+ w EQU WORD PTR\r
+ d EQU DWORD PTR\r
+ o EQU OFFSET\r
+ f EQU FAR PTR\r
+ s EQU SHORT\r
+ ?x4 EQU <?,?,?,?>\r
+ ?x3 EQU <?,?,?>\r
+ \r
+ ; ===== VGA Register Values =====\r
+ \r
+ VGA_Segment EQU 0A000h ; Vga Memory Segment\r
+ \r
+ ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller\r
+ GC_Index EQU 03CEh ; VGA Graphics Controller\r
+ SC_Index EQU 03C4h ; VGA Sequencer Controller\r
+ SC_Data EQU 03C5h ; VGA Sequencer Data Port\r
+ CRTC_Index EQU 03D4h ; VGA CRT Controller\r
+ CRTC_Data EQU 03D5h ; VGA CRT Controller Data\r
+ MISC_OUTPUT EQU 03C2h ; VGA Misc Register\r
+ INPUT_1 EQU 03DAh ; Input Status #1 Register\r
+ \r
+ DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register\r
+ DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register\r
+ PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W\r
+ \r
+ PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg\r
+ MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg\r
+ READ_MAP EQU 004h ; GC Index: Read Map Register\r
+ START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi\r
+ START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo\r
+ \r
+ MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1\r
+ MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1\r
+ ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes\r
+ \r
+ CHAIN4_OFF EQU 00604h ; Chain 4 mode Off\r
+ ASYNC_RESET EQU 00100h ; (A)synchronous Reset\r
+ SEQU_RESTART EQU 00300h ; Sequencer Restart\r
+ \r
+ LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches\r
+ LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU\r
+ \r
+ VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit\r
+ PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane #\r
+ ALL_PLANES EQU 0Fh ; All Bit Planes Selected\r
+ CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data\r
+ \r
+ GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set\r
+ ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer\r
+ ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer\r
+ \r
+ ; Constants Specific for these routines\r
+ \r
+ NUM_MODES EQU 8 ; # of Mode X Variations\r
+ \r
+ ; Specific Mode Data Table format...\r
+ \r
+Mode_Data_Table STRUC\r
+ M_MiscR DB ? ; Value of MISC_OUTPUT register\r
+ M_Pages DB ? ; Maximum Possible # of pages\r
+ M_XSize DW ? ; X Size Displayed on screen\r
+ M_YSize DW ? ; Y Size Displayed on screen\r
+ M_XMax DW ? ; Maximum Possible X Size\r
+ M_YMax DW ? ; Maximum Possible Y Size\r
+ M_CRTC DW ? ; Table of CRTC register values\r
+Mode_Data_Table ENDS\r
+ \r
+ ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====\r
+ \r
+ .DATA?\r
+ \r
+SCREEN_WIDTH DW 0 ; Width of a line in Bytes\r
+SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels\r
+ \r
+LAST_PAGE DW 0 ; # of Display Pages\r
+PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page\r
+ \r
+PAGE_SIZE DW 0 ; Size of Page in Addr Bytes\r
+ \r
+DISPLAY_PAGE DW 0 ; Page # currently displayed\r
+ACTIVE_PAGE DW 0 ; Page # currently active\r
+ \r
+CURRENT_PAGE DW 0 ; Offset of current Page\r
+CURRENT_SEGMENT DW 0 ; Segment of VGA memory\r
+ \r
+CURRENT_XOFFSET DW 0 ; Current Display X Offset\r
+CURRENT_YOFFSET DW 0 ; Current Display Y Offset\r
+ \r
+CURRENT_MOFFSET DW 0 ; Current Start Offset\r
+ \r
+MAX_XOFFSET DW 0 ; Current Display X Offset\r
+MAX_YOFFSET DW 0 ; Current Display Y Offset\r
+ \r
+CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127\r
+CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255\r
+ \r
+ .CODE\r
+ \r
+ ; ===== DATA TABLES =====\r
+ \r
+ ; Data Tables, Put in Code Segment for Easy Access\r
+ ; (Like when all the other Segment Registers are in\r
+ ; use!!) and reduced DGROUP requirements...\r
+ \r
+ ; Bit Mask Tables for Left/Right/Character Masks\r
+ \r
+Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H\r
+ \r
+Right_Clip_Mask DB 01H, 03H, 07H, 0FH\r
+ \r
+ ; Bit Patterns for converting character fonts\r
+ \r
+Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH\r
+ DB 01H,09H,05H,0DH,03H,0BH,07H,0FH\r
+ \r
+ ; CRTC Register Values for Various Configurations\r
+ \r
+MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes\r
+ DW 04009H ; Cell Height (1 Scan Line)\r
+ DW 00014H ; Dword Mode off\r
+ DW 0E317H ; turn on Byte Mode\r
+ DW nil ; End of CRTC Data for 400/480 Line Mode\r
+ \r
+MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes\r
+ DW 04109H ; Cell Height (2 Scan Lines)\r
+ DW 00014H ; Dword Mode off\r
+ DW 0E317H ; turn on Byte Mode\r
+ DW nil ; End of CRTC Data for 200/240 Line Mode\r
+ \r
+MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels\r
+ DW 05F00H ; Horz total\r
+ DW 04F01H ; Horz Displayed\r
+ DW 05002H ; Start Horz Blanking\r
+ DW 08203H ; End Horz Blanking\r
+ DW 05404H ; Start H Sync\r
+ DW 08005H ; End H Sync\r
+ DW nil ; End of CRTC Data for 320 Horz pixels\r
+ \r
+MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels\r
+ DW 06B00H ; Horz total\r
+ DW 05901H ; Horz Displayed\r
+ DW 05A02H ; Start Horz Blanking\r
+ DW 08E03H ; End Horz Blanking\r
+ DW 05E04H ; Start H Sync\r
+ DW 08A05H ; End H Sync\r
+ DW nil ; End of CRTC Data for 360 Horz pixels\r
+ \r
+MODE_200_Tall:\r
+MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes\r
+ DW 0BF06H ; Vertical Total\r
+ DW 01F07H ; Overflow\r
+ DW 09C10H ; V Sync Start\r
+ DW 08E11H ; V Sync End/Prot Cr0 Cr7\r
+ DW 08F12H ; Vertical Displayed\r
+ DW 09615H ; V Blank Start\r
+ DW 0B916H ; V Blank End\r
+ DW nil ; End of CRTC Data for 200/400 Lines\r
+ \r
+MODE_240_Tall:\r
+MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes\r
+ DW 00D06H ; Vertical Total\r
+ DW 03E07H ; Overflow\r
+ DW 0EA10H ; V Sync Start\r
+ DW 08C11H ; V Sync End/Prot Cr0 Cr7\r
+ DW 0DF12H ; Vertical Displayed\r
+ DW 0E715H ; V Blank Start\r
+ DW 00616H ; V Blank End\r
+ DW nil ; End of CRTC Data for 240/480 Lines\r
+ \r
+ ; Table of Display Mode Tables\r
+ \r
+MODE_TABLE:\r
+ DW o MODE_320x200, o MODE_320x400\r
+ DW o MODE_360x200, o MODE_360x400\r
+ DW o MODE_320x240, o MODE_320x480\r
+ DW o MODE_360x240, o MODE_360x480\r
+ \r
+ ; Table of Display Mode Components\r
+ \r
+MODE_320x200: ; Data for 320 by 200 Pixels\r
+ \r
+ DB 063h ; 400 scan Lines & 25 Mhz Clock\r
+ DB 4 ; Maximum of 4 Pages\r
+ DW 320, 200 ; Displayed Pixels (X,Y)\r
+ DW 1302, 816 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_320_Wide, o MODE_200_Tall\r
+ DW o MODE_Double_Line, nil\r
+ \r
+MODE_320x400: ; Data for 320 by 400 Pixels\r
+ \r
+ DB 063h ; 400 scan Lines & 25 Mhz Clock\r
+ DB 2 ; Maximum of 2 Pages\r
+ DW 320, 400 ; Displayed Pixels X,Y\r
+ DW 648, 816 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_320_Wide, o MODE_400_Tall\r
+ DW o MODE_Single_Line, nil\r
+ \r
+MODE_360x240: ; Data for 360 by 240 Pixels\r
+ \r
+ DB 0E7h ; 480 scan Lines & 28 Mhz Clock\r
+ DB 3 ; Maximum of 3 Pages\r
+ DW 360, 240 ; Displayed Pixels X,Y\r
+ DW 1092, 728 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_360_Wide, o MODE_240_Tall\r
+ DW o MODE_Double_Line , nil\r
+ \r
+MODE_360x480: ; Data for 360 by 480 Pixels\r
+ \r
+ DB 0E7h ; 480 scan Lines & 28 Mhz Clock\r
+ DB 1 ; Only 1 Page Possible\r
+ DW 360, 480 ; Displayed Pixels X,Y\r
+ DW 544, 728 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_360_Wide, o MODE_480_Tall\r
+ DW o MODE_Single_Line , nil\r
+ \r
+MODE_320x240: ; Data for 320 by 240 Pixels\r
+ \r
+ DB 0E3h ; 480 scan Lines & 25 Mhz Clock\r
+ DB 3 ; Maximum of 3 Pages\r
+ DW 320, 240 ; Displayed Pixels X,Y\r
+ DW 1088, 818 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_320_Wide, o MODE_240_Tall\r
+ DW o MODE_Double_Line, nil\r
+ \r
+MODE_320x480: ; Data for 320 by 480 Pixels\r
+ \r
+ DB 0E3h ; 480 scan Lines & 25 Mhz Clock\r
+ DB 1 ; Only 1 Page Possible\r
+ DW 320, 480 ; Displayed Pixels X,Y\r
+ DW 540, 818 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_320_WIDE, o MODE_480_Tall\r
+ DW o MODE_Single_Line, nil\r
+ \r
+MODE_360x200: ; Data for 360 by 200 Pixels\r
+ \r
+ DB 067h ; 400 scan Lines & 28 Mhz Clock\r
+ DB 3 ; Maximum of 3 Pages\r
+ DW 360, 200 ; Displayed Pixels (X,Y)\r
+ DW 1302, 728 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_360_Wide, MODE_200_Tall\r
+ DW o MODE_Double_Line, nil\r
+ \r
+MODE_360x400: ; Data for 360 by 400 Pixels\r
+ \r
+ DB 067h ; 400 scan Lines & 28 Mhz Clock\r
+ DB 1 ; Maximum of 1 Pages\r
+ DW 360, 400 ; Displayed Pixels X,Y\r
+ DW 648, 816 ; Max Possible X and Y Sizes\r
+ \r
+ DW o MODE_360_Wide, MODE_400_Tall\r
+ DW o MODE_Single_Line, nil\r
+ \r
+ \r
+ ; ===== MODE X SETUP ROUTINES =====\r
+ \r
+;======================================================\r
+;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)\r
+;======================================================\r
+;\r
+; Sets Up the specified version of Mode X. Allows for\r
+; the setup of multiple video pages, and a virtual\r
+; screen which can be larger than the displayed screen\r
+; (which can then be scrolled a pixel at a time)\r
+;\r
+; ENTRY: ModeType = Desired Screen Resolution (0-7)\r
+;\r
+; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio\r
+; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio\r
+; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio\r
+; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio\r
+; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio\r
+; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio\r
+; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio\r
+; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio\r
+;\r
+; MaxXpos = The Desired Virtual Screen Width\r
+; MaxYpos = The Desired Virtual Screen Height\r
+; Pages = The Desired # of Video Pages\r
+;\r
+; EXIT: AX = Success Flag: 0 = Failure / -1= Success\r
+;\r
+ \r
+SVM_STACK STRUC\r
+ SVM_Table DW ? ; Offset of Mode Info Table\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ SVM_Pages DW ? ; # of Screen Pages desired\r
+ SVM_Ysize DW ? ; Vertical Screen Size Desired\r
+ SVM_Xsize DW ? ; Horizontal Screen Size Desired\r
+ SVM_Mode DW ? ; Display Resolution Desired\r
+SVM_STACK ENDS\r
+ \r
+ PUBLIC SET_VGA_MODEX\r
+ \r
+SET_VGA_MODEX PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 2 ; Allocate workspace\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ ; Check Legality of Mode Request....\r
+ \r
+ MOV BX, [BP].SVM_Mode ; Get Requested Mode #\r
+ CMP BX, NUM_MODES ; Is it 0..7?\r
+ JAE @SVM_BadModeSetup ; If Not, Error out\r
+ \r
+ SHL BX, 1 ; Scale BX\r
+ MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info\r
+ MOV [BP].SVM_Table, SI ; Save ptr for later use\r
+ \r
+ ; Check # of Requested Display Pages\r
+ \r
+ MOV CX, [BP].SVM_Pages ; Get # of Requested Pages\r
+ CLR CH ; Set Hi Word = 0!\r
+ CMP CL, CS:[SI].M_Pages ; Check # Pages for mode\r
+ JA @SVM_BadModeSetup ; Report Error if too Many Pages\r
+ JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages\r
+ \r
+ ; Check Validity of X Size\r
+ \r
+ AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0\r
+ \r
+ MOV AX, [BP].SVM_XSize ; Get Logical Screen Width\r
+ CMP AX, CS:[SI].M_XSize ; Check against Displayed X\r
+ JB @SVM_BadModeSetup ; Report Error if too small\r
+ CMP AX, CS:[SI].M_XMax ; Check against Max X\r
+ JA @SVM_BadModeSetup ; Report Error if too big\r
+ \r
+ ; Check Validity of Y Size\r
+ \r
+ MOV BX, [BP].SVM_YSize ; Get Logical Screen Height\r
+ CMP BX, CS:[SI].M_YSize ; Check against Displayed Y\r
+ JB @SVM_BadModeSetup ; Report Error if too small\r
+ CMP BX, CS:[SI].M_YMax ; Check against Max Y\r
+ JA @SVM_BadModeSetup ; Report Error if too big\r
+ \r
+ ; Enough memory to Fit it all?\r
+ \r
+ SHR AX, 2 ; # of Bytes:Line = XSize/4\r
+ MUL CX ; AX = Bytes/Line * Pages\r
+ MUL BX ; DX:AX = Total VGA mem needed\r
+ JNO @SVM_Continue ; Exit if Total Size > 256K\r
+ \r
+ DEC DX ; Was it Exactly 256K???\r
+ OR DX, AX ; (DX = 1, AX = 0000)\r
+ JZ @SVM_Continue ; if so, it's valid...\r
+ \r
+@SVM_BadModeSetup:\r
+ \r
+ CLR AX ; Return Value = False\r
+ JMP @SVM_Exit ; Normal Exit\r
+ \r
+@SVM_Continue:\r
+ \r
+ MOV AX, 13H ; Start with Mode 13H\r
+ INT 10H ; Let BIOS Set Mode\r
+ \r
+ OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode\r
+ OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset\r
+ OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size\r
+ OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...\r
+ \r
+ OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register\r
+ INC DX ; Point to Data\r
+ IN AL, DX ; Get Value, Bit 7 = Protect\r
+ AND AL, 7FH ; Mask out Write Protect\r
+ OUT DX, AL ; And send it back\r
+ \r
+ MOV DX, CRTC_INDEX ; Vga Crtc Registers\r
+ ADD SI, M_CRTC ; SI -> CRTC Parameter Data\r
+ \r
+ ; Load Tables of CRTC Parameters from List of Tables\r
+ \r
+@SVM_Setup_Table:\r
+ \r
+ MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl\r
+ ADD SI, 2 ; Point to next Ptr Entry\r
+ OR DI, DI ; A nil Ptr means that we have\r
+ JZ @SVM_Set_Data ; finished CRTC programming\r
+ \r
+@SVM_Setup_CRTC:\r
+ MOV AX, CS:[DI] ; Get CRTC Data from Table\r
+ ADD DI, 2 ; Advance Pointer\r
+ OR AX, AX ; At End of Data Table?\r
+ JZ @SVM_Setup_Table ; If so, Exit & get next Table\r
+ \r
+ OUT DX, AX ; Reprogram VGA CRTC reg\r
+ JMP s @SVM_Setup_CRTC ; Process Next Table Entry\r
+ \r
+ ; Initialize Page & Scroll info, DI = 0\r
+ \r
+@SVM_Set_Data:\r
+ MOV DISPLAY_PAGE, DI ; Display Page = 0\r
+ MOV ACTIVE_PAGE, DI ; Active Page = 0\r
+ MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0\r
+ MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0\r
+ MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0\r
+ MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0\r
+ \r
+ MOV AX, VGA_SEGMENT ; Segment for VGA memory\r
+ MOV CURRENT_SEGMENT, AX ; Save for Future LES's\r
+ \r
+ ; Set Logical Screen Width, X Scroll and Our Data\r
+ \r
+ MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info\r
+ MOV AX, [BP].SVM_Xsize ; Get Display Width\r
+ \r
+ MOV CX, AX ; CX = Logical Width\r
+ SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value\r
+ MOV MAX_XOFFSET, CX ; Set Maximum X Scroll\r
+ \r
+ SHR AX, 2 ; Bytes = Pixels / 4\r
+ MOV SCREEN_WIDTH, AX ; Save Width in Pixels\r
+ \r
+ SHR AX, 1 ; Offset Value = Bytes / 2\r
+ MOV AH, 13h ; CRTC Offset Register Index\r
+ XCHG AL, AH ; Switch format for OUT\r
+ OUT DX, AX ; Set VGA CRTC Offset Reg\r
+ \r
+ ; Setup Data table, Y Scroll, Misc for Other Routines\r
+ \r
+ MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height\r
+ \r
+ MOV CX, AX ; CX = Logical Height\r
+ SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value\r
+ MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll\r
+ \r
+ MOV SCREEN_HEIGHT, AX ; Save Height in Pixels\r
+ MUL SCREEN_WIDTH ; AX = Page Size in Bytes,\r
+ MOV PAGE_SIZE, AX ; Save Page Size\r
+ \r
+ MOV CX, [BP].SVM_Pages ; Get # of Pages\r
+ MOV LAST_PAGE, CX ; Save # of Pages\r
+ \r
+ CLR BX ; Page # = 0\r
+ MOV DX, BX ; Page 0 Offset = 0\r
+ \r
+@SVM_Set_Pages:\r
+ \r
+ MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset\r
+ ADD BX, 2 ; Page#++\r
+ ADD DX, AX ; Compute Addr of Next Page\r
+ LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set\r
+ \r
+ ; Clear VGA Memory\r
+ \r
+ OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes\r
+ LES DI, d CURRENT_PAGE ; -> Start of VGA memory\r
+ \r
+ CLR AX ; AX = 0\r
+ CLD ; Block Xfer Forwards\r
+ MOV CX, 8000H ; 32K * 4 * 2 = 256K\r
+ REP STOSW ; Clear dat memory!\r
+ \r
+ ; Setup Font Pointers\r
+ \r
+ MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127\r
+ MOV AX, GET_CHAR_PTR ; Service to Get Pointer\r
+ INT 10h ; Call VGA BIOS\r
+ \r
+ MOV CHARSET_LOW, BP ; Save Char Set Offset\r
+ MOV CHARSET_LOW+2, ES ; Save Char Set Segment\r
+ \r
+ MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255\r
+ MOV AX, GET_CHAR_PTR ; Service to Get Pointer\r
+ INT 10h ; Call VGA BIOS\r
+ \r
+ MOV CHARSET_HI, BP ; Save Char Set Offset\r
+ MOV CHARSET_HI+2, ES ; Save Char Set Segment\r
+ \r
+ MOV AX, True ; Return Success Code\r
+ \r
+@SVM_EXIT:\r
+ ADD SP, 2 ; Deallocate workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 8 ; Exit & Clean Up Stack\r
+ \r
+SET_VGA_MODEX ENDP\r
+ \r
+ \r
+;==================\r
+;SET_MODEX% (Mode%)\r
+;==================\r
+;\r
+; Quickie Mode Set - Sets Up Mode X to Default Configuration\r
+;\r
+; ENTRY: ModeType = Desired Screen Resolution (0-7)\r
+; (See SET_VGA_MODEX for list)\r
+;\r
+; EXIT: AX = Success Flag: 0 = Failure / -1= Success\r
+;\r
+ \r
+SM_STACK STRUC\r
+ DW ?,? ; BP, SI\r
+ DD ? ; Caller\r
+ SM_Mode DW ? ; Desired Screen Resolution\r
+SM_STACK ENDS\r
+ \r
+ PUBLIC SET_MODEX\r
+ \r
+SET_MODEX PROC FAR\r
+ \r
+ PUSHx BP, SI ; Preserve Important registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ CLR AX ; Assume Failure\r
+ MOV BX, [BP].SM_Mode ; Get Desired Mode #\r
+ CMP BX, NUM_MODES ; Is it a Valid Mode #?\r
+ JAE @SMX_Exit ; If Not, don't Bother\r
+ \r
+ PUSH BX ; Push Mode Parameter\r
+ \r
+ SHL BX, 1 ; Scale BX to word Index\r
+ MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info\r
+ \r
+ PUSH CS:[SI].M_XSize ; Push Default X Size\r
+ PUSH CS:[SI].M_Ysize ; Push Default Y size\r
+ MOV AL, CS:[SI].M_Pages ; Get Default # of Pages\r
+ CLR AH ; Hi Byte = 0\r
+ PUSH AX ; Push # Pages\r
+ \r
+ CALL f SET_VGA_MODEX ; Set up Mode X!\r
+ \r
+@SMX_Exit:\r
+ POPx SI, BP ; Restore Registers\r
+ RET 2 ; Exit & Clean Up Stack\r
+ \r
+SET_MODEX ENDP\r
+ \r
+ \r
+ ; ===== BASIC GRAPHICS PRIMITIVES =====\r
+ \r
+;============================\r
+;CLEAR_VGA_SCREEN (ColorNum%)\r
+;============================\r
+;\r
+; Clears the active display page\r
+;\r
+; ENTRY: ColorNum = Color Value to fill the page with\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+CVS_STACK STRUC\r
+ DW ?,? ; DI, BP\r
+ DD ? ; Caller\r
+ CVS_COLOR DB ?,? ; Color to Set Screen to\r
+CVS_STACK ENDS\r
+ \r
+ PUBLIC CLEAR_VGA_SCREEN\r
+ \r
+CLEAR_VGA_SCREEN PROC FAR\r
+ \r
+ PUSHx BP, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes\r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AL, [BP].CVS_COLOR ; Get Color\r
+ MOV AH, AL ; Copy for Word Write\r
+ CLD ; Block fill Forwards\r
+ \r
+ MOV CX, PAGE_SIZE ; Get Size of Page\r
+ SHR CX, 1 ; Divide by 2 for Words\r
+ REP STOSW ; Block Fill VGA memory\r
+ \r
+ POPx DI, BP ; Restore Saved Registers\r
+ RET 2 ; Exit & Clean Up Stack\r
+ \r
+CLEAR_VGA_SCREEN ENDP\r
+ \r
+ \r
+;===================================\r
+;SET_POINT (Xpos%, Ypos%, ColorNum%)\r
+;===================================\r
+;\r
+; Plots a single Pixel on the active display page\r
+;\r
+; ENTRY: Xpos = X position to plot pixel at\r
+; Ypos = Y position to plot pixel at\r
+; ColorNum = Color to plot pixel with\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SP_STACK STRUC\r
+ DW ?,? ; BP, DI\r
+ DD ? ; Caller\r
+ SETP_Color DB ?,? ; Color of Point to Plot\r
+ SETP_Ypos DW ? ; Y pos of Point to Plot\r
+ SETP_Xpos DW ? ; X pos of Point to Plot\r
+SP_STACK ENDS\r
+ \r
+ PUBLIC SET_POINT\r
+ \r
+SET_POINT PROC FAR\r
+ \r
+ PUSHx BP, DI ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel\r
+ MUL SCREEN_WIDTH ; Get Offset to Start of Line\r
+ \r
+ MOV BX, [BP].SETP_Xpos ; Get Xpos\r
+ MOV CX, BX ; Copy to extract Plane # from\r
+ SHR BX, 2 ; X offset (Bytes) = Xpos/4\r
+ ADD BX, AX ; Offset = Width*Ypos + Xpos/4\r
+ \r
+ MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register\r
+ AND CL, PLANE_BITS ; Get Plane Bits\r
+ SHL AH, CL ; Get Plane Select Value\r
+ OUT_16 SC_Index, AX ; Select Plane\r
+ \r
+ MOV AL,[BP].SETP_Color ; Get Pixel Color\r
+ MOV ES:[DI+BX], AL ; Draw Pixel\r
+ \r
+ POPx DI, BP ; Restore Saved Registers\r
+ RET 6 ; Exit and Clean up Stack\r
+ \r
+SET_POINT ENDP\r
+ \r
+ \r
+;==========================\r
+;READ_POINT% (Xpos%, Ypos%)\r
+;==========================\r
+;\r
+; Read the color of a pixel from the Active Display Page\r
+;\r
+; ENTRY: Xpos = X position of pixel to read\r
+; Ypos = Y position of pixel to read\r
+;\r
+; EXIT: AX = Color of Pixel at (Xpos, Ypos)\r
+;\r
+ \r
+RP_STACK STRUC\r
+ DW ?,? ; BP, DI\r
+ DD ? ; Caller\r
+ RP_Ypos DW ? ; Y pos of Point to Read\r
+ RP_Xpos DW ? ; X pos of Point to Read\r
+RP_STACK ENDS\r
+ \r
+ PUBLIC READ_POINT\r
+ \r
+READ_POINT PROC FAR\r
+ \r
+ PUSHx BP, DI ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AX, [BP].RP_Ypos ; Get Line # of Pixel\r
+ MUL SCREEN_WIDTH ; Get Offset to Start of Line\r
+ \r
+ MOV BX, [BP].RP_Xpos ; Get Xpos\r
+ MOV CX, BX\r
+ SHR BX, 2 ; X offset (Bytes) = Xpos/4\r
+ ADD BX, AX ; Offset = Width*Ypos + Xpos/4\r
+ \r
+ MOV AL, READ_MAP ; GC Read Mask Register\r
+ MOV AH, CL ; Get Xpos\r
+ AND AH, PLANE_BITS ; & mask out Plane #\r
+ OUT_16 GC_INDEX, AX ; Select Plane to read in\r
+ \r
+ CLR AH ; Clear Return Value Hi byte\r
+ MOV AL, ES:[DI+BX] ; Get Color of Pixel\r
+ \r
+ POPx DI, BP ; Restore Saved Registers\r
+ RET 4 ; Exit and Clean up Stack\r
+ \r
+READ_POINT ENDP\r
+ \r
+ \r
+;======================================================\r
+;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)\r
+;======================================================\r
+;\r
+; Fills a rectangular block on the active display Page\r
+;\r
+; ENTRY: Xpos1 = Left X position of area to fill\r
+; Ypos1 = Top Y position of area to fill\r
+; Xpos2 = Right X position of area to fill\r
+; Ypos2 = Bottom Y position of area to fill\r
+; ColorNum = Color to fill area with\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+FB_STACK STRUC\r
+ DW ?x4 ; DS, DI, SI, BP\r
+ DD ? ; Caller\r
+ FB_Color DB ?,? ; Fill Color\r
+ FB_Ypos2 DW ? ; Y pos of Lower Right Pixel\r
+ FB_Xpos2 DW ? ; X pos of Lower Right Pixel\r
+ FB_Ypos1 DW ? ; Y pos of Upper Left Pixel\r
+ FB_Xpos1 DW ? ; X pos of Upper Left Pixel\r
+FB_STACK ENDS\r
+ \r
+ PUBLIC FILL_BLOCK\r
+ \r
+FILL_BLOCK PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ CLD ; Direction Flag = Forward\r
+ \r
+ OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
+ \r
+ ; Validate Pixel Coordinates\r
+ ; If necessary, Swap so X1 <= X2, Y1 <= Y2\r
+ \r
+ MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?\r
+ MOV BX, [BP].FB_Ypos2 ; BX = Y2\r
+ CMP AX, BX\r
+ JLE @FB_NOSWAP1\r
+ \r
+ MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1\r
+ XCHG AX, BX ; on stack for future use\r
+ \r
+@FB_NOSWAP1:\r
+ SUB BX, AX ; Get Y width\r
+ INC BX ; Add 1 to avoid 0 value\r
+ MOV [BP].FB_Ypos2, BX ; Save in Ypos2\r
+ \r
+ MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line\r
+ ADD DI, AX ; DI = Start of Line Y1\r
+ \r
+ MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2\r
+ MOV BX, [BP].FB_Xpos2 ;\r
+ CMP AX, BX\r
+ JLE @FB_NOSWAP2 ; Skip Ahead if Ok\r
+ \r
+ MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2\r
+ XCHG AX, BX ; on stack for future use\r
+ \r
+ ; All our Input Values are in order, Now determine\r
+ ; How many full "bands" 4 pixels wide (aligned) there\r
+ ; are, and if there are partial bands (<4 pixels) on\r
+ ; the left and right edges.\r
+ \r
+@FB_NOSWAP2:\r
+ MOV DX, AX ; DX = X1 (Pixel Position)\r
+ SHR DX, 2 ; DX/4 = Bytes into Line\r
+ ADD DI, DX ; DI = Addr of Upper-Left Corner\r
+ \r
+ MOV CX, BX ; CX = X2 (Pixel Position)\r
+ SHR CX, 2 ; CX/4 = Bytes into Line\r
+ \r
+ CMP DX, CX ; Start and end in same band?\r
+ JNE @FB_NORMAL ; if not, check for l & r edges\r
+ JMP @FB_ONE_BAND_ONLY ; if so, then special processing\r
+ \r
+@FB_NORMAL:\r
+ SUB CX, DX ; CX = # bands -1\r
+ MOV SI, AX ; SI = PLANE#(X1)\r
+ AND SI, PLANE_BITS ; if Left edge is aligned then\r
+ JZ @FB_L_PLANE_FLUSH ; no special processing..\r
+ \r
+ ; Draw "Left Edge" vertical strip of 1-3 pixels...\r
+ \r
+ OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask\r
+ \r
+ MOV SI, DI ; SI = Copy of Start Addr (UL)\r
+ \r
+ MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
+ MOV AL, [BP].FB_Color ; Get Fill Color\r
+ MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
+ \r
+@FB_LEFT_LOOP:\r
+ MOV ES:[SI], AL ; Fill in Left Edge Pixels\r
+ ADD SI, BX ; Point to Next Line (Below)\r
+ LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn\r
+ \r
+ MOV ES:[SI], AL ; Fill in Left Edge Pixels\r
+ ADD SI, BX ; Point to Next Line (Below)\r
+ LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn\r
+ \r
+@FB_LEFT_CONT:\r
+ \r
+ INC DI ; Point to Middle (or Right) Block\r
+ DEC CX ; Reset CX instead of JMP @FB_RIGHT\r
+ \r
+@FB_L_PLANE_FLUSH:\r
+ INC CX ; Add in Left band to middle block\r
+ \r
+ ; DI = Addr of 1st middle Pixel (band) to fill\r
+ ; CX = # of Bands to fill -1\r
+ \r
+@FB_RIGHT:\r
+ MOV SI, [BP].FB_Xpos2 ; Get Xpos2\r
+ AND SI, PLANE_BITS ; Get Plane values\r
+ CMP SI, 0003 ; Plane = 3?\r
+ JE @FB_R_EDGE_FLUSH ; Hey, add to middle\r
+ \r
+ ; Draw "Right Edge" vertical strip of 1-3 pixels...\r
+ \r
+ OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask\r
+ \r
+ MOV SI, DI ; Get Addr of Left Edge\r
+ ADD SI, CX ; Add Width-1 (Bands)\r
+ DEC SI ; To point to top of Right Edge\r
+ \r
+ MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
+ MOV AL, [BP].FB_Color ; Get Fill Color\r
+ MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
+ \r
+@FB_RIGHT_LOOP:\r
+ MOV ES:[SI], AL ; Fill in Right Edge Pixels\r
+ ADD SI, BX ; Point to Next Line (Below)\r
+ LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn\r
+ \r
+ MOV ES:[SI], AL ; Fill in Right Edge Pixels\r
+ ADD SI, BX ; Point to Next Line (Below)\r
+ LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn\r
+ \r
+@FB_RIGHT_CONT:\r
+ \r
+ DEC CX ; Minus 1 for Middle bands\r
+ JZ @FB_EXIT ; Uh.. no Middle bands...\r
+ \r
+@FB_R_EDGE_FLUSH:\r
+ \r
+ ; DI = Addr of Upper Left block to fill\r
+ ; CX = # of Bands to fill in (width)\r
+ \r
+ OUT_8 SC_Data, ALL_PLANES ; Write to All Planes\r
+ \r
+ MOV DX, SCREEN_WIDTH ; DX = DI Increment\r
+ SUB DX, CX ; = Screen_Width-# Planes Filled\r
+ \r
+ MOV BX, CX ; BX = Quick Refill for CX\r
+ MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill\r
+ MOV AL, [BP].FB_Color ; Get Fill Color\r
+ \r
+@FB_MIDDLE_LOOP:\r
+ REP STOSB ; Fill in entire line\r
+ \r
+ MOV CX, BX ; Recharge CX (Line Width)\r
+ ADD DI, DX ; Point to start of Next Line\r
+ LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn\r
+ \r
+ JMP s @FB_EXIT ; Outa here\r
+ \r
+@FB_ONE_BAND_ONLY:\r
+ MOV SI, AX ; Get Left Clip Mask, Save X1\r
+ AND SI, PLANE_BITS ; Mask out Row #\r
+ MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask\r
+ MOV SI, BX ; Get Right Clip Mask, Save X2\r
+ AND SI, PLANE_BITS ; Mask out Row #\r
+ AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte\r
+ \r
+ OUT_8 SC_Data, AL ; Clip For Left & Right Masks\r
+ \r
+ MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
+ MOV AL, [BP].FB_Color ; Get Fill Color\r
+ MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
+ \r
+@FB_ONE_LOOP:\r
+ MOV ES:[DI], AL ; Fill in Pixels\r
+ ADD DI, BX ; Point to Next Line (Below)\r
+ LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn\r
+ \r
+ MOV ES:[DI], AL ; Fill in Pixels\r
+ ADD DI, BX ; Point to Next Line (Below)\r
+ LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn\r
+ \r
+@FB_EXIT:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 10 ; Exit and Clean up Stack\r
+ \r
+FILL_BLOCK ENDP\r
+ \r
+ \r
+;=====================================================\r
+;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)\r
+;=====================================================\r
+;\r
+; Draws a Line on the active display page\r
+;\r
+; ENTRY: Xpos1 = X position of first point on line\r
+; Ypos1 = Y position of first point on line\r
+; Xpos2 = X position of last point on line\r
+; Ypos2 = Y position of last point on line\r
+; ColorNum = Color to draw line with\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+DL_STACK STRUC\r
+ DW ?x3 ; DI, SI, BP\r
+ DD ? ; Caller\r
+ DL_ColorF DB ?,? ; Line Draw Color\r
+ DL_Ypos2 DW ? ; Y pos of last point\r
+ DL_Xpos2 DW ? ; X pos of last point\r
+ DL_Ypos1 DW ? ; Y pos of first point\r
+ DL_Xpos1 DW ? ; X pos of first point\r
+DL_STACK ENDS\r
+ \r
+ PUBLIC DRAW_LINE\r
+ \r
+DRAW_LINE PROC FAR\r
+ \r
+ PUSHx BP, SI, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ CLD ; Direction Flag = Forward\r
+ \r
+ OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
+ MOV CH, [BP].DL_ColorF ; Save Line Color in CH\r
+ \r
+ ; Check Line Type\r
+ \r
+ MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?\r
+ MOV DI, [BP].DL_Xpos2 ; DX = X2\r
+ CMP SI, DI ; Is X1 < X2\r
+ JE @DL_VLINE ; If X1=X2, Draw Vertical Line\r
+ JL @DL_NOSWAP1 ; If X1 < X2, don't swap\r
+ \r
+ XCHG SI, DI ; X2 IS > X1, SO SWAP THEM\r
+ \r
+@DL_NOSWAP1:\r
+ \r
+ ; SI = X1, DI = X2\r
+ \r
+ MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?\r
+ CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?\r
+ JE @DL_HORZ ; If so, Draw a Horizontal Line\r
+ \r
+ JMP @DL_BREZHAM ; Diagonal line... go do it...\r
+ \r
+ ; This Code draws a Horizontal Line in Mode X where:\r
+ ; SI = X1, DI = X2, and AX = Y1/Y2\r
+ \r
+@DL_HORZ:\r
+ \r
+ MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width\r
+ MOV DX, AX ; CX = Line offset into Page\r
+ \r
+ MOV AX, SI ; Get Left edge, Save X1\r
+ AND SI, PLANE_BITS ; Mask out Row #\r
+ MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask\r
+ MOV CX, DI ; Get Right edge, Save X2\r
+ AND DI, PLANE_BITS ; Mask out Row #\r
+ MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte\r
+ \r
+ SHR AX, 2 ; Get X1 Byte # (=X1/4)\r
+ SHR CX, 2 ; Get X2 Byte # (=X2/4)\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ ADD DI, DX ; Point to Start of Line\r
+ ADD DI, AX ; Point to Pixel X1\r
+ \r
+ SUB CX, AX ; CX = # Of Bands (-1) to set\r
+ JNZ @DL_LONGLN ; jump if longer than one segment\r
+ \r
+ AND BL, BH ; otherwise, merge clip masks\r
+ \r
+@DL_LONGLN:\r
+ \r
+ OUT_8 SC_Data, BL ; Set the Left Clip Mask\r
+ \r
+ MOV AL, [BP].DL_ColorF ; Get Line Color\r
+ MOV BL, AL ; BL = Copy of Line Color\r
+ STOSB ; Set Left (1-4) Pixels\r
+ \r
+ JCXZ @DL_EXIT ; Done if only one Line Segment\r
+ \r
+ DEC CX ; CX = # of Middle Segments\r
+ JZ @DL_XRSEG ; If no middle segments....\r
+ \r
+ ; Draw Middle Segments\r
+ \r
+ OUT_8 DX, ALL_PLANES ; Write to ALL Planes\r
+ \r
+ MOV AL, BL ; Get Color from BL\r
+ REP STOSB ; Draw Middle (4 Pixel) Segments\r
+ \r
+@DL_XRSEG:\r
+ OUT_8 DX, BH ; Select Planes for Right Clip Mask\r
+ MOV AL, BL ; Get Color Value\r
+ STOSB ; Draw Right (1-4) Pixels\r
+ \r
+ JMP s @DL_EXIT ; We Are Done...\r
+ \r
+ \r
+ ; This Code Draws A Vertical Line. On entry:\r
+ ; CH = Line Color, SI & DI = X1\r
+ \r
+@DL_VLINE:\r
+ \r
+ MOV AX, [BP].DL_Ypos1 ; AX = Y1\r
+ MOV SI, [BP].DL_Ypos2 ; SI = Y2\r
+ CMP AX, SI ; Is Y1 < Y2?\r
+ JLE @DL_NOSWAP2 ; if so, Don't Swap them\r
+ \r
+ XCHG AX, SI ; Ok, NOW Y1 < Y2\r
+ \r
+@DL_NOSWAP2:\r
+ \r
+ SUB SI, AX ; SI = Line Height (Y2-Y1+1)\r
+ INC SI\r
+ \r
+ ; AX = Y1, DI = X1, Get offset into Page into AX\r
+ \r
+ MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width\r
+ MOV DX, DI ; Copy Xpos into DX\r
+ SHR DI, 2 ; DI = Xpos/4\r
+ ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ ADD DI, AX ; Point to Pixel X1, Y1\r
+ \r
+ ;Select Plane\r
+ \r
+ MOV CL, DL ; CL = Save X1\r
+ AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)\r
+ MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1\r
+ SHL AH, CL ; Change to Correct Plane #\r
+ OUT_16 SC_Index, AX ; Select Plane\r
+ \r
+ MOV AL, CH ; Get Saved Color\r
+ MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By\r
+ \r
+@DL_VLoop:\r
+ MOV ES:[DI], AL ; Draw Single Pixel\r
+ ADD DI, BX ; Point to Next Line\r
+ LOOPjz SI, @DL_EXIT ; Lines--, Exit if done\r
+ \r
+ MOV ES:[DI], AL ; Draw Single Pixel\r
+ ADD DI, BX ; Point to Next Line\r
+ LOOPx SI, @DL_VLoop ; Lines--, Loop until Done\r
+ \r
+@DL_EXIT:\r
+ \r
+ JMP @DL_EXIT2 ; Done!\r
+ \r
+ ; This code Draws a diagonal line in Mode X\r
+ \r
+@DL_BREZHAM:\r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AX, [BP].DL_Ypos1 ; get Y1 value\r
+ MOV BX, [BP].DL_Ypos2 ; get Y2 value\r
+ MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos\r
+ \r
+ CMP BX, AX ; Y2-Y1 is?\r
+ JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...\r
+ \r
+ XCHG BX, AX ; Swap em...\r
+ MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos\r
+ \r
+@DL_DeltaYOK:\r
+ MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1\r
+ \r
+ ADD DI, AX ; DI -> Start of Line Y1 on Page\r
+ MOV AX, CX ; AX = Xpos (X1)\r
+ SHR AX, 2 ; /4 = Byte Offset into Line\r
+ ADD DI, AX ; DI = Starting pos (X1,Y1)\r
+ \r
+ MOV AL, 11h ; Staring Mask\r
+ AND CL, PLANE_BITS ; Get Plane #\r
+ SHL AL, CL ; and shift into place\r
+ MOV AH, [BP].DL_ColorF ; Color in Hi Bytes\r
+ \r
+ PUSH AX ; Save Mask,Color...\r
+ \r
+ MOV AH, AL ; Plane # in AH\r
+ MOV AL, MAP_MASK ; Select Plane Register\r
+ OUT_16 SC_Index, AX ; Select initial plane\r
+ \r
+ MOV AX, [BP].DL_Xpos1 ; get X1 value\r
+ MOV BX, [BP].DL_Ypos1 ; get Y1 value\r
+ MOV CX, [BP].DL_Xpos2 ; get X2 value\r
+ MOV DX, [BP].DL_Ypos2 ; get Y2 value\r
+ \r
+ MOV BP, SCREEN_WIDTH ; Use BP for Line width to\r
+ ; to avoid extra memory access\r
+ \r
+ SUB DX, BX ; figure Delta_Y\r
+ JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1\r
+ \r
+ ADD BX, DX ; put Y2 into Y1\r
+ NEG DX ; abs(Delta_Y)\r
+ XCHG AX, CX ; and exchange X1 and X2\r
+ \r
+@DL_DeltaYOK2:\r
+ MOV BX, 08000H ; seed for fraction accumulator\r
+ \r
+ SUB CX, AX ; figure Delta_X\r
+ JC @DL_DrawLeft ; if negative, go left\r
+ \r
+ JMP @DL_DrawRight ; Draw Line that slopes right\r
+ \r
+@DL_DrawLeft:\r
+ \r
+ NEG CX ; abs(Delta_X)\r
+ \r
+ CMP CX, DX ; is Delta_X < Delta_Y?\r
+ JB @DL_SteepLeft ; yes, so go do steep line\r
+ ; (Delta_Y iterations)\r
+ \r
+ ; Draw a Shallow line to the left in Mode X\r
+ \r
+@DL_ShallowLeft:\r
+ CLR AX ; zero low word of Delta_Y * 10000h\r
+ SUB AX, DX ; DX:AX <- DX * 0FFFFh\r
+ SBB DX, 0 ; include carry\r
+ DIV CX ; divide by Delta_X\r
+ \r
+ MOV SI, BX ; SI = Accumulator\r
+ MOV BX, AX ; BX = Add fraction\r
+ POP AX ; Get Color, Bit mask\r
+ MOV DX, SC_Data ; Sequence controller data register\r
+ INC CX ; Inc Delta_X so we can unroll loop\r
+ \r
+ ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...\r
+ \r
+@DL_SLLLoop:\r
+ MOV ES:[DI], AH ; set first pixel, plane data set up\r
+ LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @DL_SLLL2nc ; move down on carry\r
+ \r
+ ADD DI, BP ; Move Down one line...\r
+ \r
+@DL_SLLL2nc:\r
+ DEC DI ; Left one addr\r
+ ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
+ CMP AL, 87h ; wrap?, if AL <88 then Carry set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+ MOV ES:[DI], AH ; set pixel\r
+ LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator,\r
+ JNC @DL_SLLL3nc ; move down on carry\r
+ \r
+ ADD DI, BP ; Move Down one line...\r
+ \r
+@DL_SLLL3nc: ; Now move left a pixel...\r
+ DEC DI ; Left one addr\r
+ ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
+ CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ JMP s @DL_SLLLoop ; loop until done\r
+ \r
+@DL_SLLExit:\r
+ JMP @DL_EXIT2 ; and exit\r
+ \r
+ ; Draw a steep line to the left in Mode X\r
+ \r
+@DL_SteepLeft:\r
+ CLR AX ; zero low word of Delta_Y * 10000h\r
+ XCHG DX, CX ; Delta_Y switched with Delta_X\r
+ DIV CX ; divide by Delta_Y\r
+ \r
+ MOV SI, BX ; SI = Accumulator\r
+ MOV BX, AX ; BX = Add Fraction\r
+ POP AX ; Get Color, Bit mask\r
+ MOV DX, SC_Data ; Sequence controller data register\r
+ INC CX ; Inc Delta_Y so we can unroll loop\r
+ \r
+ ; Loop (x2) to Draw Pixels, Move Down, and Maybe left\r
+ \r
+@DL_STLLoop:\r
+ \r
+ MOV ES:[DI], AH ; set first pixel\r
+ LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @DL_STLnc2 ; No carry, just move down!\r
+ \r
+ DEC DI ; Move Left one addr\r
+ ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
+ CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+@DL_STLnc2:\r
+ ADD DI, BP ; advance to next line.\r
+ \r
+ MOV ES:[DI], AH ; set pixel\r
+ LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @DL_STLnc3 ; No carry, just move down!\r
+ \r
+ DEC DI ; Move Left one addr\r
+ ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
+ CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+@DL_STLnc3:\r
+ ADD DI, BP ; advance to next line.\r
+ JMP s @DL_STLLoop ; Loop until done\r
+ \r
+@DL_STLExit:\r
+ JMP @DL_EXIT2 ; and exit\r
+ \r
+ ; Draw a line that goes to the Right...\r
+ \r
+@DL_DrawRight:\r
+ CMP CX, DX ; is Delta_X < Delta_Y?\r
+ JB @DL_SteepRight ; yes, so go do steep line\r
+ ; (Delta_Y iterations)\r
+ \r
+ ; Draw a Shallow line to the Right in Mode X\r
+ \r
+@DL_ShallowRight:\r
+ CLR AX ; zero low word of Delta_Y * 10000h\r
+ SUB AX, DX ; DX:AX <- DX * 0FFFFh\r
+ SBB DX, 0 ; include carry\r
+ DIV CX ; divide by Delta_X\r
+ \r
+ MOV SI, BX ; SI = Accumulator\r
+ MOV BX, AX ; BX = Add Fraction\r
+ POP AX ; Get Color, Bit mask\r
+ MOV DX, SC_Data ; Sequence controller data register\r
+ INC CX ; Inc Delta_X so we can unroll loop\r
+ \r
+ ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...\r
+ \r
+@DL_SLRLoop:\r
+ MOV ES:[DI], AH ; set first pixel, mask is set up\r
+ LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @DL_SLR2nc ; don't move down if carry not set\r
+ \r
+ ADD DI, BP ; Move Down one line...\r
+ \r
+@DL_SLR2nc: ; Now move right a pixel...\r
+ ROL AL, 1 ; Move Right one addr if Plane = 0\r
+ CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+ MOV ES:[DI], AH ; set pixel\r
+ LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @DL_SLR3nc ; don't move down if carry not set\r
+ \r
+ ADD DI, BP ; Move Down one line...\r
+ \r
+@DL_SLR3nc:\r
+ ROL AL, 1 ; Move Right one addr if Plane = 0\r
+ CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ JMP s @DL_SLRLoop ; loop till done\r
+ \r
+@DL_SLRExit:\r
+ JMP @DL_EXIT2 ; and exit\r
+ \r
+ ; Draw a Steep line to the Right in Mode X\r
+ \r
+@DL_SteepRight:\r
+ CLR AX ; zero low word of Delta_Y * 10000h\r
+ XCHG DX, CX ; Delta_Y switched with Delta_X\r
+ DIV CX ; divide by Delta_Y\r
+ \r
+ MOV SI, BX ; SI = Accumulator\r
+ MOV BX, AX ; BX = Add Fraction\r
+ POP AX ; Get Color, Bit mask\r
+ MOV DX, SC_Data ; Sequence controller data register\r
+ INC CX ; Inc Delta_Y so we can unroll loop\r
+ \r
+ ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right\r
+ \r
+@STRLoop:\r
+ MOV ES:[DI], AH ; set first pixel, mask is set up\r
+ LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @STRnc2 ; if no carry then just go down...\r
+ \r
+ ROL AL, 1 ; Move Right one addr if Plane = 0\r
+ CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+@STRnc2:\r
+ ADD DI, BP ; advance to next line.\r
+ \r
+ MOV ES:[DI], AH ; set pixel\r
+ LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done\r
+ \r
+ ADD SI, BX ; add numerator to accumulator\r
+ JNC @STRnc3 ; if no carry then just go down...\r
+ \r
+ ROL AL, 1 ; Move Right one addr if Plane = 0\r
+ CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
+ ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
+ OUT DX, AL ; Set up New Bit Plane mask\r
+ \r
+@STRnc3:\r
+ ADD DI, BP ; advance to next line.\r
+ JMP s @STRLoop ; loop till done\r
+ \r
+@DL_EXIT2:\r
+ POPx DI, SI, BP ; Restore Saved Registers\r
+ RET 10 ; Exit and Clean up Stack\r
+ \r
+DRAW_LINE ENDP\r
+ \r
+ \r
+ ; ===== DAC COLOR REGISTER ROUTINES =====\r
+ \r
+;=================================================\r
+;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)\r
+;=================================================\r
+;\r
+; Sets a single (RGB) Vga Palette Register\r
+;\r
+; ENTRY: Register = The DAC # to modify (0-255)\r
+; Red = The new Red Intensity (0-63)\r
+; Green = The new Green Intensity (0-63)\r
+; Blue = The new Blue Intensity (0-63)\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SDR_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ SDR_Blue DB ?,? ; Blue Data Value\r
+ SDR_Green DB ?,? ; Green Data Value\r
+ SDR_Red DB ?,? ; Red Data Value\r
+ SDR_Register DB ?,? ; Palette Register #\r
+SDR_STACK ENDS\r
+ \r
+ PUBLIC SET_DAC_REGISTER\r
+ \r
+SET_DAC_REGISTER PROC FAR\r
+ \r
+ PUSH BP ; Save BP\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ ; Select which DAC Register to modify\r
+ \r
+ OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register\r
+ \r
+ MOV DX, PEL_DATA_REG ; Dac Data Register\r
+ OUT_8 DX, [BP].SDR_Red ; Set Red Intensity\r
+ OUT_8 DX, [BP].SDR_Green ; Set Green Intensity\r
+ OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity\r
+ \r
+ POP BP ; Restore Registers\r
+ RET 8 ; Exit & Clean Up Stack\r
+ \r
+SET_DAC_REGISTER ENDP\r
+ \r
+;====================================================\r
+;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)\r
+;====================================================\r
+;\r
+; Reads the RGB Values of a single Vga Palette Register\r
+;\r
+; ENTRY: Register = The DAC # to read (0-255)\r
+; Red = Offset to Red Variable in DS\r
+; Green = Offset to Green Variable in DS\r
+; Blue = Offset to Blue Variable in DS\r
+;\r
+; EXIT: The values of the integer variables Red,\r
+; Green, and Blue are set to the values\r
+; taken from the specified DAC register.\r
+;\r
+ \r
+GDR_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ GDR_Blue DW ? ; Addr of Blue Data Value in DS\r
+ GDR_Green DW ? ; Addr of Green Data Value in DS\r
+ GDR_Red DW ? ; Addr of Red Data Value in DS\r
+ GDR_Register DB ?,? ; Palette Register #\r
+GDR_STACK ENDS\r
+ \r
+ PUBLIC GET_DAC_REGISTER\r
+ \r
+GET_DAC_REGISTER PROC FAR\r
+ \r
+ PUSH BP ; Save BP\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ ; Select which DAC Register to read in\r
+ \r
+ OUT_8 DAC_READ_ADDR, [BP].GDR_Register\r
+ \r
+ MOV DX, PEL_DATA_REG ; Dac Data Register\r
+ CLR AX ; Clear AX\r
+ \r
+ IN AL, DX ; Read Red Value\r
+ MOV BX, [BP].GDR_Red ; Get Address of Red%\r
+ MOV [BX], AX ; *Red% = AX\r
+ \r
+ IN AL, DX ; Read Green Value\r
+ MOV BX, [BP].GDR_Green ; Get Address of Green%\r
+ MOV [BX], AX ; *Green% = AX\r
+ \r
+ IN AL, DX ; Read Blue Value\r
+ MOV BX, [BP].GDR_Blue ; Get Address of Blue%\r
+ MOV [BX], AX ; *Blue% = AX\r
+ \r
+ POP BP ; Restore Registers\r
+ RET 8 ; Exit & Clean Up Stack\r
+ \r
+GET_DAC_REGISTER ENDP\r
+ \r
+ \r
+;===========================================================\r
+;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)\r
+;===========================================================\r
+;\r
+; Sets a Block of Vga Palette Registers\r
+;\r
+; ENTRY: PalData = Far Pointer to Block of palette data\r
+; StartReg = First Register # in range to set (0-255)\r
+; EndReg = Last Register # in Range to set (0-255)\r
+; Sync = Wait for Vertical Retrace Flag (Boolean)\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+; NOTES: PalData is a linear array of 3 byte Palette values\r
+; in the order: Red (0-63), Green (0-63), Blue (0-63)\r
+;\r
+ \r
+LDR_STACK STRUC\r
+ DW ?x3 ; BP, DS, SI\r
+ DD ? ; Caller\r
+ LDR_Sync DW ? ; Vertical Sync Flag\r
+ LDR_EndReg DB ?,? ; Last Register #\r
+ LDR_StartReg DB ?,? ; First Register #\r
+ LDR_PalData DD ? ; Far Ptr to Palette Data\r
+LDR_STACK ENDS\r
+ \r
+ PUBLIC LOAD_DAC_REGISTERS\r
+ \r
+LOAD_DAC_REGISTERS PROC FAR\r
+ \r
+ PUSHx BP, DS, SI ; Save Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+ \r
+ mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag\r
+ or AX, AX ; is Sync Flag = 0?\r
+ jz @LDR_Load ; if so, skip call\r
+ \r
+ call f SYNC_DISPLAY ; wait for vsync\r
+ \r
+ ; Determine register #'s, size to copy, etc\r
+ \r
+@LDR_Load:\r
+ \r
+ lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data\r
+ mov DX, DAC_WRITE_ADDR ; DAC register # selector\r
+ \r
+ CLR AX, BX ; Clear for byte loads\r
+ mov AL, [BP].LDR_StartReg ; Get Start Register\r
+ mov BL, [BP].LDR_EndReg ; Get End Register\r
+ \r
+ sub BX, AX ; BX = # of DAC registers -1\r
+ inc BX ; BX = # of DAC registers\r
+ mov CX, BX ; CX = # of DAC registers\r
+ add CX, BX ; CX = " " * 2\r
+ add CX, BX ; CX = " " * 3\r
+ cld ; Block OUTs forward\r
+ out DX, AL ; set up correct register #\r
+ \r
+ ; Load a block of DAC Registers\r
+ \r
+ mov DX, PEL_DATA_REG ; Dac Data Register\r
+ \r
+ rep outsb ; block set DAC registers\r
+ \r
+ POPx SI, DS, BP ; Restore Registers\r
+ ret 10 ; Exit & Clean Up Stack\r
+ \r
+LOAD_DAC_REGISTERS ENDP\r
+ \r
+ \r
+;====================================================\r
+;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)\r
+;====================================================\r
+;\r
+; Reads a Block of Vga Palette Registers\r
+;\r
+; ENTRY: PalData = Far Pointer to block to store palette data\r
+; StartReg = First Register # in range to read (0-255)\r
+; EndReg = Last Register # in Range to read (0-255)\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+; NOTES: PalData is a linear array of 3 byte Palette values\r
+; in the order: Red (0-63), Green (0-63), Blue (0-63)\r
+;\r
+ \r
+RDR_STACK STRUC\r
+ DW ?x3 ; BP, ES, DI\r
+ DD ? ; Caller\r
+ RDR_EndReg DB ?,? ; Last Register #\r
+ RDR_StartReg DB ?,? ; First Register #\r
+ RDR_PalData DD ? ; Far Ptr to Palette Data\r
+RDR_STACK ENDS\r
+ \r
+ PUBLIC READ_DAC_REGISTERS\r
+ \r
+READ_DAC_REGISTERS PROC FAR\r
+ \r
+ PUSHx BP, ES, DI ; Save Registers\r
+ mov BP, SP ; Set up Stack Frame\r
+ \r
+ ; Determine register #'s, size to copy, etc\r
+ \r
+ les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer\r
+ mov DX, DAC_READ_ADDR ; DAC register # selector\r
+ \r
+ CLR AX, BX ; Clear for byte loads\r
+ mov AL, [BP].RDR_StartReg ; Get Start Register\r
+ mov BL, [BP].RDR_EndReg ; Get End Register\r
+ \r
+ sub BX, AX ; BX = # of DAC registers -1\r
+ inc BX ; BX = # of DAC registers\r
+ mov CX, BX ; CX = # of DAC registers\r
+ add CX, BX ; CX = " " * 2\r
+ add CX, BX ; CX = " " * 3\r
+ cld ; Block INs forward\r
+ \r
+ ; Read a block of DAC Registers\r
+ \r
+ out DX, AL ; set up correct register #\r
+ mov DX, PEL_DATA_REG ; Dac Data Register\r
+ \r
+ rep insb ; block read DAC registers\r
+ \r
+ POPx DI, ES, BP ; Restore Registers\r
+ ret 8 ; Exit & Clean Up Stack\r
+ \r
+READ_DAC_REGISTERS ENDP\r
+ \r
+ \r
+ ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====\r
+ \r
+;=========================\r
+;SET_ACTIVE_PAGE (PageNo%)\r
+;=========================\r
+;\r
+; Sets the active display Page to be used for future drawing\r
+;\r
+; ENTRY: PageNo = Display Page to make active\r
+; (values: 0 to Number of Pages - 1)\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SAP_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ SAP_Page DW ? ; Page # for Drawing\r
+SAP_STACK ENDS\r
+ \r
+ PUBLIC SET_ACTIVE_PAGE\r
+ \r
+SET_ACTIVE_PAGE PROC FAR\r
+ \r
+ PUSH BP ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ MOV BX, [BP].SAP_Page ; Get Desired Page #\r
+ CMP BX, LAST_PAGE ; Is Page # Valid?\r
+ JAE @SAP_Exit ; IF Not, Do Nothing\r
+ \r
+ MOV ACTIVE_PAGE, BX ; Set Active Page #\r
+ \r
+ SHL BX, 1 ; Scale Page # to Word\r
+ MOV AX, PAGE_ADDR[BX] ; Get offset to Page\r
+ \r
+ MOV CURRENT_PAGE, AX ; And set for future LES's\r
+ \r
+@SAP_Exit:\r
+ POP BP ; Restore Registers\r
+ RET 2 ; Exit and Clean up Stack\r
+ \r
+SET_ACTIVE_PAGE ENDP\r
+ \r
+ \r
+;================\r
+;GET_ACTIVE_PAGE%\r
+;================\r
+;\r
+; Returns the Video Page # currently used for Drawing\r
+;\r
+; ENTRY: No Parameters are passed\r
+;\r
+; EXIT: AX = Current Video Page used for Drawing\r
+;\r
+ \r
+ PUBLIC GET_ACTIVE_PAGE\r
+ \r
+GET_ACTIVE_PAGE PROC FAR\r
+ \r
+ MOV AX, ACTIVE_PAGE ; Get Active Page #\r
+ RET ; Exit and Clean up Stack\r
+ \r
+GET_ACTIVE_PAGE ENDP\r
+ \r
+ \r
+;===============================\r
+;SET_DISPLAY_PAGE (DisplayPage%)\r
+;===============================\r
+;\r
+; Sets the currently visible display page.\r
+; When called this routine syncronizes the display\r
+; to the vertical blank.\r
+;\r
+; ENTRY: PageNo = Display Page to show on the screen\r
+; (values: 0 to Number of Pages - 1)\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SDP_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ SDP_Page DW ? ; Page # to Display...\r
+SDP_STACK ENDS\r
+ \r
+ PUBLIC SET_DISPLAY_PAGE\r
+ \r
+SET_DISPLAY_PAGE PROC FAR\r
+ \r
+ PUSH BP ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ MOV BX, [BP].SDP_Page ; Get Desired Page #\r
+ CMP BX, LAST_PAGE ; Is Page # Valid?\r
+ JAE @SDP_Exit ; IF Not, Do Nothing\r
+ \r
+ MOV DISPLAY_PAGE, BX ; Set Display Page #\r
+ \r
+ SHL BX, 1 ; Scale Page # to Word\r
+ MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page\r
+ ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling\r
+ \r
+ ; Wait if we are currently in a Vertical Retrace\r
+ \r
+ MOV DX, INPUT_1 ; Input Status #1 Register\r
+ \r
+@DP_WAIT0:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; In Display mode yet?\r
+ JNZ @DP_WAIT0 ; If Not, wait for it\r
+ \r
+ ; Set the Start Display Address to the new page\r
+ \r
+ MOV DX, CRTC_Index ; We Change the VGA Sequencer\r
+ \r
+ MOV AL, START_DISP_LO ; Display Start Low Register\r
+ MOV AH, CL ; Low 8 Bits of Start Addr\r
+ OUT DX, AX ; Set Display Addr Low\r
+ \r
+ MOV AL, START_DISP_HI ; Display Start High Register\r
+ MOV AH, CH ; High 8 Bits of Start Addr\r
+ OUT DX, AX ; Set Display Addr High\r
+ \r
+ ; Wait for a Vertical Retrace to smooth out things\r
+ \r
+ MOV DX, INPUT_1 ; Input Status #1 Register\r
+ \r
+@DP_WAIT1:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
+ JZ @DP_WAIT1 ; If Not, wait for it\r
+ \r
+ ; Now Set Display Starting Address\r
+ \r
+ \r
+@SDP_Exit:\r
+ POP BP ; Restore Registers\r
+ RET 2 ; Exit and Clean up Stack\r
+ \r
+SET_DISPLAY_PAGE ENDP\r
+ \r
+ \r
+;=================\r
+;GET_DISPLAY_PAGE%\r
+;=================\r
+;\r
+; Returns the Video Page # currently displayed\r
+;\r
+; ENTRY: No Parameters are passed\r
+;\r
+; EXIT: AX = Current Video Page being displayed\r
+;\r
+ \r
+ PUBLIC GET_DISPLAY_PAGE\r
+ \r
+GET_DISPLAY_PAGE PROC FAR\r
+ \r
+ MOV AX, DISPLAY_PAGE ; Get Display Page #\r
+ RET ; Exit & Clean Up Stack\r
+ \r
+GET_DISPLAY_PAGE ENDP\r
+ \r
+ \r
+;=======================================\r
+;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)\r
+;=======================================\r
+;\r
+; Since a Logical Screen can be larger than the Physical\r
+; Screen, Scrolling is possible. This routine sets the\r
+; Upper Left Corner of the Screen to the specified Pixel.\r
+; Also Sets the Display page to simplify combined page\r
+; flipping and scrolling. When called this routine\r
+; syncronizes the display to the vertical blank.\r
+;\r
+; ENTRY: DisplayPage = Display Page to show on the screen\r
+; Xpos = # of pixels to shift screen right\r
+; Ypos = # of lines to shift screen down\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SW_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ SW_Ypos DW ? ; Y pos of UL Screen Corner\r
+ SW_Xpos DW ? ; X pos of UL Screen Corner\r
+ SW_Page DW ? ; (new) Display Page\r
+SW_STACK ENDS\r
+ \r
+ PUBLIC SET_WINDOW\r
+ \r
+SET_WINDOW PROC FAR\r
+ \r
+ PUSH BP ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ ; Check if our Scroll Offsets are Valid\r
+ \r
+ MOV BX, [BP].SW_Page ; Get Desired Page #\r
+ CMP BX, LAST_PAGE ; Is Page # Valid?\r
+ JAE @SW_Exit ; IF Not, Do Nothing\r
+ \r
+ MOV AX, [BP].SW_Ypos ; Get Desired Y Offset\r
+ CMP AX, MAX_YOFFSET ; Is it Within Limits?\r
+ JA @SW_Exit ; if not, exit\r
+ \r
+ MOV CX, [BP].SW_Xpos ; Get Desired X Offset\r
+ CMP CX, MAX_XOFFSET ; Is it Within Limits?\r
+ JA @SW_Exit ; if not, exit\r
+ \r
+ ; Compute proper Display start address to use\r
+ \r
+ MUL SCREEN_WIDTH ; AX = YOffset * Line Width\r
+ SHR CX, 2 ; CX / 4 = Bytes into Line\r
+ ADD AX, CX ; AX = Offset of Upper Left Pixel\r
+ \r
+ MOV CURRENT_MOFFSET, AX ; Save Offset Info\r
+ \r
+ MOV DISPLAY_PAGE, BX ; Set Current Page #\r
+ SHL BX, 1 ; Scale Page # to Word\r
+ ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page\r
+ MOV BX, AX ; BX = Desired Display Start\r
+ \r
+ MOV DX, INPUT_1 ; Input Status #1 Register\r
+ \r
+ ; Wait if we are currently in a Vertical Retrace\r
+ \r
+@SW_WAIT0:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; In Display mode yet?\r
+ JNZ @SW_WAIT0 ; If Not, wait for it\r
+ \r
+ ; Set the Start Display Address to the new window\r
+ \r
+ MOV DX, CRTC_Index ; We Change the VGA Sequencer\r
+ MOV AL, START_DISP_LO ; Display Start Low Register\r
+ MOV AH, BL ; Low 8 Bits of Start Addr\r
+ OUT DX, AX ; Set Display Addr Low\r
+ \r
+ MOV AL, START_DISP_HI ; Display Start High Register\r
+ MOV AH, BH ; High 8 Bits of Start Addr\r
+ OUT DX, AX ; Set Display Addr High\r
+ \r
+ ; Wait for a Vertical Retrace to smooth out things\r
+ \r
+ MOV DX, INPUT_1 ; Input Status #1 Register\r
+ \r
+@SW_WAIT1:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
+ JZ @SW_WAIT1 ; If Not, wait for it\r
+ \r
+ ; Now Set the Horizontal Pixel Pan values\r
+ \r
+ OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register\r
+ \r
+ MOV AX, [BP].SW_Xpos ; Get Desired X Offset\r
+ AND AL, 03 ; Get # of Pixels to Pan (0-3)\r
+ SHL AL, 1 ; Shift for 256 Color Mode\r
+ OUT DX, AL ; Fine tune the display!\r
+ \r
+@SW_Exit:\r
+ POP BP ; Restore Saved Registers\r
+ RET 6 ; Exit and Clean up Stack\r
+ \r
+SET_WINDOW ENDP\r
+ \r
+ \r
+;=============\r
+;GET_X_OFFSET%\r
+;=============\r
+;\r
+; Returns the X coordinate of the Pixel currently display\r
+; in the upper left corner of the display\r
+;\r
+; ENTRY: No Parameters are passed\r
+;\r
+; EXIT: AX = Current Horizontal Scroll Offset\r
+;\r
+ \r
+ PUBLIC GET_X_OFFSET\r
+ \r
+GET_X_OFFSET PROC FAR\r
+ \r
+ MOV AX, CURRENT_XOFFSET ; Get current horz offset\r
+ RET ; Exit & Clean Up Stack\r
+ \r
+GET_X_OFFSET ENDP\r
+ \r
+ \r
+;=============\r
+;GET_Y_OFFSET%\r
+;=============\r
+;\r
+; Returns the Y coordinate of the Pixel currently display\r
+; in the upper left corner of the display\r
+;\r
+; ENTRY: No Parameters are passed\r
+;\r
+; EXIT: AX = Current Vertical Scroll Offset\r
+;\r
+ \r
+ PUBLIC GET_Y_OFFSET\r
+ \r
+GET_Y_OFFSET PROC FAR\r
+ \r
+ MOV AX, CURRENT_YOFFSET ; Get current vertical offset\r
+ RET ; Exit & Clean Up Stack\r
+ \r
+GET_Y_OFFSET ENDP\r
+ \r
+ \r
+;============\r
+;SYNC_DISPLAY\r
+;============\r
+;\r
+; Pauses the computer until the next Vertical Retrace starts\r
+;\r
+; ENTRY: No Parameters are passed\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+ PUBLIC SYNC_DISPLAY\r
+ \r
+SYNC_DISPLAY PROC FAR\r
+ \r
+ MOV DX, INPUT_1 ; Input Status #1 Register\r
+ \r
+ ; Wait for any current retrace to end\r
+ \r
+@SD_WAIT0:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; In Display mode yet?\r
+ JNZ @SD_WAIT0 ; If Not, wait for it\r
+ \r
+ ; Wait for the start of the next vertical retrace\r
+ \r
+@SD_WAIT1:\r
+ IN AL, DX ; Get VGA status\r
+ AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
+ JZ @SD_WAIT1 ; If Not, wait for it\r
+ \r
+ RET ; Exit & Clean Up Stack\r
+ \r
+SYNC_DISPLAY ENDP\r
+ \r
+ \r
+ ; ===== TEXT DISPLAY ROUTINES =====\r
+ \r
+;==================================================\r
+;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)\r
+;==================================================\r
+;\r
+; Draws an ASCII Text Character using the currently selected\r
+; 8x8 font on the active display page. It would be a simple\r
+; exercise to make this routine process variable height fonts.\r
+;\r
+; ENTRY: CharNum = ASCII character # to draw\r
+; Xpos = X position to draw Character at\r
+; Ypos = Y position of to draw Character at\r
+; ColorF = Color to draw text character in\r
+; ColorB = Color to set background to\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+GPC_STACK STRUC\r
+ GPC_Width DW ? ; Screen Width-1\r
+ GPC_Lines DB ?,? ; Scan lines to Decode\r
+ GPC_T_SETS DW ? ; Saved Charset Segment\r
+ GPC_T_SETO DW ? ; Saved Charset Offset\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ GPC_ColorB DB ?,? ; Background Color\r
+ GPC_ColorF DB ?,? ; Text Color\r
+ GPC_Ypos DW ? ; Y Position to Print at\r
+ GPC_Xpos DW ? ; X position to Print at\r
+ GPC_Char DB ?,? ; Character to Print\r
+GPC_STACK ENDS\r
+ \r
+ PUBLIC GPRINTC\r
+ \r
+GPRINTC PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 8 ; Allocate WorkSpace on Stack\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AX, SCREEN_WIDTH ; Get Logical Line Width\r
+ MOV BX, AX ; BX = Screen Width\r
+ DEC BX ; = Screen Width-1\r
+ MOV [BP].GPC_Width, BX ; Save for later use\r
+ \r
+ MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width\r
+ ADD DI, AX ; DI -> Start of Line Ypos\r
+ \r
+ MOV AX, [BP].GPC_Xpos ; Get Xpos of Character\r
+ MOV CX, AX ; Save Copy of Xpos\r
+ SHR AX, 2 ; Bytes into Line = Xpos/4\r
+ ADD DI, AX ; DI -> (Xpos, Ypos)\r
+ \r
+ ;Get Source ADDR of Character Bit Map & Save\r
+ \r
+ MOV AL, [BP].GPC_Char ; Get Character #\r
+ TEST AL, 080h ; Is Hi Bit Set?\r
+ JZ @GPC_LowChar ; Nope, use low char set ptr\r
+ \r
+ AND AL, 07Fh ; Mask Out Hi Bit\r
+ MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset\r
+ MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment\r
+ JMP s @GPC_Set_Char ; Go Setup Character Ptr\r
+ \r
+@GPC_LowChar:\r
+ \r
+ MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset\r
+ MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment\r
+ \r
+@GPC_Set_Char:\r
+ MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack\r
+ \r
+ MOV AH, 0 ; Valid #'s are 0..127\r
+ SHL AX, 3 ; * 8 Bytes Per Bitmap\r
+ ADD BX, AX ; BX = Offset of Selected char\r
+ MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack\r
+ \r
+ AND CX, PLANE_BITS ; Get Plane #\r
+ MOV CH, ALL_PLANES ; Get Initial Plane mask\r
+ SHL CH, CL ; And shift into position\r
+ AND CH, ALL_PLANES ; And mask to lower nibble\r
+ \r
+ MOV AL, 04 ; 4-Plane # = # of initial\r
+ SUB AL, CL ; shifts to align bit mask\r
+ MOV CL, AL ; Shift Count for SHL\r
+ \r
+ ;Get segment of character map\r
+ \r
+ OUT_8 SC_Index, MAP_MASK ; Setup Plane selections\r
+ INC DX ; DX -> SC_Data\r
+ \r
+ MOV AL, 08 ; 8 Lines to Process\r
+ MOV [BP].GPC_Lines, AL ; Save on Stack\r
+ \r
+ MOV DS, [BP].GPC_T_SETS ; Point to character set\r
+ \r
+@GPC_DECODE_CHAR_BYTE:\r
+ \r
+ MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String\r
+ \r
+ MOV BH, [SI] ; Get Bit Map\r
+ INC SI ; Point to Next Line\r
+ MOV [BP].GPC_T_SETO, SI ; And save new Pointer...\r
+ \r
+ CLR AX ; Clear AX\r
+ \r
+ CLR BL ; Clear BL\r
+ ROL BX, CL ; BL holds left edge bits\r
+ MOV SI, BX ; Use as Table Index\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set\r
+ \r
+ MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@GPC_NO_LEFT1BITS:\r
+ XOR AL, CH ; Invert mask for Background\r
+ JZ @GPC_NO_LEFT0BITS ; Hey, no need for this\r
+ \r
+ MOV AH, [BP].GPC_ColorB ; Get background Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+ ;Now Do Middle/Last Band\r
+ \r
+@GPC_NO_LEFT0BITS:\r
+ INC DI ; Point to next Byte\r
+ ROL BX, 4 ; Shift 4 bits\r
+ \r
+ MOV SI, BX ; Make Lookup Pointer\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set\r
+ \r
+ MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@GPC_NO_MIDDLE1BITS:\r
+ XOR AL, ALL_PLANES ; Invert mask for Background\r
+ JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this\r
+ \r
+ MOV AH, [BP].GPC_ColorB ; Get background Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@GPC_NO_MIDDLE0BITS:\r
+ XOR CH, ALL_PLANES ; Invert Clip Mask\r
+ CMP CL, 4 ; Aligned by 4?\r
+ JZ @GPC_NEXT_LINE ; If so, Exit now..\r
+ \r
+ INC DI ; Point to next Byte\r
+ ROL BX, 4 ; Shift 4 bits\r
+ \r
+ MOV SI, BX ; Make Lookup Pointer\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set\r
+ \r
+ MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@GPC_NO_RIGHT1BITS:\r
+ \r
+ XOR AL, CH ; Invert mask for Background\r
+ JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this\r
+ \r
+ MOV AH, [BP].GPC_ColorB ; Get background Color\r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@GPC_NO_RIGHT0BITS:\r
+ DEC DI ; Adjust for Next Line Advance\r
+ \r
+@GPC_NEXT_LINE:\r
+ ADD DI, [BP].GPC_Width ; Point to Next Line\r
+ XOR CH, CHAR_BITS ; Flip the Clip mask back\r
+ \r
+ DEC [BP].GPC_Lines ; Count Down Lines\r
+ JZ @GPC_EXIT ; Ok... Done!\r
+ \r
+ JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!\r
+ \r
+@GPC_EXIT:\r
+ ADD SP, 08 ; Deallocate stack workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 10 ; Exit and Clean up Stack\r
+ \r
+GPRINTC ENDP\r
+ \r
+ \r
+;==========================================\r
+;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)\r
+;==========================================\r
+;\r
+; Transparently draws an ASCII Text Character using the\r
+; currently selected 8x8 font on the active display page.\r
+;\r
+; ENTRY: CharNum = ASCII character # to draw\r
+; Xpos = X position to draw Character at\r
+; Ypos = Y position of to draw Character at\r
+; ColorF = Color to draw text character in\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+TGP_STACK STRUC\r
+ TGP_Width DW ? ; Screen Width-1\r
+ TGP_Lines DB ?,? ; Scan lines to Decode\r
+ TGP_T_SETS DW ? ; Saved Charset Segment\r
+ TGP_T_SETO DW ? ; Saved Charset Offset\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ TGP_ColorF DB ?,? ; Text Color\r
+ TGP_Ypos DW ? ; Y Position to Print at\r
+ TGP_Xpos DW ? ; X position to Print at\r
+ TGP_Char DB ?,? ; Character to Print\r
+TGP_STACK ENDS\r
+ \r
+ PUBLIC TGPRINTC\r
+ \r
+TGPRINTC PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 8 ; Allocate WorkSpace on Stack\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ \r
+ MOV AX, SCREEN_WIDTH ; Get Logical Line Width\r
+ MOV BX, AX ; BX = Screen Width\r
+ DEC BX ; = Screen Width-1\r
+ MOV [BP].TGP_Width, BX ; Save for later use\r
+ \r
+ MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width\r
+ ADD DI, AX ; DI -> Start of Line Ypos\r
+ \r
+ MOV AX, [BP].TGP_Xpos ; Get Xpos of Character\r
+ MOV CX, AX ; Save Copy of Xpos\r
+ SHR AX, 2 ; Bytes into Line = Xpos/4\r
+ ADD DI, AX ; DI -> (Xpos, Ypos)\r
+ \r
+ ;Get Source ADDR of Character Bit Map & Save\r
+ \r
+ MOV AL, [BP].TGP_Char ; Get Character #\r
+ TEST AL, 080h ; Is Hi Bit Set?\r
+ JZ @TGP_LowChar ; Nope, use low char set ptr\r
+ \r
+ AND AL, 07Fh ; Mask Out Hi Bit\r
+ MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset\r
+ MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment\r
+ JMP s @TGP_Set_Char ; Go Setup Character Ptr\r
+ \r
+@TGP_LowChar:\r
+ \r
+ MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset\r
+ MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment\r
+ \r
+@TGP_Set_Char:\r
+ MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack\r
+ \r
+ MOV AH, 0 ; Valid #'s are 0..127\r
+ SHL AX, 3 ; * 8 Bytes Per Bitmap\r
+ ADD BX, AX ; BX = Offset of Selected char\r
+ MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack\r
+ \r
+ AND CX, PLANE_BITS ; Get Plane #\r
+ MOV CH, ALL_PLANES ; Get Initial Plane mask\r
+ SHL CH, CL ; And shift into position\r
+ AND CH, ALL_PLANES ; And mask to lower nibble\r
+ \r
+ MOV AL, 04 ; 4-Plane # = # of initial\r
+ SUB AL, CL ; shifts to align bit mask\r
+ MOV CL, AL ; Shift Count for SHL\r
+ \r
+ ;Get segment of character map\r
+ \r
+ OUT_8 SC_Index, MAP_MASK ; Setup Plane selections\r
+ INC DX ; DX -> SC_Data\r
+ \r
+ MOV AL, 08 ; 8 Lines to Process\r
+ MOV [BP].TGP_Lines, AL ; Save on Stack\r
+ \r
+ MOV DS, [BP].TGP_T_SETS ; Point to character set\r
+ \r
+@TGP_DECODE_CHAR_BYTE:\r
+ \r
+ MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String\r
+ \r
+ MOV BH, [SI] ; Get Bit Map\r
+ INC SI ; Point to Next Line\r
+ MOV [BP].TGP_T_SETO, SI ; And save new Pointer...\r
+ \r
+ MOV AH, [BP].TGP_ColorF ; Get Foreground Color\r
+ \r
+ CLR BL ; Clear BL\r
+ ROL BX, CL ; BL holds left edge bits\r
+ MOV SI, BX ; Use as Table Index\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set\r
+ \r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+ ;Now Do Middle/Last Band\r
+ \r
+@TGP_NO_LEFT1BITS:\r
+ \r
+ INC DI ; Point to next Byte\r
+ ROL BX, 4 ; Shift 4 bits\r
+ \r
+ MOV SI, BX ; Make Lookup Pointer\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set\r
+ \r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@TGP_NO_MIDDLE1BITS:\r
+ XOR CH, ALL_PLANES ; Invert Clip Mask\r
+ CMP CL, 4 ; Aligned by 4?\r
+ JZ @TGP_NEXT_LINE ; If so, Exit now..\r
+ \r
+ INC DI ; Point to next Byte\r
+ ROL BX, 4 ; Shift 4 bits\r
+ \r
+ MOV SI, BX ; Make Lookup Pointer\r
+ AND SI, CHAR_BITS ; Get Low Bits\r
+ MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
+ JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set\r
+ \r
+ OUT DX, AL ; Set up Screen Mask\r
+ MOV ES:[DI], AH ; Write Foreground color\r
+ \r
+@TGP_NO_RIGHT1BITS:\r
+ \r
+ DEC DI ; Adjust for Next Line Advance\r
+ \r
+@TGP_NEXT_LINE:\r
+ ADD DI, [BP].TGP_Width ; Point to Next Line\r
+ XOR CH, CHAR_BITS ; Flip the Clip mask back\r
+ \r
+ DEC [BP].TGP_Lines ; Count Down Lines\r
+ JZ @TGP_EXIT ; Ok... Done!\r
+ \r
+ JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!\r
+ \r
+@TGP_EXIT:\r
+ ADD SP, 08 ; Deallocate stack workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 8 ; Exit and Clean up Stack\r
+ \r
+TGPRINTC ENDP\r
+ \r
+ \r
+;===============================================================\r
+;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)\r
+;===============================================================\r
+;\r
+; Routine to quickly Print a null terminated ASCII string on the\r
+; active display page up to a maximum length.\r
+;\r
+; ENTRY: String = Far Pointer to ASCII string to print\r
+; MaxLen = # of characters to print if no null found\r
+; Xpos = X position to draw Text at\r
+; Ypos = Y position of to draw Text at\r
+; ColorF = Color to draw text in\r
+; ColorB = Color to set background to\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+PS_STACK STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ PS_ColorB DW ? ; Background Color\r
+ PS_ColorF DW ? ; Text Color\r
+ PS_Ypos DW ? ; Y Position to Print at\r
+ PS_Xpos DW ? ; X position to Print at\r
+ PS_Len DW ? ; Maximum Length of string to print\r
+ PS_Text DW ?,? ; Far Ptr to Text String\r
+PS_STACK ENDS\r
+ \r
+ PUBLIC PRINT_STR\r
+ \r
+PRINT_STR PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+@PS_Print_It:\r
+ \r
+ MOV CX, [BP].PS_Len ; Get Remaining text Length\r
+ JCXZ @PS_Exit ; Exit when out of text\r
+ \r
+ LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text\r
+ MOV AL, ES:[DI] ; AL = Text Character\r
+ AND AX, 00FFh ; Clear High Word\r
+ JZ @PS_Exit ; Exit if null character\r
+ \r
+ DEC [BP].PS_Len ; Remaining Text length--\r
+ INC [BP].PS_Text ; Point to Next text char\r
+ \r
+ ; Set up Call to GPRINTC\r
+ \r
+ PUSH AX ; Set Character Parameter\r
+ MOV BX, [BP].PS_Xpos ; Get Xpos\r
+ PUSH BX ; Set Xpos Parameter\r
+ ADD BX, 8 ; Advance 1 Char to Right\r
+ MOV [BP].PS_Xpos, BX ; Save for next time through\r
+ \r
+ MOV BX, [BP].PS_Ypos ; Get Ypos\r
+ PUSH BX ; Set Ypos Parameter\r
+ \r
+ MOV BX, [BP].PS_ColorF ; Get Text Color\r
+ PUSH BX ; Set ColorF Parameter\r
+ \r
+ MOV BX, [BP].PS_ColorB ; Get Background Color\r
+ PUSH BX ; Set ColorB Parameter\r
+ \r
+ CALL f GPRINTC ; Print Character!\r
+ JMP s @PS_Print_It ; Process next character\r
+ \r
+@PS_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 14 ; Exit and Clean up Stack\r
+ \r
+PRINT_STR ENDP\r
+ \r
+ \r
+;================================================================\r
+;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)\r
+;================================================================\r
+;\r
+; Routine to quickly transparently Print a null terminated ASCII\r
+; string on the active display page up to a maximum length.\r
+;\r
+; ENTRY: String = Far Pointer to ASCII string to print\r
+; MaxLen = # of characters to print if no null found\r
+; Xpos = X position to draw Text at\r
+; Ypos = Y position of to draw Text at\r
+; ColorF = Color to draw text in\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+TPS_STACK STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ TPS_ColorF DW ? ; Text Color\r
+ TPS_Ypos DW ? ; Y Position to Print at\r
+ TPS_Xpos DW ? ; X position to Print at\r
+ TPS_Len DW ? ; Maximum Length of string to print\r
+ TPS_Text DW ?,? ; Far Ptr to Text String\r
+TPS_STACK ENDS\r
+ \r
+ PUBLIC TPRINT_STR\r
+ \r
+TPRINT_STR PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+@TPS_Print_It:\r
+ \r
+ MOV CX, [BP].TPS_Len ; Get Remaining text Length\r
+ JCXZ @TPS_Exit ; Exit when out of text\r
+ \r
+ LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text\r
+ MOV AL, ES:[DI] ; AL = Text Character\r
+ AND AX, 00FFh ; Clear High Word\r
+ JZ @TPS_Exit ; Exit if null character\r
+ \r
+ DEC [BP].TPS_Len ; Remaining Text length--\r
+ INC [BP].TPS_Text ; Point to Next text char\r
+ \r
+ ; Set up Call to TGPRINTC\r
+ \r
+ PUSH AX ; Set Character Parameter\r
+ MOV BX, [BP].TPS_Xpos ; Get Xpos\r
+ PUSH BX ; Set Xpos Parameter\r
+ ADD BX, 8 ; Advance 1 Char to Right\r
+ MOV [BP].TPS_Xpos, BX ; Save for next time through\r
+ \r
+ MOV BX, [BP].TPS_Ypos ; Get Ypos\r
+ PUSH BX ; Set Ypos Parameter\r
+ \r
+ MOV BX, [BP].TPS_ColorF ; Get Text Color\r
+ PUSH BX ; Set ColorF Parameter\r
+ \r
+ CALL f TGPRINTC ; Print Character!\r
+ JMP s @TPS_Print_It ; Process next character\r
+ \r
+@TPS_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 12 ; Exit and Clean up Stack\r
+ \r
+TPRINT_STR ENDP\r
+ \r
+ \r
+;===========================================\r
+;SET_DISPLAY_FONT(SEG FontData, FontNumber%)\r
+;===========================================\r
+;\r
+; Allows the user to specify their own font data for\r
+; wither the lower or upper 128 characters.\r
+;\r
+; ENTRY: FontData = Far Pointer to Font Bitmaps\r
+; FontNumber = Which half of set this is\r
+; = 0, Lower 128 characters\r
+; = 1, Upper 128 characters\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+SDF_STACK STRUC\r
+ DW ? ; BP\r
+ DD ? ; Caller\r
+ SDF_Which DW ? ; Hi Table/Low Table Flag\r
+ SDF_Font DD ? ; Far Ptr to Font Table\r
+SDF_STACK ENDS\r
+ \r
+ PUBLIC SET_DISPLAY_FONT\r
+ \r
+SET_DISPLAY_FONT PROC FAR\r
+ \r
+ PUSH BP ; Preserve Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, [BP].SDF_Font ; Get Far Ptr to Font\r
+ \r
+ MOV SI, o CHARSET_LOW ; Assume Lower 128 chars\r
+ TEST [BP].SDF_Which, 1 ; Font #1 selected?\r
+ JZ @SDF_Set_Font ; If not, skip ahead\r
+ \r
+ MOV SI, o CHARSET_HI ; Ah, really it's 128-255\r
+ \r
+@SDF_Set_Font:\r
+ MOV [SI], DI ; Set Font Pointer Offset\r
+ MOV [SI+2], ES ; Set Font Pointer Segment\r
+ \r
+ POP BP ; Restore Registers\r
+ RET 6 ; We are Done.. Outa here\r
+ \r
+SET_DISPLAY_FONT ENDP\r
+ \r
+ \r
+ ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====\r
+ \r
+;======================================================\r
+;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)\r
+;======================================================\r
+;\r
+; Draws a variable sized Graphics Bitmap such as a\r
+; picture or an Icon on the current Display Page in\r
+; Mode X. The Bitmap is stored in a linear byte array\r
+; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)\r
+; This is the same linear manner as mode 13h graphics.\r
+;\r
+; ENTRY: Image = Far Pointer to Bitmap Data\r
+; Xpos = X position to Place Upper Left pixel at\r
+; Ypos = Y position to Place Upper Left pixel at\r
+; Width = Width of the Bitmap in Pixels\r
+; Height = Height of the Bitmap in Pixels\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+DB_STACK STRUC\r
+ DB_LineO DW ? ; Offset to Next Line\r
+ DB_PixCount DW ? ; (Minimum) # of Pixels/Line\r
+ DB_Start DW ? ; Addr of Upper Left Pixel\r
+ DB_PixSkew DW ? ; # of bytes to Adjust EOL\r
+ DB_SkewFlag DW ? ; Extra Pix on Plane Flag\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ DB_Height DW ? ; Height of Bitmap in Pixels\r
+ DB_Width DW ? ; Width of Bitmap in Pixels\r
+ DB_Ypos DW ? ; Y position to Draw Bitmap at\r
+ DB_Xpos DW ? ; X position to Draw Bitmap at\r
+ DB_Image DD ? ; Far Pointer to Graphics Bitmap\r
+DB_STACK ENDS\r
+ \r
+ PUBLIC DRAW_BITMAP\r
+ \r
+DRAW_BITMAP PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 10 ; Allocate workspace\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ CLD ; Direction Flag = Forward\r
+ \r
+ MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos\r
+ MUL SCREEN_WIDTH ; AX = Offset to Line Ypos\r
+ \r
+ MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos\r
+ MOV CL, BL ; Save Plane # in CL\r
+ SHR BX, 2 ; Xpos/4 = Offset Into Line\r
+ \r
+ ADD DI, AX ; ES:DI -> Start of Line\r
+ ADD DI, BX ; ES:DI -> Upper Left Pixel\r
+ MOV [BP].DB_Start, DI ; Save Starting Addr\r
+ \r
+ ; Compute line to line offset\r
+ \r
+ MOV BX, [BP].DB_Width ; Get Width of Image\r
+ MOV DX, BX ; Save Copy in DX\r
+ SHR BX, 2 ; /4 = width in bands\r
+ MOV AX, SCREEN_WIDTH ; Get Screen Width\r
+ SUB AX, BX ; - (Bitmap Width/4)\r
+ \r
+ MOV [BP].DB_LineO, AX ; Save Line Width offset\r
+ MOV [BP].DB_PixCount, BX ; Minimum # pix to copy\r
+ \r
+ AND DX, PLANE_BITS ; Get "partial band" size (0-3)\r
+ MOV [BP].DB_PixSkew, DX ; Also End of Line Skew\r
+ MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count\r
+ \r
+ AND CX, PLANE_BITS ; CL = Starting Plane #\r
+ MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select\r
+ SHL AH, CL ; Select correct Plane\r
+ OUT_16 SC_Index, AX ; Select Plane...\r
+ MOV BH, AH ; BH = Saved Plane Mask\r
+ MOV BL, 4 ; BL = Planes to Copy\r
+ \r
+@DB_COPY_PLANE:\r
+ \r
+ LDS SI, [BP].DB_Image ; DS:SI-> Source Image\r
+ MOV DX, [BP].DB_Height ; # of Lines to Copy\r
+ MOV DI, [BP].DB_Start ; ES:DI-> Dest pos\r
+ \r
+@DB_COPY_LINE:\r
+ MOV CX, [BP].DB_PixCount ; Min # to copy\r
+ \r
+ TEST CL, 0FCh ; 16+PixWide?\r
+ JZ @DB_COPY_REMAINDER ; Nope...\r
+ \r
+ ; Pixel Copy loop has been unrolled to x4\r
+ \r
+@DB_COPY_LOOP:\r
+ MOVSB ; Copy Bitmap Pixel\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ MOVSB ; Copy Bitmap Pixel\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ MOVSB ; Copy Bitmap Pixel\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ MOVSB ; Copy Bitmap Pixel\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ \r
+ SUB CL, 4 ; Pixels to Copy=-4\r
+ TEST CL, 0FCh ; 4+ Pixels Left?\r
+ JNZ @DB_COPY_LOOP ; if so, do another block\r
+ \r
+@DB_COPY_REMAINDER:\r
+ JCXZ @DB_NEXT_LINE ; Any Pixels left on line\r
+ \r
+@DB_COPY2:\r
+ MOVSB ; Copy Bitmap Pixel\r
+ ADD SI,3 ; Skip to Next Byte in same plane\r
+ LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done\r
+ \r
+@DB_NEXT_LINE:\r
+ \r
+ ; any Partial Pixels? (some planes only)\r
+ \r
+ OR CX, [BP].DB_SkewFlag ; Get Skew Count\r
+ JZ @DB_NEXT2 ; if no partial pixels\r
+ \r
+ MOVSB ; Copy Bitmap Pixel\r
+ DEC DI ; Back up to align\r
+ DEC SI ; Back up to align\r
+ \r
+@DB_NEXT2:\r
+ ADD SI, [BP].DB_PixSkew ; Adjust Skew\r
+ ADD DI, [BP].DB_LineO ; Set to Next Display Line\r
+ LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more\r
+ \r
+ ; Copy Next Plane....\r
+ \r
+ DEC BL ; Planes to Go--\r
+ JZ @DB_Exit ; Hey! We are done\r
+ \r
+ ROL BH, 1 ; Next Plane in line...\r
+ OUT_8 SC_Data, BH ; Select Plane\r
+ \r
+ CMP AL, 12h ; Carry Set if AL=11h\r
+ ADC [BP].DB_Start, 0 ; Screen Addr =+Carry\r
+ INC w [BP].DB_Image ; Start @ Next Byte\r
+ \r
+ SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew\r
+ ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1\r
+ \r
+ JMP s @DB_COPY_PLANE ; Go Copy the Next Plane\r
+ \r
+@DB_Exit:\r
+ ADD SP, 10 ; Deallocate workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 12 ; Exit and Clean up Stack\r
+ \r
+DRAW_BITMAP ENDP\r
+ \r
+ \r
+;=======================================================\r
+;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)\r
+;=======================================================\r
+;\r
+; Transparently Draws a variable sized Graphics Bitmap\r
+; such as a picture or an Icon on the current Display Page\r
+; in Mode X. Pixels with a value of 0 are not drawn,\r
+; leaving the previous "background" contents intact.\r
+;\r
+; The Bitmap format is the same as for the DRAW_BITMAP function.\r
+;\r
+; ENTRY: Image = Far Pointer to Bitmap Data\r
+; Xpos = X position to Place Upper Left pixel at\r
+; Ypos = Y position to Place Upper Left pixel at\r
+; Width = Width of the Bitmap in Pixels\r
+; Height = Height of the Bitmap in Pixels\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+TB_STACK STRUC\r
+ TB_LineO DW ? ; Offset to Next Line\r
+ TB_PixCount DW ? ; (Minimum) # of Pixels/Line\r
+ TB_Start DW ? ; Addr of Upper Left Pixel\r
+ TB_PixSkew DW ? ; # of bytes to Adjust EOL\r
+ TB_SkewFlag DW ? ; Extra Pix on Plane Flag\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ TB_Height DW ? ; Height of Bitmap in Pixels\r
+ TB_Width DW ? ; Width of Bitmap in Pixels\r
+ TB_Ypos DW ? ; Y position to Draw Bitmap at\r
+ TB_Xpos DW ? ; X position to Draw Bitmap at\r
+ TB_Image DD ? ; Far Pointer to Graphics Bitmap\r
+TB_STACK ENDS\r
+ \r
+ PUBLIC TDRAW_BITMAP\r
+ \r
+TDRAW_BITMAP PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 10 ; Allocate workspace\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
+ CLD ; Direction Flag = Forward\r
+ \r
+ MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos\r
+ MUL SCREEN_WIDTH ; AX = Offset to Line Ypos\r
+ \r
+ MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos\r
+ MOV CL, BL ; Save Plane # in CL\r
+ SHR BX, 2 ; Xpos/4 = Offset Into Line\r
+ \r
+ ADD DI, AX ; ES:DI -> Start of Line\r
+ ADD DI, BX ; ES:DI -> Upper Left Pixel\r
+ MOV [BP].TB_Start, DI ; Save Starting Addr\r
+ \r
+ ; Compute line to line offset\r
+ \r
+ MOV BX, [BP].TB_Width ; Get Width of Image\r
+ MOV DX, BX ; Save Copy in DX\r
+ SHR BX, 2 ; /4 = width in bands\r
+ MOV AX, SCREEN_WIDTH ; Get Screen Width\r
+ SUB AX, BX ; - (Bitmap Width/4)\r
+ \r
+ MOV [BP].TB_LineO, AX ; Save Line Width offset\r
+ MOV [BP].TB_PixCount, BX ; Minimum # pix to copy\r
+ \r
+ AND DX, PLANE_BITS ; Get "partial band" size (0-3)\r
+ MOV [BP].TB_PixSkew, DX ; Also End of Line Skew\r
+ MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count\r
+ \r
+ AND CX, PLANE_BITS ; CL = Starting Plane #\r
+ MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select\r
+ SHL AH, CL ; Select correct Plane\r
+ OUT_16 SC_Index, AX ; Select Plane...\r
+ MOV BH, AH ; BH = Saved Plane Mask\r
+ MOV BL, 4 ; BL = Planes to Copy\r
+ \r
+@TB_COPY_PLANE:\r
+ \r
+ LDS SI, [BP].TB_Image ; DS:SI-> Source Image\r
+ MOV DX, [BP].TB_Height ; # of Lines to Copy\r
+ MOV DI, [BP].TB_Start ; ES:DI-> Dest pos\r
+ \r
+ ; Here AH is set with the value to be considered\r
+ ; "Transparent". It can be changed!\r
+ \r
+ MOV AH, 0 ; Value to Detect 0\r
+ \r
+@TB_COPY_LINE:\r
+ MOV CX, [BP].TB_PixCount ; Min # to copy\r
+ \r
+ TEST CL, 0FCh ; 16+PixWide?\r
+ JZ @TB_COPY_REMAINDER ; Nope...\r
+ \r
+ ; Pixel Copy loop has been unrolled to x4\r
+ \r
+@TB_COPY_LOOP:\r
+ LODSB ; Get Pixel Value in AL\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_SKIP_01 ; Skip ahead if so\r
+ MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_SKIP_01:\r
+ LODSB ; Get Pixel Value in AL\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_SKIP_02 ; Skip ahead if so\r
+ MOV ES:[DI+1], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_SKIP_02:\r
+ LODSB ; Get Pixel Value in AL\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_SKIP_03 ; Skip ahead if so\r
+ MOV ES:[DI+2], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_SKIP_03:\r
+ LODSB ; Get Pixel Value in AL\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_SKIP_04 ; Skip ahead if so\r
+ MOV ES:[DI+3], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_SKIP_04:\r
+ ADD DI, 4 ; Adjust Pixel Write Location\r
+ SUB CL, 4 ; Pixels to Copy=-4\r
+ TEST CL, 0FCh ; 4+ Pixels Left?\r
+ JNZ @TB_COPY_LOOP ; if so, do another block\r
+ \r
+@TB_COPY_REMAINDER:\r
+ JCXZ @TB_NEXT_LINE ; Any Pixels left on line\r
+ \r
+@TB_COPY2:\r
+ LODSB ; Get Pixel Value in AL\r
+ ADD SI, 3 ; Skip to Next Byte in same plane\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_SKIP_05 ; Skip ahead if so\r
+ MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_SKIP_05:\r
+ INC DI ; Advance Dest Addr\r
+ LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done\r
+ \r
+@TB_NEXT_LINE:\r
+ \r
+ ; any Partial Pixels? (some planes only)\r
+ \r
+ OR CX, [BP].TB_SkewFlag ; Get Skew Count\r
+ JZ @TB_NEXT2 ; if no partial pixels\r
+ \r
+ LODSB ; Get Pixel Value in AL\r
+ DEC SI ; Backup to Align\r
+ CMP AL, AH ; It is "Transparent"?\r
+ JE @TB_NEXT2 ; Skip ahead if so\r
+ MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
+ \r
+@TB_NEXT2:\r
+ ADD SI, [BP].TB_PixSkew ; Adjust Skew\r
+ ADD DI, [BP].TB_LineO ; Set to Next Display Line\r
+ LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More\r
+ \r
+ ;Copy Next Plane....\r
+ \r
+ DEC BL ; Planes to Go--\r
+ JZ @TB_Exit ; Hey! We are done\r
+ \r
+ ROL BH, 1 ; Next Plane in line...\r
+ OUT_8 SC_Data, BH ; Select Plane\r
+ \r
+ CMP AL, 12h ; Carry Set if AL=11h\r
+ ADC [BP].TB_Start, 0 ; Screen Addr =+Carry\r
+ INC w [BP].TB_Image ; Start @ Next Byte\r
+ \r
+ SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew\r
+ ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1\r
+ \r
+ JMP @TB_COPY_PLANE ; Go Copy the next Plane\r
+ \r
+@TB_Exit:\r
+ ADD SP, 10 ; Deallocate workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 12 ; Exit and Clean up Stack\r
+ \r
+TDRAW_BITMAP ENDP\r
+ \r
+ \r
+ ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====\r
+ \r
+;==================================\r
+;COPY_PAGE (SourcePage%, DestPage%)\r
+;==================================\r
+;\r
+; Duplicate on display page onto another\r
+;\r
+; ENTRY: SourcePage = Display Page # to Duplicate\r
+; DestPage = Display Page # to hold copy\r
+;\r
+; EXIT: No meaningful values returned\r
+;\r
+ \r
+CP_STACK STRUC\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ CP_DestP DW ? ; Page to hold copied image\r
+ CP_SourceP DW ? ; Page to Make copy from\r
+CP_STACK ENDS\r
+ \r
+ PUBLIC COPY_PAGE\r
+ \r
+COPY_PAGE PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ MOV BP, SP ; Set up Stack Frame\r
+ CLD ; Block Xfer Forwards\r
+ \r
+ ; Make sure Page #'s are valid\r
+ \r
+ MOV AX, [BP].CP_SourceP ; Get Source Page #\r
+ CMP AX, LAST_PAGE ; is it > Max Page #?\r
+ JAE @CP_Exit ; if so, abort\r
+ \r
+ MOV BX, [BP].CP_DestP ; Get Destination Page #\r
+ CMP BX, LAST_PAGE ; is it > Max Page #?\r
+ JAE @CP_Exit ; if so, abort\r
+ \r
+ CMP AX, BX ; Pages #'s the same?\r
+ JE @CP_Exit ; if so, abort\r
+ \r
+ ; Setup DS:SI and ES:DI to Video Pages\r
+ \r
+ SHL BX, 1 ; Scale index to Word\r
+ MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page\r
+ \r
+ MOV BX, AX ; Index to Source page\r
+ SHL BX, 1 ; Scale index to Word\r
+ MOV SI, PAGE_ADDR[BX] ; Offset to Source Page\r
+ \r
+ MOV CX, PAGE_SIZE ; Get size of Page\r
+ MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment\r
+ MOV ES, AX ; ES:DI -> Dest Page\r
+ MOV DS, AX ; DS:SI -> Source Page\r
+ \r
+ ; Setup VGA registers for Mem to Mem copy\r
+ \r
+ OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on\r
+ OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes\r
+ \r
+ ; Note.. Do *NOT* use MOVSW or MOVSD - they will\r
+ ; Screw with the latches which are 8 bits x 4\r
+ \r
+ REP MOVSB ; Copy entire Page!\r
+ \r
+ ; Reset VGA for normal memory access\r
+ \r
+ OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off\r
+ \r
+@CP_Exit:\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 4 ; Exit and Clean up Stack\r
+ \r
+COPY_PAGE ENDP\r
+ \r
+ \r
+;==========================================================================\r
+;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)\r
+;==========================================================================\r
+;\r
+; Copies a Bitmap Image from one Display Page to Another\r
+; This Routine is Limited to copying Images with the same\r
+; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)\r
+; Copying an Image to the Same Page is supported, but results\r
+; may be defined when the when the rectangular areas\r
+; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -\r
+; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...\r
+; No Paramter checking to done to insure that\r
+; X2 >= X1 and Y2 >= Y1. Be Careful...\r
+;\r
+; ENTRY: SourcePage = Display Page # with Source Image\r
+; X1 = Upper Left Xpos of Source Image\r
+; Y1 = Upper Left Ypos of Source Image\r
+; X2 = Lower Right Xpos of Source Image\r
+; Y2 = Lower Right Ypos of Source Image\r
+; DestPage = Display Page # to copy Image to\r
+; DestX1 = Xpos to Copy UL Corner of Image to\r
+; DestY1 = Ypos to Copy UL Corner of Image to\r
+;\r
+; EXIT: AX = Success Flag: 0 = Failure / -1= Success\r
+;\r
+ \r
+CB_STACK STRUC\r
+ CB_Height DW ? ; Height of Image in Lines\r
+ CB_Width DW ? ; Width of Image in "bands"\r
+ DW ?x4 ; DI, SI, DS, BP\r
+ DD ? ; Caller\r
+ CB_DestY1 DW ? ; Destination Ypos\r
+ CB_DestX1 DW ? ; Destination Xpos\r
+ CB_DestP DW ? ; Page to Copy Bitmap To\r
+ CB_Y2 DW ? ; LR Ypos of Image\r
+ CB_X2 DW ? ; LR Xpos of Image\r
+ CB_Y1 DW ? ; UL Ypos of Image\r
+ CB_X1 DW ? ; UL Xpos of Image\r
+ CB_SourceP DW ? ; Page containing Source Bitmap\r
+CB_STACK ENDS\r
+ \r
+ PUBLIC COPY_BITMAP\r
+ \r
+COPY_BITMAP PROC FAR\r
+ \r
+ PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
+ SUB SP, 4 ; Allocate WorkSpace on Stack\r
+ MOV BP, SP ; Set up Stack Frame\r
+ \r
+ ; Prep Registers (and keep jumps short!)\r
+ \r
+ MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram\r
+ CLD ; Block Xfer Forwards\r
+ \r
+ ; Make sure Parameters are valid\r
+ \r
+ MOV BX, [BP].CB_SourceP ; Get Source Page #\r
+ CMP BX, LAST_PAGE ; is it > Max Page #?\r
+ JAE @CB_Abort ; if so, abort\r
+ \r
+ MOV CX, [BP].CB_DestP ; Get Destination Page #\r
+ CMP CX, LAST_PAGE ; is it > Max Page #?\r
+ JAE @CB_Abort ; if so, abort\r
+ \r
+ MOV AX, [BP].CB_X1 ; Get Source X1\r
+ XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1\r
+ AND AX, PLANE_BITS ; Check Plane Bits\r
+ JNZ @CB_Abort ; They should cancel out\r
+ \r
+ ; Setup for Copy processing\r
+ \r
+ OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
+ OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on\r
+ \r
+ ; Compute Info About Images, Setup ES:SI & ES:DI\r
+ \r
+ MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines\r
+ SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1\r
+ INC AX ; (add 1 since were not 0 based)\r
+ MOV [BP].CB_Height, AX ; Save on Stack for later use\r
+ \r
+ MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels\r
+ MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1\r
+ SHR AX, 2 ; Get X2 Band (X2 / 4)\r
+ SHR DX, 2 ; Get X1 Band (X1 / 4)\r
+ SUB AX, DX ; AX = # of Bands - 1\r
+ INC AX ; AX = # of Bands\r
+ MOV [BP].CB_Width, AX ; Save on Stack for later use\r
+ \r
+ SHL BX, 1 ; Scale Source Page to Word\r
+ MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page\r
+ MOV AX, [BP].CB_Y1 ; Get Source Y1 Line\r
+ MUL SCREEN_WIDTH ; AX = Offset to Line Y1\r
+ ADD SI, AX ; SI = Offset to Line Y1\r
+ MOV AX, [BP].CB_X1 ; Get Source X1\r
+ SHR AX, 2 ; X1 / 4 = Byte offset\r
+ ADD SI, AX ; SI = Byte Offset to (X1,Y1)\r
+ \r
+ MOV BX, CX ; Dest Page Index to BX\r
+ SHL BX, 1 ; Scale Source Page to Word\r
+ MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page\r
+ MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line\r
+ MUL SCREEN_WIDTH ; AX = Offset to Line Y1\r
+ ADD DI, AX ; DI = Offset to Line Y1\r
+ MOV AX, [BP].CB_DestX1 ; Get Dest X1\r
+ SHR AX, 2 ; X1 / 4 = Byte offset\r
+ ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)\r
+ \r
+ MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)\r
+ DEC CX ; CX = 1?\r
+ JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band\r
+ \r
+ MOV BX, [BP].CB_X1 ; Get Source X1\r
+ AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)\r
+ JZ @CB_Check_Right ; if so, check right alignment\r
+ JNZ @CB_Left_Band ; not aligned? well..\r
+ \r
+@CB_Abort:\r
+ CLR AX ; Return False (Failure)\r
+ JMP @CB_Exit ; and Finish Up\r
+ \r
+ ; Copy when Left & Right Clip Masks overlap...\r
+ \r
+@CB_Only_One_Band:\r
+ MOV BX, [BP].CB_X1 ; Get Left Clip Mask\r
+ AND BX, PLANE_BITS ; Mask out Row #\r
+ MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask\r
+ MOV BX, [BP].CB_X2 ; Get Right Clip Mask\r
+ AND BX, PLANE_BITS ; Mask out Row #\r
+ AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte\r
+ \r
+ OUT_8 SC_Data, AL ; Clip For Left & Right Masks\r
+ \r
+ MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
+ MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
+ CLR BX ; BX = Offset into Image\r
+ \r
+@CB_One_Loop:\r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPjz CX, @CB_One_Done ; Exit Loop if Finished\r
+ \r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPx CX, @CB_One_Loop ; Loop until Finished\r
+ \r
+@CB_One_Done:\r
+ JMP @CB_Finish ; Outa Here!\r
+ \r
+ ; Copy Left Edge of Bitmap\r
+ \r
+@CB_Left_Band:\r
+ \r
+ OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask\r
+ \r
+ MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
+ MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
+ CLR BX ; BX = Offset into Image\r
+ \r
+@CB_Left_Loop:\r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished\r
+ \r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPx CX, @CB_Left_Loop ; Loop until Finished\r
+ \r
+@CB_Left_Done:\r
+ INC DI ; Move Dest Over 1 band\r
+ INC SI ; Move Source Over 1 band\r
+ DEC [BP].CB_Width ; Band Width--\r
+ \r
+ ; Determine if Right Edge of Bitmap needs special copy\r
+ \r
+@CB_Check_Right:\r
+ MOV BX, [BP].CB_X2 ; Get Source X2\r
+ AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)\r
+ CMP BL, 03h ; Plane = 3?\r
+ JE @CB_Copy_Middle ; Copy the Middle then!\r
+ \r
+ ; Copy Right Edge of Bitmap\r
+ \r
+@CB_Right_Band:\r
+ \r
+ OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask\r
+ \r
+ DEC [BP].CB_Width ; Band Width--\r
+ MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
+ MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
+ MOV BX, [BP].CB_Width ; BX = Offset to Right Edge\r
+ \r
+@CB_Right_Loop:\r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished\r
+ \r
+ MOV AL, ES:[SI+BX] ; Load Latches\r
+ MOV ES:[DI+BX], AL ; Unload Latches\r
+ ADD BX, DX ; Advance Offset to Next Line\r
+ LOOPx CX, @CB_Right_Loop ; Loop until Finished\r
+ \r
+@CB_Right_Done:\r
+ \r
+ ; Copy the Main Block of the Bitmap\r
+ \r
+@CB_Copy_Middle:\r
+ \r
+ MOV CX, [BP].CB_Width ; Get Width Remaining\r
+ JCXZ @CB_Finish ; Exit if Done\r
+ \r
+ OUT_8 SC_Data, ALL_PLANES ; Copy all Planes\r
+ \r
+ MOV DX, SCREEN_WIDTH ; Get Width of Screen minus\r
+ SUB DX, CX ; Image width (for Adjustment)\r
+ MOV AX, [BP].CB_Height ; AX = # of Lines to Copy\r
+ MOV BX, CX ; BX = Quick REP reload count\r
+ MOV CX, ES ; Move VGA Segment\r
+ MOV DS, CX ; Into DS\r
+ \r
+ ; Actual Copy Loop. REP MOVSB does the work\r
+ \r
+@CB_Middle_Copy:\r
+ MOV CX, BX ; Recharge Rep Count\r
+ REP MOVSB ; Move Bands\r
+ LOOPjz AX, @CB_Finish ; Exit Loop if Finished\r
+ \r
+ ADD SI, DX ; Adjust DS:SI to Next Line\r
+ ADD DI, DX ; Adjust ES:DI to Next Line\r
+ \r
+ MOV CX, BX ; Recharge Rep Count\r
+ REP MOVSB ; Move Bands\r
+ \r
+ ADD SI, DX ; Adjust DS:SI to Next Line\r
+ ADD DI, DX ; Adjust ES:DI to Next Line\r
+ LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done\r
+ \r
+@CB_Finish:\r
+ OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on\r
+ \r
+@CB_Exit:\r
+ ADD SP, 04 ; Deallocate stack workspace\r
+ POPx DI, SI, DS, BP ; Restore Saved Registers\r
+ RET 16 ; Exit and Clean up Stack\r
+ \r
+COPY_BITMAP ENDP\r
+ \r
+ END ; End of Code Segment\r
--- /dev/null
+ \r
+ ' ===== SCREEN RESOLUTIONS =====\r
+ \r
+CONST Mode320x200 = 0, Mode320x400 = 1\r
+CONST Mode360x200 = 2, Mode360x400 = 3\r
+CONST Mode320x240 = 4, Mode320x480 = 5\r
+CONST Mode360x240 = 6, Mode360x480 = 7\r
+ \r
+ ' ===== MODE X SETUP ROUTINES =====\r
+ \r
+DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%)\r
+DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%)\r
+ \r
+ ' ===== BASIC GRAPHICS PRIMITIVES =====\r
+ \r
+DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%)\r
+DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%)\r
+DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%)\r
+DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%)\r
+ \r
+ ' ===== DAC COLOR REGISTER ROUTINES =====\r
+ \r
+DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%)\r
+DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%)\r
+DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%)\r
+DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%)\r
+ \r
+ \r
+ ' ===== PAGE FLIPPING AND SCROLLING ROUTINES =====\r
+ \r
+DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE"\r
+DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%)\r
+DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE"\r
+DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%)\r
+DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" ()\r
+DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" ()\r
+DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY"\r
+ \r
+ ' ===== TEXT DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%)\r
+DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%)\r
+DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%)\r
+ \r
+ ' ===== BITMAP (SPRITE) DISPLAY ROUTINES =====\r
+ \r
+DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%)\r
+ \r
+ ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====\r
+ \r
+DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%)\r
+DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%)\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
--- /dev/null
+ \r
+#ifndef __MODEX_H\r
+#define __MODEX_H\r
+ \r
+ /* ===== SCREEN RESOLUTIONS ===== */\r
+ \r
+#define Mode_320x200 0\r
+#define Mode_320x400 1\r
+#define Mode_360x200 2\r
+#define Mode_360x400 3\r
+#define Mode_320x240 4\r
+#define Mode_320x480 5\r
+#define Mode_360x240 6\r
+#define Mode_360x480 7\r
+ \r
+ /* ===== MODE X SETUP ROUTINES ===== */\r
+ \r
+int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages);\r
+int far pascal set_modex (int Mode);\r
+ \r
+ /* ===== BASIC GRAPHICS PRIMITIVES ===== */\r
+ \r
+void far pascal clear_vga_screen (int Color);\r
+void far pascal set_point (int Xpos, int Ypos, int Color);\r
+int far pascal read_point (int Xpos, int Ypos);\r
+void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2,\r
+ int Color);\r
+void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2,\r
+ int Color);\r
+ \r
+ /* ===== DAC COLOR REGISTER ROUTINES ===== */\r
+ \r
+void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue);\r
+void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue);\r
+void far pascal load_dac_registers (char far *PalData, int StartReg,\r
+ int EndReg, int VSync);\r
+void far pascal readd_dac_registers (char far *PalData, int StartReg,\r
+ int EndReg);\r
+ \r
+ /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */\r
+ \r
+void far pascal set_active_page (int PageNo);\r
+int far pascal get_active_page (void);\r
+void far pascal set_display_page (int PageNo);\r
+int far pascal get_display_page (void);\r
+void far pascal set_window (int DisplayPage, int XOffset, int YOffset);\r
+int far pascal get_x_offset (void);\r
+int far pascal get_y_offset (void);\r
+void far pascal sync_display (void);\r
+ \r
+ /* ===== TEXT DISPLAY ROUTINES ===== */\r
+ \r
+void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF,\r
+ int ColorB);\r
+void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF);\r
+void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos,\r
+ int ColorF, int ColorB);\r
+void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos,\r
+ int ColorF);\r
+void far pascal set_display_font (char far *FontData, int FontNumber);\r
+ \r
+ /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */\r
+ \r
+void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos,\r
+ int Width, int Height);\r
+void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos,\r
+ int Width, int Height);\r
+ \r
+ /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */\r
+ \r
+void far pascal copy_page (int SourcePage, int DestPage);\r
+void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2,\r
+ int DestPage, int DestX1, int DestY1);\r
+ \r
+ \r
+#endif\r
--- /dev/null
+\r
+PACKING LIST FOR MODEX104\r
+\r
+DIRECTORY: \ - The Mode X Library versoon 1.04 \r
+\r
+ASM BAT 26 05-14-93 6:00p - Batch File to Assemble MODEX.ASM\r
+MODE-X TXT 2135 05-14-93 6:00p - File Describing MODE X Routines\r
+MODEX ASM 117039 05-14-93 6:00p - Assembly source to Mode X Library\r
+MODEX BI 3238 05-14-93 6:00p - Include File for BASIC/PDS\r
+MODEX H 2943 05-14-93 6:00p - Include File for C/C++\r
+MODEX OBJ 5208 05-14-93 6:00p - The Mode X Library\r
+README DOC 3259 05-14-93 6:00p - Information on this Product\r
+PACKING LST 4767 05-14-93 6:00p - This File\r
+\r
+DIRECTORY: \DEMOS - Mode X Demos\r
+\r
+CHARDEMO EXE 13066 05-14-93 6:00p - Demo of Multiple Fonts & Color Cycling\r
+TEST6 EXE 19990 05-14-93 6:00p - Main Mode X Demo\r
+ROM_8X8 FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE\r
+SPACEAGE FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE\r
+SYSTEM FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE\r
+\r
+DIRECTORY: \DEMOS\BASIC7 - Demo Sources for Microsoft BASIC 7.1 (PDS)\r
+\r
+MAKE-LIB BAT 166 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB\r
+MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library\r
+MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QBX\r
+MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File\r
+MODEX QLB 11141 05-14-93 6:00p - Mode X & Utility Quick Library\r
+TEST6 BAS 12733 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE)\r
+UASM-BC7 BAT 43 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QBX\r
+UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source\r
+UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes\r
+UTILS OBJ 681 05-14-93 6:00p - Basic Utilities - Object File\r
+CHARDEMO BAS 3431 05-14-93 6:00p - Source to CHARDEMO.EXE\r
+\r
+DIRECTORY: \DEMOS\C - Demo Sources for Borland C/C++\r
+\r
+C_UTILS ASM 8782 05-14-93 6:00p - C Utilities - Assembler source\r
+C_UTILS H 2623 05-14-93 6:00p - C Utilities - C Includes\r
+C_UTILS OBJ 648 05-14-93 6:00p - C Utilities - Object File\r
+MODEX H 2943 05-14-93 6:00p - Mode X Library C Incldues\r
+MODEX OBJ 5208 05-14-93 6:00p - Mode X Library\r
+UTLS-ASM BAT 36 05-14-93 6:00p - Batch File to Make C_UTILS.OBJ\r
+X-DEMO C 15085 05-14-93 6:00p - Source to Main Demo (TEST6) in C\r
+X-DEMO EXE 41090 05-14-93 6:00p - C Version of Main Demo\r
+X-DEMO PRJ 5188 05-14-93 6:00p - Borland C Project file\r
+\r
+DIRECTORY: \DEMOS\PASCAL - Demo Sources for Turbo Pascal\r
+\r
+TEST5 PAS 15873 05-14-93 6:00p - Source for a TP Version of TEST6.EXE\r
+\r
+DIRECTORY: \DEMOS\QB45 - Demo Sources for Microsoft QuickBASIC 4.5\r
+\r
+MAKE-LIB BAT 164 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB\r
+MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library\r
+MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QB45\r
+MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File\r
+MODEX QLB 9739 05-14-93 6:00p - Mode X & Utility Quick Library/QB45\r
+TEST6A BAS 12743 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE)\r
+TEST6A EXE 40544 05-14-93 6:00p - QB45 Version of Main Demo\r
+UASM-QB4 BAT 30 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QB45\r
+UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source\r
+UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes\r
+UTILS OBJ 628 05-14-93 6:00p - Basic Utilities - Object File\r
+\r
+DIRECTORY: \FONTEDIT - Font Editor\r
+\r
+CSEDIT EXE 39242 05-14-93 6:00p - Font Editor Program\r
+CSEDIT DOC 8629 05-14-93 6:00p - Font Editor Documentation\r
+CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor\r
+MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor\r
+PALETTE CS 768 05-14-93 6:00p - Palette for Editor\r
+INVERSE FNT 1024 05-14-93 6:00p - Sample Font\r
+ROM_8X8 FNT 1024 05-14-93 6:00p - Sample Font\r
+SPACEAGE FNT 1024 05-14-93 6:00p - Sample Font\r
+SYSTEM FNT 1024 05-14-93 6:00p - Sample Font\r
+\r
+DIRECTORY: \PALEDIT - Palette Editor\r
+\r
+PALEDIT EXE 31954 05-14-93 6:00p - Palette Editor Program\r
+PALEDIT DOC 6688 05-14-93 6:00p - Palette Editor Documentation\r
+CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor\r
+MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor\r
+GAMECOLR PAL 768 05-14-93 6:00p - Sample Palette\r
+PRIME PAL 768 05-14-93 6:00p - Sample Palette\r
+RGB PAL 768 05-14-93 6:00p - Sample Palette\r
--- /dev/null
+ \r
+PALEDIT - A Simple VGA 256 Color Palette Editor\r
+ \r
+ \r
+PALEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X\r
+Library for VGA Graphics.\r
+ \r
+WHAT YOU NEED TO RUN PALEDIT:\r
+ \r
+ * A Vga Monitor\r
+ * A Microsoft Compatible Mouse\r
+ \r
+ A Mouse is most definitely required, as the keyboard is used for\r
+ nothing except entering file names.\r
+ \r
+FILES NEEDED IN THE CURRENT DIRECTORY:\r
+ \r
+ PALEDIT.EXE - The Palette Editor Program\r
+ CHARSETS.CS - The Palette Editor's Internal Fonts\r
+ MOUSEIMG.CS - The Palette Editor's Mouse Pointer\r
+ \r
+SAMPLE PALETTE FILE THAT SHOULD BE INCLUDED:\r
+ \r
+ RGB.PAL - A Simple Palette with Reds, Greens, and Blues\r
+ PRIME.PAL - A Simple Palette\r
+ GAMECOLR.PAL - A Bright Palette from a Game of mine.\r
+ \r
+WHAT IT EDITS:\r
+ \r
+ The VGA DAC Registers, all 256 of them.\r
+ \r
+HOW IT WORKS/FEATURES:\r
+ \r
+ PALEDIT allows the user to see the entire VGA Palette of 256 colors\r
+ and select and modify the RED, GREEN, and BLUE values of any individual\r
+ color (DAC) register. The entire group of 256 colors can be saved to\r
+ a disk file for later retrieval.\r
+ \r
+ Individual "SLIDERS" show the current RED, GREEN, and BLUE color\r
+ components of the current color and allow them to be changed.\r
+ \r
+ The Following operations can be performed.\r
+ \r
+ * Raise, Lower, and set the RED, GREEN, or BLUE components.\r
+ * Copy the current RGB values to another Color (DAC) Register\r
+ * Brighten the selected color\r
+ * Darken and selected color\r
+ * Reset the selected color to its original state\r
+ * Blend an entire range of colors, creating a smooth\r
+ Transition from one color to another\r
+ * Optionally Lock out the first 16 colors to prevent\r
+ Accidental Modification\r
+ \r
+DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN:\r
+ \r
+ COLOR SLIDERS: In the upper left of the screen there are\r
+ Three Rectangular Boxes: One for each primary color:\r
+ RED, GREEN, and BLUE. Each Box has an arrow at each\r
+ end, and a scale bar in the middle, connecting the two\r
+ arrows. The scale bar is much like a thermometer,\r
+ indicating how much of that color is in the selected\r
+ color. To the right of each Box, the name of the color\r
+ is indicated, along with the content color in the form\r
+ of a number from 0 to 63; where 0 means none of that\r
+ color goes into making the selected color, and 63 means\r
+ that the selected color is saturated with that color.\r
+ \r
+ Clicking the mouse on the slider's left arrow box will\r
+ decrease the amount of that primary color in the selected\r
+ color. Holding the mouse button down will reduce the\r
+ color value all the way to 0.\r
+ \r
+ Clicking the mouse on the slider's right arrow box will\r
+ increase the amount of that primary color in the selected\r
+ color. Holding the mouse button down will increase the\r
+ color value all the way to 63.\r
+ \r
+ Clicking the mouse on the scale bar will set the amount\r
+ of that primary color to the value the represents that\r
+ position on the slider.\r
+ \r
+ LOCK Button: Clicking the button toggles the lockout of the\r
+ first 16 colors. When they are locked out, they can not\r
+ be modified, and when selected the word "LOCKED" will\r
+ appear below the color # on the Color Information Display.\r
+ \r
+ LOAD Button: Clicking this button will load the Palette file\r
+ that is named in the Palette File name box. If no name is\r
+ given or no such file exists, then nothing will be loaded.\r
+ \r
+ SAVE Button: Clicking this button will save the current Palette\r
+ in a file using the name given in the Palette File Name Box.\r
+ If a Valid name is not provided, nothing will be saved.\r
+ \r
+ QUIT Button: Clicking this button will return you to DOS.\r
+ Nothing is saved, and no confirmation is given.\r
+ \r
+ \r
+ Color Information Display: This Box is on the left side of the\r
+ Screen, below the Color Sliders. It shows the number of the\r
+ currently selected color (from 0 to 255) and indicates if\r
+ that color is locked. To the right of this box is a big\r
+ square showing the current color.\r
+ \r
+ LIGHTER Button: Clicking this button will make the selected\r
+ color brighter.\r
+ \r
+ DARKER Button: Clicking this button will make the selected\r
+ color darker.\r
+ \r
+ RESET Button: Clicking this button will restore the selected\r
+ color to the value it had when it was first selected.\r
+ \r
+ BLEND Button: Clicking this button will let you Blend a range\r
+ of colors together. One end of the range of colors is the\r
+ currently selected color. After Clicking the BLEND button.\r
+ You must click on the color at the other end of the range\r
+ in the Palette Display Box. All of the colors in between\r
+ those two colors will be changed to represent a gradual\r
+ transition from the color at one end to the color at the\r
+ other end.\r
+ \r
+ PALETTE FILE NAME BOX: This Text Box is used to enter the name\r
+ of a Palette file to load or the name to save the current\r
+ Palette as. Just click on the Box, and it will change color\r
+ and a flashing cursor will appear. Now you type in a filename\r
+ or edit the existing filename. Press <RETURN> or click\r
+ outside the text box to end editing.\r
+ \r
+ PALETTE DISPLAY BOX: This Box shows all 256 colors in an array\r
+ of 32 by 8 color blocks. The Currently Selected Color will\r
+ have a Box around it. Clicking on a color with the Left\r
+ Mouse button will make that color the new currently selected\r
+ color. Clicking on a color with the Right Mouse Button will\r
+ copy the color value from the old selected color to it, before\r
+ it is made the new selected color.\r
+ \r
+ Message Bar: At the very bottom of the screen, this Bar will display\r
+ information and messages for various functions.\r
+ \r
+PALETTE FILE FORMAT:\r
+ \r
+ BINARY image, in order of VGA DAC (Color) Number. 3 Bytes Per\r
+ Color, 256 Colors. 768 Bytes total. The Files will be exactly\r
+ 768 bytes in size.\r
+ \r
+ COLOR:\r
+ RED: 1 BYTE\r
+ GREEN: 1 BYTE\r
+ BLUE: 1 BYTE\r
+ \r
+ PALETTE: Array (0 to 255) of COLOR\r
+ \r
+COMMENTS, QUESTIONS, BUG REPORTS, etc:\r
+ \r
+ Send the to the Author: Matt Pritchard\r
+ \r
+ Through the 80xxx Fidonet Echo or\r
+ \r
+ Matt Pritchard\r
+ P.O. Box 140264\r
+ Irving, TX 75014\r
+ \r
+CREDITS:\r
+ \r
+ This Palette Editor was written in QuickBASIC 4.5\r
--- /dev/null
+\r
+=========================================================================\r
+ þ þ þþþþþ þþþþ þþþþþ þ þ þ þþþþþ þ þ \r
+ þþ þþ þ þ þ þ þ þ þ þþ þ þ þ þ\r
+ þ þ þ þ þ þ þ þþþþ þ þ þ þ þ þþþþþ\r
+ þ þ þ þ þ þ þ þ þ þ þ þ þ\r
+ þ þ þþþþþ þþþþ þþþþþ þ þ þþþþþ þþ þþþþþ þ\r
+=========================================================================\r
+ MODE X 1.04\r
+=========================================================================\r
+ Library & Editors by Matt Pritchard: Release 1.04 on 14 Mar 93\r
+=========================================================================\r
+\r
+MODEX104 is a library of high performance assembler routines for setting,\r
+accessing, and manipulating the Undocumented 256 Color Modes available in\r
+all VGA adaptors.\r
+\r
+MODEX104 includes the following elements:\r
+\r
+ MODE X Library - A library of MODE X routines written in assembly.\r
+\r
+ FONT EDITOR - An editor for creating and modifying fonts for use by\r
+ The MODE X Library.\r
+\r
+ PALETTE EDITOR - An editor for creating and modifying palettes for\r
+ use in VGA 256 Color modes.\r
+\r
+ MODE X Demos - Programs that show off the various features of the\r
+ MODE X Library\r
+\r
+ MODE X Demo Source - The Full source code for the MODE X Demos for \r
+ the following Languages: Microsoft QuickBASIC 4.5,\r
+ Microsoft BASIC 7.1 PDS, Borland C/C++ 3.1,\r
+ and Borland Turbo Pascal.\r
+\r
+THE LEGAL STUFF:\r
+\r
+ The Mode X Library has been placed into the Public Domain by the\r
+ Author (Matt Pritchard). The Font Editor and Palette Editor are also\r
+ placed into the Public Domain by the Author (Matt Pritchard). The\r
+ Source Code to the above editors is not in the Public Domain.\r
+\r
+ The Mode X Demos and the Mode X Demo Sources have been placed into the\r
+ Public domain by the Author (Matt Pritchard).\r
+\r
+ The Mode X Library may be used freely in any non commerical product.\r
+ It would be nice if the author was credited for the contribution, \r
+ but it is not necessary. No $$$ involved.\r
+ \r
+ The Mode X Library may be used freely in a commercial product, *IF*\r
+ the author (Matt Pritchard) is credited for the contribution. That's\r
+ it. No $$$ involved.\r
+\r
+ The Mode X Library should not be re-sold or modified and re-sold.\r
+ No fee in excess of $5 should be charged for duplication of this\r
+ Library.\r
+\r
+CONTRIBUTORS: The following people have contributed to this effort.\r
+\r
+ Michael Abrash - He told us all how to do it in the first place.\r
+ Scott Wyatt - He ported the Main Demo code to Turbo Pascal.\r
+\r
+THE AUTHOR:\r
+\r
+ The author of MODEX104 is Matt Pritchard.\r
+ All Questions and correspondance can be directed to:\r
+\r
+ "Matt Pritchard" on Fido Net ECHO Conference: 80xxx\r
+\r
+ or mailed to: Matt Pritchard\r
+ P.O. Box 140264\r
+ Irving, TX 75014-0264\r
+\r
+ Questions, Inquiries, Comments, Donations, etc are quite welcome.\r
+\r
+\r