From: sparky4 Date: Sat, 17 May 2014 00:32:17 +0000 (-0500) Subject: new file: 16/PCX_LIB.ZIP X-Git-Url: http://4ch.mooo.com/gitweb/?a=commitdiff_plain;h=ec4f0db1f7da03b379704b1073931cb4e30275a2;p=16.git new file: 16/PCX_LIB.ZIP new file: 16/PCX_LIB/PCX_COMM.C new file: 16/PCX_LIB/PCX_DISP.C new file: 16/PCX_LIB/PCX_EXAM.C new file: 16/PCX_LIB/PCX_EXAM.EXE new file: 16/PCX_LIB/PCX_EXT.H new file: 16/PCX_LIB/PCX_FILE.C new file: 16/PCX_LIB/PCX_FMT.DOC new file: 16/PCX_LIB/PCX_INT.H new file: 16/PCX_LIB/PCX_LIB.BAT new file: 16/PCX_LIB/PCX_LIB.DOC new file: 16/PCX_LIB/RD_DEMO.C new file: 16/PCX_LIB/RD_DEMO.EXE new file: 16/PCX_LIB/TEST_04.PCX new file: 16/PCX_LIB/TEST_06.PCX new file: 16/PCX_LIB/TEST_16.PCX new file: 16/PCX_LIB/TEST_19.PCX new file: 16/PCX_LIB/WR_DEMO.C new file: 16/PCX_LIB/WR_DEMO.EXE new file: 16/modex105.zip new file: 16/modex105/ASM.BAT new file: 16/modex105/DEMOS/BASIC7/CHARDEMO.BAS new file: 16/modex105/DEMOS/BASIC7/MAKE-LIB.BAT new file: 16/modex105/DEMOS/BASIC7/MODEX.BI new file: 16/modex105/DEMOS/BASIC7/MODEX.LIB new file: 16/modex105/DEMOS/BASIC7/MODEX.QLB new file: 16/modex105/DEMOS/BASIC7/TEST6.BAS new file: 16/modex105/DEMOS/BASIC7/UASM-BC7.BAT new file: 16/modex105/DEMOS/BASIC7/UTILS.ASM new file: 16/modex105/DEMOS/BASIC7/UTILS.BI new file: 16/modex105/DEMOS/C/C_UTILS.ASM new file: 16/modex105/DEMOS/C/C_UTILS.H new file: 16/modex105/DEMOS/C/MODEX.H new file: 16/modex105/DEMOS/C/UTLS-ASM.BAT new file: 16/modex105/DEMOS/C/X-DEMO.C new file: 16/modex105/DEMOS/C/X-DEMO.EXE new file: 16/modex105/DEMOS/C/X-DEMO.PRJ new file: 16/modex105/DEMOS/CHARDEMO.EXE new file: 16/modex105/DEMOS/PASCAL/TEST5.PAS new file: 16/modex105/DEMOS/QB45/MAKE-LIB.BAT new file: 16/modex105/DEMOS/QB45/MODEX.BI new file: 16/modex105/DEMOS/QB45/MODEX.LIB new file: 16/modex105/DEMOS/QB45/MODEX.QLB new file: 16/modex105/DEMOS/QB45/TEST6A.BAS new file: 16/modex105/DEMOS/QB45/TEST6A.EXE new file: 16/modex105/DEMOS/QB45/UASM-QB4.BAT new file: 16/modex105/DEMOS/QB45/UTILS.ASM new file: 16/modex105/DEMOS/QB45/UTILS.BI new file: 16/modex105/DEMOS/ROM_8X8.FNT new file: 16/modex105/DEMOS/SPACEAGE.FNT new file: 16/modex105/DEMOS/SYSTEM.FNT new file: 16/modex105/DEMOS/TEST6.EXE new file: 16/modex105/FONTEDIT/CHARSETS.CS new file: 16/modex105/FONTEDIT/CSEDIT.DOC new file: 16/modex105/FONTEDIT/CSEDIT.EXE new file: 16/modex105/FONTEDIT/INVERSE.FNT new file: 16/modex105/FONTEDIT/MOUSEIMG.CS new file: 16/modex105/FONTEDIT/PALETTE.CS new file: 16/modex105/FONTEDIT/ROM_8X8.FNT new file: 16/modex105/FONTEDIT/SPACEAGE.FNT new file: 16/modex105/FONTEDIT/SYSTEM.FNT new file: 16/modex105/MODE-X.TXT new file: 16/modex105/MODEX.ASM new file: 16/modex105/MODEX.BI new file: 16/modex105/MODEX.H new file: 16/modex105/PACKING.LST new file: 16/modex105/PALEDIT/CHARSETS.CS new file: 16/modex105/PALEDIT/GAMECOLR.PAL new file: 16/modex105/PALEDIT/MOUSEIMG.CS new file: 16/modex105/PALEDIT/PALEDIT.DOC new file: 16/modex105/PALEDIT/PALEDIT.EXE new file: 16/modex105/PALEDIT/PRIME.PAL new file: 16/modex105/PALEDIT/RGB.PAL new file: 16/modex105/README.DOC --- diff --git a/16/PCX_LIB.ZIP b/16/PCX_LIB.ZIP new file mode 100644 index 00000000..d43913bb Binary files /dev/null and b/16/PCX_LIB.ZIP differ diff --git a/16/PCX_LIB/PCX_COMM.C b/16/PCX_LIB/PCX_COMM.C new file mode 100644 index 00000000..42520561 --- /dev/null +++ b/16/PCX_LIB/PCX_COMM.C @@ -0,0 +1,198 @@ +/* + ************************************************************************* + * + * PCX_COMM.C - PCX_LIB Library Common Functions + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/03 - fixed "segread" call. + * 91/04/07 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* + ************************************************************************* + * + * PORTABILITY NOTES + * + * 1. While this program is written in ANSI C, it uses a number of + * function calls that are specific to the Microsoft C V6.0 library. + * These are documented as follows for the purposes of porting this + * program to other compilers and/or processors: + * + * int86x - execute 80x86 interrupt routine (far data) + * segread - get current 80x86 segment register values + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include +#include "pcx_int.h" + +/* FORWARD REFERENCES */ + +/* GLOBALS */ + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * PCX_OPEN - Open PCX Workblock + * + * Purpose: To allocate and initialize a PCX image file workblock. + * + * Setup: PCX_WORKBLK *pcx_open + * ( + * char *fname, + * BOOL wrt_flag + * ) + * + * Where: fname is a PCX image file name. + * wrt_flag is a Boolean flag which if TRUE indicates that + * the PCX image file is to be opened for writing; + * otherwise it is opened for reading. + * + * Return: A pointer to a PCX image file workblock if successful; + * otherwise NULL. + * + ************************************************************************* + */ + +PCX_WORKBLK *pcx_open +( + char *fname, + BOOL wrt_flag +) +{ + PCX_WORKBLK *wbp; /* PCX image file workblock pointer */ + + /* Allocate a workblock */ + + if ((wbp = (PCX_WORKBLK *) malloc(sizeof(PCX_WORKBLK))) == NULL) + return (NULL); + + /* Open the PCX image file in binary mode */ + + if (wrt_flag == FALSE) + wbp->fp = fopen(fname, "rb"); /* Open for reading */ + else + wbp->fp = fopen(fname, "wb"); /* Open for writing */ + + if (wbp->fp == NULL) /* Check for successful file opening */ + { + free(wbp); /* Free the workblock memory */ + return (NULL); + } + + return (wbp); /* Return the workblock pointer */ +} + +/* + ************************************************************************* + * + * PCX_CLOSE - Close PCX Workblock + * + * Purpose: To close a PCX image file and release its workblock + * memory. + * + * Setup: BOOL pcx_close + * ( + * PCX_WORKBLK *wbp + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +BOOL pcx_close +( + PCX_WORKBLK *wbp +) +{ + free(wbp->palettep); /* Free the extended palette (if it exists) */ + + free(wbp); /* Free the PCX image file workblock */ + + if (fclose(wbp->fp) == EOF) /* Close the PCX image file */ + return (FALSE); + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_ISVGA - Check For VGA Display Adapter + * + * Purpose: To determine whether a display adapter supports VGA BIOS + * service routines. + * + * Setup: BOOL pcx_isvga(void) + * + * Return: TRUE if display adapter is VGA-compatible; otherwise + * FALSE. + * + ************************************************************************* + */ + +BOOL pcx_isvga(void) +{ + unsigned char *vinfop; /* VGA information buffer pointer */ + union REGS regs; /* 80x86 register values */ + struct SREGS sregs; /* 80x86 segment register values */ + + /* Allocate a VGA functionality/state information buffer */ + + if ((vinfop = (unsigned char *) malloc(sizeof(unsigned char) * 64)) == + NULL) + return (FALSE); + + /* Attempt to read the VGA information */ + + regs.h.ah = 0x1b; /* Select "Return VGA Info" BIOS routine */ + regs.x.bx = 0; /* Implementation type */ + + /* Get the VGA information buffer offset value */ + + regs.x.di = (unsigned int) vinfop; + + segread(&sregs); /* Get the current DS segment register value */ + + sregs.es = sregs.ds; + + int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */ + + free(vinfop); /* Free the VGA information buffer */ + + /* The value 0x1b is returned in register AL only if a VGA display */ + /* adapter is present */ + + if (regs.h.al == 0x1b) + return (TRUE); + else + return (FALSE); +} + diff --git a/16/PCX_LIB/PCX_DISP.C b/16/PCX_LIB/PCX_DISP.C new file mode 100644 index 00000000..7547b9f9 --- /dev/null +++ b/16/PCX_LIB/PCX_DISP.C @@ -0,0 +1,1140 @@ +/* + ************************************************************************* + * + * PCX_DISP.C - PCX_LIB Library Image Display Functions + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/03 - fixed "segread" call. + * 91/04/07 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* + ************************************************************************* + * + * PORTABILITY NOTES + * + * 1. While this program is written in ANSI C, it uses a number of + * function calls that are specific to the Microsoft C V6.0 library. + * These are documented as follows for the purposes of porting this + * program to other compilers and/or processors: + * + * _fmemcpy - "memcpy" for small model / far data + * int86 - execute 80x86 interrupt routine + * int86x - execute 80x86 interrupt routine (far + * data) + * _remapallpalette - remap entire video display color palette + * _selectpalette - select CGA color palette + * outpw - output word to 80x86 I/O port + * segread - get current 80x86 segment register + * values + * + * 2. When porting this program to other processors, remember that words + * are stored by 80x86-based machines in the big-endian format. That + * is, the eight least significant bits (lower byte) are stored + * first, followed by the eight most significant bits (upper byte). + * If PCX-format files are transferred to little-endian machines + * (such as those based on 680x0 and Z8000 processors), the order of + * bytes within each word will have to be reversed before they can + * be interpreted. (This applies to the file header only, since the + * encoded image data and optional 256-color palette are stored as + * bytes.) + * + * 3. MS-DOS does not recognize the 720 x 348 graphics mode of the + * Hercules monochrome display adapter. Therefore, the constant + * PCX_HERC should never be passed as a video mode parameter to any + * BIOS service routine. + * + * The Microsoft C compiler includes a "video mode" parameter + * definition (_HERCMONO) that is defined as 0x08. This is a + * reserved MS-DOS video mode that is apparently used internally by + * the ROM BIOS. It can, however, be passed to the Microsoft C + * library function "_setvideomode" to force the Hercules display + * adapter into graphics mode. + * + * Most other MS-DOS C compilers offer similar library functions to + * force the Hercules monochrome display adapter into its 720 x 348 + * graphics mode. + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include +#include +#include +#include +#include +#include "pcx_int.h" + +/* FORWARD REFERENCES */ + +static BOOL pcx_read_init(PCX_WORKBLK *, int, int); +static BOOL pcx_read_extpal(PCX_WORKBLK *); +static BOOL pcx_read_header(PCX_WORKBLK *); +static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int); +static BOOL pcx_set_palette(PCX_PAL *, int); + +static void pcx_cga_palette(PCX_PAL *, int); +static void pcx_put_cga(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_put_ega(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_put_herc(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int); + +/* GLOBALS */ + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * PCX_READ - Read PCX Image File + * + * Purpose: To read and display a PCX-format image file. + * + * Setup: BOOL pcx_read + * ( + * char *fname, + * int vmode, + * int page + * ) + * + * Where: fname is a PCX image file name. + * vmode is the MS-DOS video mode. Valid values are: + * + * PCX_HERC - 720 x 348 Hercules monochrome + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * page is the video display page number. Valid values are: + * + * Mode PCX_HERC - 0 or 1 + * Mode 0x0d - 0 to 7 + * Mode 0x0e - 0 to 3 + * Mode 0x0f - 0 or 1 + * Mode 0x10 - 0 or 1 + * All Other - 0 + * + * Return: TRUE if successful; otherwise FALSE. + * + * Note: The video display adapter must be in the appropriate mode + * and active page for the image to be displayed. + * + ************************************************************************* + */ + +BOOL pcx_read +( + char *fname, + int vmode, + int page +) +{ + int bpline; /* Number of bytes per scan line */ + int line_num; /* Scan line number */ + int max_lines; /* Maximum number of scan lines */ + unsigned char *linep; /* PCX scan line buffer pointer */ + BOOL status = TRUE; /* Return status */ + PCX_WORKBLK *wbp; /* PCX image file workblock pointer */ + + /* Open a PCX image file workblock */ + + if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL) + return (FALSE); + + /* Initialize the workblock for reading */ + + if (pcx_read_init(wbp, vmode, page) == FALSE) + { + (void) pcx_close(wbp); /* Close the PCX workblock */ + return (FALSE); + } + + /* Calculate the image height */ + + max_lines = wbp->header.yul + wbp->header.ylr + 1; + + /* Calculate number of bytes per line (for all color planes) */ + + bpline = wbp->header.bppscan * wbp->header.nplanes; + + /* Allocate the PCX scan line buffer */ + + if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *) + NULL) + { + /* Set the file pointer to the beginning of the encoded image data */ + + if (status == TRUE) + if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0) + status = FALSE; + + /* Set the video display adapter color palette unless the PCX file */ + /* is Version 3.0 (i.e. - PC Paintbrush Version 2.8 w/o palette) */ + + if (status == TRUE) + if (wbp->header.version != 3) + if (pcx_set_palette(wbp->palettep, vmode) == FALSE) + status = FALSE; + + /* Read the image line by line */ + + if (status == TRUE) + { + for (line_num = 0; line_num < max_lines; line_num++) + { + /* Read the current scan line */ + + if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE) + { + status = FALSE; + break; + } + + /* Display the current scan line */ + + wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num); + } + } + + free(linep); /* Free the PCX scan line buffer */ + } + else + status = FALSE; + + if (pcx_close(wbp) == FALSE) /* Close the PCX workblock */ + status = FALSE; + + return (status); +} + +/* PRIVATE FUNCTIONS */ + +/* + ************************************************************************* + * + * PCX_READ_INIT - Initialize PCX Workblock For Reading + * + * Purpose: To initialize a PCX image file workblock for reading. + * + * Setup: static BOOL pcx_read_init + * ( + * PCX_WORKBLK *wbp, + * int vmode, + * int page + * ) + * + * Where: wbp is a PCX workblock pointer. + * vmode is the MS-DOS video mode. Valid values are: + * + * PCX_HERC - 720 x 348 Hercules monochrome + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * page is the video display page number. Valid values are: + * + * Mode PCX_HERC - 0 or 1 + * Mode 0x0d - 0 to 7 + * Mode 0x0e - 0 to 3 + * Mode 0x0f - 0 or 1 + * Mode 0x10 - 0 or 1 + * All Other - 0 + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_read_init +( + PCX_WORKBLK *wbp, + int vmode, + int page +) +{ + int width; /* Display width */ + int leftover; /* Number of unseen bits */ + BOOL status = TRUE; /* Return status */ + + /* Read the file header */ + + if ((pcx_read_header(wbp)) == FALSE) + return (FALSE); + + /* Initialize the workblock color palette pointer */ + + wbp->palettep = wbp->header.palette; + wbp->epal_flag = FALSE; + + /* Read the extended palette (if any) */ + + if (vmode == 0x13 && wbp->header.version == 5) + if (pcx_read_extpal(wbp) == FALSE) + return (FALSE); + + /* Initialize the display page address offset */ + + wbp->page_offset = (unsigned long) 0L; + + switch (vmode) /* Select PCX line display function */ + { + case PCX_HERC: /* 720 x 348 Hercules monochrome */ + + /* Hercules monochrome display adapter supports 2 pages */ + + wbp->page_offset = 0x08000000L * (unsigned long) page; + + /* Calculate display width in pixels */ + + width = min((wbp->header.xlr - wbp->header.xul + 1), 720); + + /* Calculate number of bytes to display */ + + wbp->num_bytes = (width + 7) >> 3; + + /* Calculate mask for leftover bits */ + + if ((leftover = width & 7) != 0) + wbp->mask = (0xff << (8 - leftover)) & 0xff; + else + wbp->mask = 0xff; + + wbp->pcx_funcp = pcx_put_herc; /* Set the display function ptr */ + + break; + + case 0x04: /* 320 x 200 4-color CGA */ + case 0x05: /* 320 x 200 4-color CGA (color burst off) */ + + /* Calculate display width in pixels */ + + width = min((wbp->header.xlr - wbp->header.xul + 1), 320); + + /* Calculate number of bytes to display */ + + wbp->num_bytes = (width + 3) >> 2; + + /* Calculate mask for leftover bits */ + + if ((leftover = (width & 3) << 1) != 0) + wbp->mask = (0xff << (8 - leftover)) & 0xff; + else + wbp->mask = 0xff; + + wbp->pcx_funcp = pcx_put_cga; /* Set the display function ptr */ + + break; + + case 0x06: /* 640 x 200 2-color CGA */ + + /* Calculate display width in pixels */ + + width = min((wbp->header.xlr - wbp->header.xul + 1), 640); + + /* Calculate number of bytes to display */ + + wbp->num_bytes = (width + 7) >> 3; + + /* Calculate mask for leftover bits */ + + if ((leftover = width & 7) != 0) + wbp->mask = (0xff << (8 - leftover)) & 0xff; + else + wbp->mask = 0xff; + + wbp->pcx_funcp = pcx_put_cga; /* Set the display function ptr */ + + break; + + case 0x0d: /* 320 x 200 16-color EGA/VGA */ + case 0x0e: /* 640 x 200 16-color EGA/VGA */ + case 0x0f: /* 640 x 350 2-color EGA/VGA */ + case 0x10: /* 640 x 350 16-color EGA/VGA */ + case 0x11: /* 640 x 480 2-color VGA */ + case 0x12: /* 640 x 480 16-color VGA */ + + switch (vmode) /* Initialize the display adapter page offset */ + { + case 0x0d: /* 320 x 200 16-color EGA/VGA (8 pages maximum) */ + + wbp->page_offset = 0x02000000L * (unsigned long) page; + + break; + + case 0x0e: /* 640 x 200 16-color EGA/VGA (4 pages maximum) */ + + wbp->page_offset = 0x04000000L * (unsigned long) page; + + break; + + case 0x0f: /* 640 x 350 2-color EGA/VGA (2 pages maximum) */ + case 0x10: /* 640 x 350 16-color EGA/VGA (2 pages maximum) */ + + wbp->page_offset = 0x08000000L * (unsigned long) page; + + break; + + default: /* All other modes support only one page */ + + break; + } + + /* Calculate display width in pixels */ + + width = min((wbp->header.xlr - wbp->header.xul + 1), 640); + + /* Calculate number of bytes to display */ + + wbp->num_bytes = (width + 7) >> 3; + + /* Calculate mask for leftover bits */ + + if ((leftover = width & 7) != 0) + wbp->mask = (0xff << (8 - leftover)) & 0xff; + else + wbp->mask = 0xff; + + wbp->pcx_funcp = pcx_put_ega; /* Set the display function ptr */ + + break; + + case 0x13: /* 320 x 200 256-color VGA */ + + /* Calculate number of bytes to display */ + + wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320); + + wbp->mask = 0; /* Dummy parameter */ + + wbp->pcx_funcp = pcx_put_vga; /* Set the display function ptr */ + + break; + + default: /* Other display adapters not supported */ + + status = FALSE; + + break; + } + + return (status); +} + +/* + ************************************************************************* + * + * PCX_READ_HEADER - Read PCX File Header + * + * Purpose: To read and validate a PCX file header. + * + * Setup: static BOOL pcx_read_header + * ( + * PCX_WORKBLK *wbp + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * + * Return: TRUE if successful; otherwise FALSE. + * + * Result: The file header is read into the "header" member of the + * PCX workblock. + * + ************************************************************************* + */ + +static BOOL pcx_read_header +( + PCX_WORKBLK *wbp +) +{ + BOOL status = TRUE; /* Status flag */ + PCX_HDR *hdrp; /* PCX file header buffer pointer */ + + hdrp = &(wbp->header); /* Initialize the file header pointer */ + + /* Read the file header */ + + if (fseek(wbp->fp, 0L, SEEK_SET) != 0) + status = FALSE; + + if (status == TRUE) + if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1) + status = FALSE; + + /* Validate the PCX file format */ + + if (status == TRUE) + if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1)) + status = FALSE; + + return (status); +} + +/* + ************************************************************************* + * + * PCX_READ_EXTPAL - Read Extended Palette + * + * Purpose: To read an extended (256-color) palette (if it exists). + * + * Setup: static BOOL pcx_read_extpal + * ( + * PCX_WORKBLK *wbp + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * + * Return: TRUE if successful; otherwise FALSE. + * + * Note: It is possible for a PCX image file without an appended + * 256-color palette to have the value 0x0c as the 769th byte + * (the location of the extended palette indicator byte) from + * the end of the file (i.e. - in the encoded image data + * section). This function will misinterpret the following + * 768 bytes of encoded image data as an extended palette. + * + * This problem will only occur if an attempt is made to + * display a PCX image using the wrong MS-DOS video mode. It + * can be detected by decoding the image data and using + * "ftell" to note the file position of the end of the + * encoded image data section, then comparing it to the file + * position of the indicator byte. If the supposed indicator + * byte is located within the encoded image data section, the + * indicator byte is invalid and so the file header palette + * should be used instead. + * + ************************************************************************* + */ + +static BOOL pcx_read_extpal +( + PCX_WORKBLK *wbp +) +{ + int indicator; /* PCX extended palette indicator */ + + /* Position the file pointer to the extended palette indicator byte */ + + if (fseek(wbp->fp, -769L, SEEK_END) != 0) + return (FALSE); + + /* Read the (assumed) extended palette indicator byte */ + + if ((indicator = getc(wbp->fp)) == EOF) + return (FALSE); + + if (indicator == PCX_EPAL_FLAG) /* Check for indicator byte */ + { + /* Allocate an extended palette buffer */ + + if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), + PCX_EPAL_SIZE)) == (PCX_PAL *) NULL) + return (FALSE); + + /* Read the extended palette */ + + if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) != + PCX_EPAL_SIZE) + { + free(wbp->palettep); /* Free the extended palette buffer */ + return (FALSE); + } + + wbp->epal_flag = TRUE; /* Indicate extended palette present */ + } + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_READ_LINE - Read PCX Line + * + * Purpose: To read an encoded line (all color planes) from a PCX- + * format image file and write the decoded data to a line + * buffer. + * + * Setup: static BOOL pcx_read_line + * ( + * PCX_WORKBLK *wbp, + * unsigned char *linep, + * int bpline + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * linep is a PCX scan line buffer pointer. + * bpline is the number of bytes per scan line (all color + * planes). + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_read_line +( + PCX_WORKBLK *wbp, + unsigned char *linep, + int bpline +) +{ + int data; /* Image data byte */ + int count; /* Image data byte repeat count */ + int offset = 0; /* Scan line buffer offset */ + + while (offset < bpline) /* Decode current scan line */ + { + if ((data = getc(wbp->fp)) == EOF) /* Get next byte */ + return (FALSE); + + /* If top two bits of byte are set, lower six bits show how */ + /* many times to duplicate next byte */ + + if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) + { + count = data & PCX_COMP_MASK; /* Mask off repeat count */ + + if ((data = getc(wbp->fp)) == EOF) /* Get next byte */ + return (FALSE); + + memset(linep, data, count); /* Duplicate byte */ + linep += count; + offset += count; + } + else + { + *linep++ = (unsigned char) data; /* Copy byte */ + offset++; + } + } + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_SET_PALETTE - Set Palette + * + * Purpose: To set the display palette according to a PCX file + * palette. + * + * Setup: static BOOL pcx_set_palette + * ( + * PCX_PAL *palettep, + * int vmode + * ) + * + * Where: palettep is a pointer to a PCX file palette. + * vmode is the MS-DOS video mode. Valid values are: + * + * PCX_HERC - 720 x 348 Hercules monochrome + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_set_palette +( + PCX_PAL *palettep, + int vmode +) +{ + int i; /* Scratch counter */ + int red_lo; /* Low red intensity */ + int red_hi; /* High red intensity */ + int green_lo; /* Green low intensity */ + int green_hi; /* Green high intensity */ + int blue_lo; /* Blue low intensity */ + int blue_hi; /* Blue high intensity */ + unsigned char *ega_palp; /* EGA 16-color palette buffer pointer */ + unsigned long *vga_palp; /* VGA 256-color palette buffer pointer */ + BOOL status = TRUE; /* Return status */ + union REGS regs; /* 80x86 register values */ + struct SREGS sregs; /* 80x86 segment register values */ + + switch (vmode) + { + case PCX_HERC: /* 720 x 348 Hercules monochrome */ + + break; + + case 0x04: /* 320 x 200 4-color CGA display */ + case 0x05: /* 320 x 200 monochrome CGA display (burst off) */ + case 0x06: /* 640 x 200 2-color CGA display */ + + /* Set the CGA color palette */ + + pcx_cga_palette(palettep, vmode); + + break; + + case 0x0d: /* 320 x 200 16-color EGA/VGA */ + case 0x0e: /* 640 x 200 16-color EGA/VGA */ + case 0x0f: /* 640 x 350 2-color EGA/VGA */ + case 0x10: /* 640 x 350 16-color EGA/VGA */ + case 0x11: /* 640 x 480 2-color VGA */ + case 0x12: /* 640 x 480 16-color VGA */ + + if (pcx_isvga() == TRUE) /* Check for VGA display adapter */ + { + /* Allocate a 16-color VGA display adapter palette buffer */ + + if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long), + PCX_PAL_SIZE)) == (unsigned long *) NULL) + { + status = FALSE; + break; + } + + /* Map PCX hardware palette to 16-color VGA palette (each color */ + /* value is a "long" with the form: */ + /* */ + /* 00000000-00BBBBBB-00GGGGGG-00RRRRRR */ + /* */ + /* where each color is a 6-bit value. */ + + for (i = 0; i < PCX_PAL_SIZE; i++) + vga_palp[i] = (long) (palettep[i].red >> 2) | + ((long) (palettep[i].green >> 2)) << 8 | + ((long) (palettep[i].blue >> 2)) << 16; + + (void) _remapallpalette(vga_palp); /* Remap entire palette */ + + free(vga_palp); /* Free the VGA palette buffer */ + } + else /* EGA display adapter */ + { + /* Allocate an EGA display adapter palette buffer */ + + if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char), + PCX_PAL_SIZE + 1)) == (unsigned char *) NULL) + { + status = FALSE; + break; + } + + /* Map PCX hardware palette to 16-color EGA palette (each EGA */ + /* color value is an "unsigned char" with the form: */ + /* */ + /* 0 0 R' G' B' R G B */ + /* */ + /* where X' is the low-intensity value and X is the high */ + /* intensity value for the color X.) */ + /* */ + /* NOTE: the "_remapallpalette" function could be used to set */ + /* the palette for EGA display adapters. However, this */ + /* function does not appear to update the palette */ + /* register values in the Dynamic Save Area (see the */ + /* function header for "pcx_init_palette" in PCX_FILE.C) */ + /* for a detailed explanation). */ + + for (i = 0; i < PCX_PAL_SIZE; i++) + { + /* Extract low and high intensity bits for each color */ + + red_lo = (palettep[i].red >> 6) & 0x01; + red_hi = (palettep[i].red >> 6) & 0x02; + green_lo = (palettep[i].green >> 6) & 0x01; + green_hi = (palettep[i].green >> 6) & 0x02; + blue_lo = (palettep[i].blue >> 6) & 0x01; + blue_hi = (palettep[i].blue >> 6) & 0x02; + + /* Combine color intensity bits for EGA palette value */ + + ega_palp[i] = (unsigned char) ((red_lo << 5) | (green_lo << 4) | + (blue_lo << 3) | (red_hi << 1) | green_hi | (blue_hi >> + 1)); + } + + /* Set the border (overscan) color to black (BIOS default) */ + + ega_palp[16] = (unsigned char) 0; + + regs.h.ah = 0x10; /* Select "Set All Palette Registers" */ + regs.h.al = 0x02; + + /* Get the EGA palette registers buffer offset value */ + + regs.x.dx = (unsigned int) ega_palp; + + segread(&sregs); /* Get the current DS segment register value */ + + sregs.es = sregs.ds; + + int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */ + + free(ega_palp); /* Free the EGA palette buffer */ + } + + break; + + case 0x13: /* 320 x 200 256-color VGA display */ + + /* Allocate a 256-color VGA display adapter palette buffer */ + + if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long), + PCX_EPAL_SIZE)) == (unsigned long *) NULL) + { + status = FALSE; + break; + } + + /* Map PCX extended palette to 256-color VGA palette */ + + for (i = 0; i < PCX_EPAL_SIZE; i++) + vga_palp[i] = (long) (palettep[i].red >> 2) | + ((long) (palettep[i].green >> 2)) << 8 | + ((long) (palettep[i].blue >> 2)) << 16; + + (void) _remapallpalette(vga_palp); /* Remap entire palette */ + + free(vga_palp); /* Free the VGA palette buffer */ + + break; + + default: /* Other modes not supported */ + + status = FALSE; + + break; + } + + return (status); +} + +/* + ************************************************************************* + * + * PCX_CGA_PALETTE - Select CGA Palette + * + * Purpose: To set the Color Graphics Adapter (CGA) display palette + * according to a PCX file palette. + * + * Setup: static void pcx_cga_palette + * ( + * PCX_PAL *palettep, + * int vmode + * ) + * + * Where: palettep is a pointer to a PCX file palette. + * vmode is the MS-DOS video mode. Valid values are: + * + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * + * Note: ZSoft's PC Paintbrush products no longer support the CGA + * color palette. When a CGA color palette is encountered, + * PC Paintbrush maps it to a monochrome (black and white) + * palette. + * + * MS-DOS video mode 0x05 (320 x 200 monochrome CGA display, + * color burst off) will only display a monochrome image on + * a composite video monitor (typically a television set with + * an RF adapter). All other monitors will display a color + * palette in this mode (which is different for CGA and EGA + * or VGA display adapters). + * + * The "background" color is actually the foreground color + * (i.e. - the color of activated pixels) for MS-DOS video + * mode 0x06. The background color is black for CGA display + * adapters. + * + ************************************************************************* + */ + +static void pcx_cga_palette +( + PCX_PAL *palettep, + int vmode +) +{ + short pal_num; /* Palette number */ + BOOL sel_flag; /* Palette selector bit flag */ + BOOL int_flag; /* Intensity bit flag */ + union REGS regs; /* 80x86 register values */ + + /* Set the background color */ + + regs.h.ah = 0x0b; /* Select "Set Color Palette" BIOS routine */ + regs.h.bh = 0; + + regs.h.bl = (unsigned char) PCX_CGA_BKGND(palettep); + + int86(0x10, ®s, ®s); /* Call BIOS video service */ + + if (vmode != 0x06) /* Select the CGA color palette */ + { + /* Check the palette selector bit flag */ + + sel_flag = PCX_CGA_SELECT(palettep) ? TRUE : FALSE; + + /* Check the intensity bit flag */ + + int_flag = PCX_CGA_INTENSITY(palettep) ? TRUE : FALSE; + + /* Determine the CGA palette number */ + + if (int_flag == TRUE) /* Intensity = bright */ + { + if (sel_flag == TRUE) + pal_num = 3; /* Light cyan - light magenta - white */ + else + pal_num = 1; /* Cyan - magenta - light grey */ + } + else /* Intensity = dim */ + { + if (sel_flag == TRUE) + pal_num = 2; /* Light green - light red - yellow */ + else + pal_num = 0; /* Green - red - brown */ + } + + /* Select the foreground color palette */ + + (void) _selectpalette(pal_num); + } +} + +/* + ************************************************************************* + * + * PCX_PUT_HERC - Display Hercules PCX Line + * + * Purpose: To copy a decoded PCX image scan line to a Hercules + * monochrome graphics display adapter buffer. + * + * Setup: static void pcx_put_herc + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * linep is a PCX scan line buffer pointer. + * line_num is the scan line number. + * + ************************************************************************* + */ + +void pcx_put_herc +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] &= wbp->mask; + + /* Calculate Hercules display buffer pointer */ + + displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) + + ((line_num >> 2) * 90) + 0x2000 * (line_num & 3); + + /* Copy data from the scan line buffer to the Hercules display buffer */ + + (void) _fmemcpy(displayp, linep, wbp->num_bytes); +} + +/* + ************************************************************************* + * + * PCX_PUT_CGA - Display CGA PCX Line + * + * Purpose: To copy a decoded PCX image scan line to a CGA display + * adapter buffer. + * + * Setup: static void pcx_put_cga + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * linep is a PCX scan line buffer pointer. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_put_cga +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] &= wbp->mask; + + /* Calculate CGA display buffer pointer */ + + displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80) + + 0x2000 * (line_num & 1); + + /* Copy data from the scan line buffer to the CGA display buffer */ + + (void) _fmemcpy(displayp, linep, wbp->num_bytes); +} + +/* + ************************************************************************* + * + * PCX_PUT_EGA - Display EGA/VGA PCX Line + * + * Purpose: To copy a decoded PCX image scan line to an EGA/VGA + * display adapter buffer. + * + * Setup: static void pcx_put_ega + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * linep is a PCX scan line buffer pointer. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_put_ega +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + int plane_num; /* EGA/VGA color plane number */ + int plane_mask; /* EGA/VGA color plane mask */ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate buffer pointer */ + + displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) + + line_num * 80; + + outpw(0x03ce, 0x0005); /* Select EGA/VGA write mode 0 */ + + /* Copy PCX scan line data to each color plane */ + + plane_mask = 0x0100; /* Start with color plane 0 */ + + for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++) + { + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] &= wbp->mask; + + outpw(0x03c4, plane_mask + 2); /* Select current color plane */ + + /* Copy data from the scan line buffer to the EGA/VGA display */ + + (void) _fmemcpy(displayp, linep, wbp->num_bytes); + + linep += wbp->header.bppscan; /* Increment plane offset */ + + plane_mask <<= 1; /* Sequence plane mask */ + } + + outpw(0x03c4, 0x0f02); /* Select all color planes */ +} + +/* + ************************************************************************* + * + * PCX_PUT_VGA - Display VGA PCX Line + * + * Purpose: To copy a decoded PCX image scan line to a VGA display + * adapter buffer. + * + * Setup: static void pcx_put_vga + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX image file workblock pointer. + * linep is a PCX scan line buffer pointer. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_put_vga +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate buffer pointer */ + + displayp = (unsigned char _far *) 0xa0000000L + line_num * 320; + + /* Copy data from the scan line buffer to the VGA display buffer */ + + (void) _fmemcpy(displayp, linep, wbp->num_bytes); +} + diff --git a/16/PCX_LIB/PCX_EXAM.C b/16/PCX_LIB/PCX_EXAM.C new file mode 100644 index 00000000..556f0f00 --- /dev/null +++ b/16/PCX_LIB/PCX_EXAM.C @@ -0,0 +1,339 @@ +/* + ************************************************************************* + * + * PCX_EXAM.C - PCX_LIB File Header Examination Utility + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/06 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* + ************************************************************************* + * + * PORTABILITY NOTES + * + * 1. When porting this program to other processors, remember that words + * are stored by 80x86-based machines in the big-endian format. That + * is, the eight least significant bits (lower byte) are stored + * first, followed by the eight most significant bits (upper byte). + * If PCX-format files are transferred to little-endian machines + * (such as those based on 680x0 and Z8000 processors), the order of + * bytes within each word will have to be reversed before they can + * be interpreted. (This applies to the file header only, since the + * encoded image data and optional 256-color palette are stored as + * bytes.) + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include "pcx_int.h" + +/* FORWARD REFERENCES */ + +/* GLOBALS */ + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * MAIN - Executive Function + * + * Purpose: To read and display a PCX-format image file header. + * + * Setup: int main + * ( + * int argc, + * char **argv + * ) + * + * Where: argc is the number of command-line arguments. + * argv is a pointer to an array of command-line argument + * strings. + * + * Return: 0 if successful; otherwise 2. + * + * Result: The file header information is written to "stdout". + * + * Note: Usage is: + * + * PCX_EXAM filename + * + * where "filename" is the name of a PCX-format image file. + * + ************************************************************************* + */ + +int main +( + int argc, + char **argv +) +{ + char *vers; /* Version number string pointer */ + char *pal_type; /* Palette type string pointer */ + int range; /* Palette range */ + int indicator; /* Extended palette indicator byte */ + BOOL status = TRUE; /* Return status */ + BOOL ep_flag = FALSE; /* Extended palette flag */ + FILE *fp; /* File pointer */ + PCX_HDR *hdrp; /* File header structure pointer */ + PCX_PAL *ext_palettep; /* Extended palette pointer */ + + /* Display program title */ + + puts("\nPCX_EXAM - PCX Image File Examination Utility\n"); + + /* Check for filename */ + + if (argc < 2) + { + /* Display usage information */ + + fputs(" Synopsis: This public domain utility displays inf", stderr); + fputs("ormation contained in the\n header of a ", stderr); + fputs("Paintbrush (R) PCX-format image file.\n\n Usage: ", stderr); + fputs(" PCX_EXAM filename\n\n Example: PCX_EXAM picture", stderr); + fputs(".pcx\n", stderr); + + return (2); + } + + /* Allocate a PCX file header buffer */ + + if ((hdrp = (PCX_HDR *) malloc(sizeof(PCX_HDR))) == (PCX_HDR *) NULL) + { + fputs("ERROR: out of memory\n", stderr); + return (2); + } + + /* Open the PCX image file in binary mode */ + + if ((fp = fopen(argv[1], "rb")) == (FILE *) NULL) + { + fprintf(stderr, "ERROR: cannot open file %s\n", argv[1]); + + free(hdrp); /* Free the file header memory */ + + return (2); + } + + /* Read the file header */ + + if (status == TRUE) + if (fseek(fp, 0L, SEEK_SET) != 0) + { + fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]); + status = FALSE; + } + + if (status == TRUE) + if (fread(hdrp, sizeof(PCX_HDR), 1, fp) != 1) + { + fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]); + status = FALSE; + } + + /* Validate the PCX file format */ + + if (status == TRUE) + if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1)) + { + fprintf(stderr, "ERROR: file %s not valid PCX format\n", argv[1]); + status = FALSE; + } + + /* Determine the version number */ + + switch (hdrp->version) + { + case 0: + + vers = "PC Paintbrush 2.5"; + + break; + + case 2: + + vers = "PC Paintbrush 2.8 (with palette information)"; + + break; + + case 3: + + vers = "PC Paintbrush 2.8 (without palette information)"; + + break; + + case 4: + + vers = "PC Paintbrush for Windows (not 3.0)"; + + break; + + case 5: + + vers = "PC Paintbrush 3.0 and greater"; + + break; + + default: + + vers = "Unknown version"; + + break; + } + + /* Display the PCX file header information */ + + printf("PCX filename: %s\n", argv[1]); + printf("Version: %s\n", vers); + printf("Encoding: %s\n", hdrp->encoding == 1 ? "Run length" : + "Unknown"); + printf("%d bits per pixel\n", hdrp->bppixel); + printf("Image from (%d, %d) to (%d, %d) pixels.\n", hdrp->xul, + hdrp->yul, hdrp->xlr, hdrp->ylr); + printf("Created on a device with %d x %d dpi resolution\n", + hdrp->horz_res, hdrp->vert_res); + printf("Number of color planes: %d\n", hdrp->nplanes); + printf("Bytes per color plane scan line: %d\n", hdrp->bppscan); + + switch (hdrp->palette_type & PCX_PAL_MASK) + { + case 1: + + pal_type = "color or B&W"; + + break; + + case 2: + + pal_type = "grayscale"; + + break; + + default: + + pal_type = "unknown"; + + break; + } + + printf("Palette type: %s\n", pal_type); + + /* Check for extended (256-color) palette */ + + if (hdrp->version == 5) + { + /* Check for valid palette indicator byte */ + + if (fseek(fp, -769L, SEEK_END) != 0) + { + fprintf(stderr, "ERROR: cannot read file %s\n", argv[1]); + status = FALSE; + } + + if (status == TRUE) + { + if ((indicator = getc(fp)) == PCX_EPAL_FLAG) + { + /* Allocate an extended palette buffer */ + + if ((ext_palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), + PCX_EPAL_SIZE)) == (PCX_PAL *) NULL) + { + fputs("ERROR: out of memory\n", stderr); + status = FALSE; + } + + /* Read the extended palette */ + + if (status == TRUE) + { + if (fread(ext_palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) != + PCX_EPAL_SIZE) + { + free(ext_palettep); /* Free extended palette buffer */ + status = FALSE; + } + } + + ep_flag = TRUE; /* Indicate extended palette exists */ + } + } + } + + if (status == TRUE) + if (ep_flag == TRUE) + { + /* Display extended (256-color) palette */ + + puts("Extended 256-color palette:\n"); + + puts("COLOR RED GREEN BLUE\n"); + + for (range = 0; range < PCX_EPAL_SIZE; range++) + printf(" %03d %2x %2x %2x\n", range, + ext_palettep[range].red, ext_palettep[range].green, + ext_palettep[range].blue); + + putchar('\n'); + + free(ext_palettep); /* Free the extended palette */ + } + else + { + /* Display file header palette */ + + puts("File header color palette:\n"); + + printf("RED ... "); + + for (range = 0; range < PCX_PAL_SIZE; range++) + printf("%2x ", hdrp->palette[range].red); + + printf("\nGREEN ... "); + + for (range = 0; range < PCX_PAL_SIZE; range++) + printf("%2x ", hdrp->palette[range].green); + + printf("\nBLUE ... "); + + for (range = 0; range < PCX_PAL_SIZE; range++) + printf("%2x ", hdrp->palette[range].blue); + + putchar('\n'); + } + + if (fclose(fp) == EOF) /* Close the file */ + { + fprintf(stderr, "Error: cannot close file %s\n", argv[1]); + status = FALSE; + } + + free (hdrp); /* Free the file header buffer */ + + return (0); +} + diff --git a/16/PCX_LIB/PCX_EXAM.EXE b/16/PCX_LIB/PCX_EXAM.EXE new file mode 100644 index 00000000..ddbc9880 Binary files /dev/null and b/16/PCX_LIB/PCX_EXAM.EXE differ diff --git a/16/PCX_LIB/PCX_EXT.H b/16/PCX_LIB/PCX_EXT.H new file mode 100644 index 00000000..78dbcf18 --- /dev/null +++ b/16/PCX_LIB/PCX_EXT.H @@ -0,0 +1,66 @@ +/* + ************************************************************************* + * + * PCX_EXT.H - PCX_LIB Library External Definitions Include File + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/07 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* DEFINITIONS */ + +#define _PCX_EXT_H 1 + +#define FALSE 0 +#define TRUE 1 + +typedef int BOOL; /* Boolean flag */ + +/* STRUCTURE DECLARATIONS */ + +typedef struct pcx_vsb /* BIOS video services data save buffer */ +{ + struct pcx_ppt /* Primary Pointer Table */ + { + void _far *vptp; /* Video Parameter Table pointer */ + unsigned char _far *dsap; /* Dynamic Save Area pointer */ + void _far *tmacgp; /* Text Mode Aux Char Generator pointer */ + void _far *gmacgp; /* Graphics Mode Aux Char Generator ptr */ + void _far *sptp; /* Secondary Pointer Table pointer */ + void _far *rsv_1; /* Reserved */ + void _far *rsv_2; /* Reserved */ + } + pcx_ppt; + + /* Previous Primary Pointer Table pointer */ + + struct pcx_ppt _far *prev_pptp; +} +PCX_VSB; + +/* FUNCTIONS PROTOTYPES */ + +extern BOOL pcx_init_dsa(PCX_VSB **); +extern BOOL pcx_isvga(void); +extern BOOL pcx_read(char *, int, int); +extern BOOL pcx_write(char *, int, int, int, int); + +extern void pcx_free_dsa(PCX_VSB *); + diff --git a/16/PCX_LIB/PCX_FILE.C b/16/PCX_LIB/PCX_FILE.C new file mode 100644 index 00000000..8e4162c0 --- /dev/null +++ b/16/PCX_LIB/PCX_FILE.C @@ -0,0 +1,1379 @@ +/* + ************************************************************************* + * + * PCX_FILE.C - PCX_LIB Library Image File Functions + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/03 - fixed "segread" call. + * 91/04/07 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* + ************************************************************************* + * + * PORTABILITY NOTES + * + * 1. While this program is written in ANSI C, it uses a number of + * function calls that are specific to the Microsoft C V6.0 library. + * These are documented as follows for the purposes of porting this + * program to other compilers and/or processors: + * + * _ffree - "free" for small model / far data + * _fmalloc - "malloc" for small model / far data + * _fmemcpy - "memcpy" for small model / far data + * int86 - execute 80x86 interrupt routine + * int86x - execute 80x86 interrupt routine (far data) + * outpw - output word to 80x86 I/O port + * segread - get current 80x86 segment register values + * + * 2. When porting this program to other processors, remember that words + * are stored by 80x86-based machines in the big-endian format. That + * is, the eight least significant bits (lower byte) are stored + * first, followed by the eight most significant bits (upper byte). + * If PCX-format files are transferred to little-endian machines + * (such as those based on 680x0 and Z8000 processors), the order of + * bytes within each word will have to be reversed before they can + * be interpreted. (This applies to the file header only, since the + * encoded image data and optional 256-color palette are stored as + * bytes.) + * + * 3. MS-DOS does not recognize the 720 x 348 graphics mode of the + * Hercules monochrome display adapter. Therefore, the constant + * PCX_HERC should never be passed as a video mode parameter to any + * BIOS service routine. + * + * The Microsoft C compiler includes a "video mode" parameter + * definition (_HERCMONO) that is defined as 0x08. This is a + * reserved MS-DOS video mode that is apparently used internally by + * the ROM BIOS. It can, however, be passed to the Microsoft C + * library function "_setvideomode" to force the Hercules display + * adapter into graphics mode. + * + * Most other MS-DOS C compilers offer similar library functions to + * force the Hercules monochrome display adapter into its 720 x 348 + * graphics mode. + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include +#include +#include +#include +#include +#include "pcx_int.h" + +/* FORWARD REFERENCES */ + +static BOOL pcx_encode(int, int, FILE *); +static BOOL pcx_init_palette(PCX_PAL *, int); +static BOOL pcx_write_extpal(FILE *); +static BOOL pcx_write_line(unsigned char *, int, FILE *); +static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int); + +static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int); +static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int); + +/* GLOBALS */ + +/* Default EGA palette register values */ + +static BYTE pcx_EGA_DefPal_1[16] = /* Modes 0x0d and 0x0e */ +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17 +}; + +static BYTE pcx_EGA_DefPal_2[16] = /* Mode 0x0f */ +{ + 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00 +}; + +static BYTE pcx_EGA_DefPal_3[16] = /* Mode 0x10 */ +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f +}; + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * PCX_WRITE - Write PCX File + * + * Purpose: To write a PCX-format image file from an image stored in + * a video buffer. The image is assumed to start in the + * upper left corner of the screen. + * + * Setup: BOOL pcx_write + * ( + * char *fname, + * int vmode, + * int page, + * int width, + * int height, + * ) + * + * Where: fname is a PCX image file name. + * vmode is the MS-DOS video mode. Valid values are: + * + * PCX_HERC - 720 x 348 Hercules monochrome + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * page is the video display page number. Valid values are: + * + * Mode PCX_HERC - 0 or 1 + * Mode 0x0d - 0 to 7 + * Mode 0x0e - 0 to 3 + * Mode 0x0f - 0 or 1 + * Mode 0x10 - 0 or 1 + * All Other - 0 + * + * width is the image width in pixels. + * height is the image height in pixels. + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +BOOL pcx_write +( + char *fname, + int vmode, + int page, + int width, + int height +) +{ + int bpline; /* Number of bytes per scan line */ + int line_num; /* Scan line number */ + unsigned char *linep; /* Image scan line buffer pointer */ + BOOL status = TRUE; /* Return status */ + PCX_WORKBLK *wbp; /* PCX image file workblock pointer */ + + /* Open a PCX image file workblock */ + + if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL) + return (FALSE); + + /* Initialize the workblock for writing */ + + if (pcx_write_init(wbp, vmode, page, width, height) == FALSE) + status = FALSE; + + /* Calculate number of bytes per line (for all color planes) */ + + bpline = wbp->header.bppscan * wbp->header.nplanes; + + /* Allocate a scan line buffer */ + + if (status == TRUE) + if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *) + NULL) + status = FALSE; + + /* Write the file header to the file */ + + if (status == TRUE) + if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1) + status = FALSE; + + /* Write the encoded image data to the file */ + + if (status == TRUE) + { + for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++) + { + /* Get the current video buffer scan line */ + + wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num); + + /* Encode the scan line and write it to the file */ + + if (pcx_write_line(linep, bpline, wbp->fp) == FALSE) + { + status = FALSE; + break; + } + } + } + + if (vmode == 0x13) /* Is a 256-color palette supported ? */ + { + /* Write the extended palette to the file */ + + if (status == TRUE) + if (pcx_write_extpal(wbp->fp) == FALSE) + status = FALSE; + } + + if (pcx_close(wbp) == FALSE) /* Close the PCX workblock */ + status = FALSE; + + free(linep); /* Free the scan line buffer */ + + /* Remove the PCX image file if an error occurred */ + + if (status == FALSE) + (void) remove(fname); + + return (status); +} + +/* + ************************************************************************* + * + * PCX_INIT_DSA - Initialize Dynamic Save Area + * + * Purpose: To set up a Video Services Primary Pointer Table and an + * associated Dynamic Save Area where BIOS service "Set All + * Palette Registers" (function 0x02) can store the EGA color + * palette registers settings after it updates them. + * + * Setup: BOOL pcx_init_dsa + * ( + * PCX_VSB **vsbpp + * ) + * + * Where: vsbp is a pointer to where a pointer to an instantiated + * PCX_VSB structure is to be returned. + * + * Return: TRUE if successful; otherwise FALSE. + * + * Note: The EGA display adapter color palette registers are + * write-only. In order to save the current color palette + * with a PCX-format image file by calling "pcx_write", you + * must call this function BEFORE you display the image in + * the following MS-DOS video modes: + * + * 0x0d - 320 x 200 16-color EGA + * 0x0e - 640 x 200 16-color EGA + * 0x0f - 640 x 350 2-color EGA + * 0x10 - 640 x 350 16-color EGA + * + * You MUST call "pcx_free_dsa" upon completion of your + * program. See the function header of "pcx_init_palette" + * for more information. + * + ************************************************************************* + */ + +BOOL pcx_init_dsa +( + PCX_VSB **vsbpp +) +{ + unsigned char _far *dsap; /* Dynamic Save Area pointer */ + PCX_VSB *vsbp; /* Video services data save buffer ptr */ + + *vsbpp = (PCX_VSB *) NULL; /* Initialize returned pointer */ + + /* Allocate a Dynamic Save Area buffer */ + + if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) * + 256)) == (unsigned char _far *) NULL) + return (FALSE); + + /* Allocate a BIOS video services data save buffer */ + + if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL) + { + _ffree(dsap); /* Free the Dynamic Save Area buffer */ + return (FALSE); + } + + /* Save the existing Primary Pointer Table pointer */ + + vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L); + + /* Copy the existing Primary Pointer Table into the buffer */ + + (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt), + vsbp->prev_pptp, sizeof(struct pcx_ppt)); + + vsbp->pcx_ppt.dsap = dsap; /* Update the Dynamic Save Area ptr */ + + /* Update the Primary Pointer Table pointer in the Video Save Table */ + + *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt); + + *vsbpp = vsbp; /* Return Video Services data save buffer ptr */ + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_FREE_DSA - Release Dynamic Save Area + * + * Purpose: To release memory allocated to the Video Services Primary + * Pointer Table and associated Dynamic Save Area and reset + * the pointer in the Video Save Table. + * + * Setup: void pcx_free_dsa + * ( + * PCX_VSB *vsbp + * ) + * + * Where: vsbp is a pointer to a PCX_VSB structure that was + * previously allocated and initialized by "pcx_init_dsa". + * + * Note: You MUST call this function on completion of your program + * if you previously called "pcx_init_dsa". Failure to do so + * will leave the system in an unstable state. See the + * function header of "pcx_init_palette" for more + * information. + * + ************************************************************************* + */ + +void pcx_free_dsa +( + PCX_VSB *vsbp +) +{ + /* Restore the previous primary pointer table pointer */ + + *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp; + + _ffree(vsbp->pcx_ppt.dsap); /* Free the Dynamic Save Area */ + + free(vsbp); /* Free the Video Services data save buffer */ +} + +/* PRIVATE FUNCTIONS */ + +/* + ************************************************************************* + * + * PCX_WRITE_INIT - Initialize PCX Workblock For Writing + * + * Purpose: To initialize a PCX image file workblock for writing. + * + * Setup: static BOOL pcx_write_init + * ( + * PCX_WORKBLK *wbp, + * int vmode, + * int page, + * int width, + * int height + * ) + * + * Where: wbp is a PCX workblock pointer. + * vmode is the MS-DOS video mode. Valid values are: + * + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * Ox07 - 720 x 348 Hercules monochrome + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * page is the video display page number. Valid values are: + * + * Mode PCX_HERC - 0 or 1 + * Mode 0x0d - 0 to 7 + * Mode 0x0e - 0 to 3 + * Mode 0x0f - 0 or 1 + * Mode 0x10 - 0 or 1 + * All Other - 0 + * + * width is the image width in pixels. + * height is the image height in pixels. + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_write_init +( + PCX_WORKBLK *wbp, + int vmode, + int page, + int width, + int height +) +{ + int max_width; /* Maximum image width */ + int max_height; /* Maximum image height */ + int shift; /* Mask shift value */ + BOOL status = TRUE; /* Return status */ + PCX_HDR *hdrp; /* File header buffer pointer */ + + /* Initialize the display page address offset */ + + wbp->page_offset = (unsigned long) 0L; + + hdrp = &(wbp->header); /* Initialize the file header pointer */ + + /* Initialize the header constants */ + + hdrp->pcx_id = 0x0a; /* PCX format identifier */ + hdrp->version = 5; /* Version number */ + hdrp->encoding = 1; /* Encoding format (run-length) */ + hdrp->xul = 0; /* Upper left x-position */ + hdrp->yul = 0; /* Upper left y-position */ + hdrp->reserved = 0; /* (Used to be video mode) */ + hdrp->palette_type = 1; /* Color or b&w palette type */ + + memset(hdrp->filler, 0, sizeof(hdrp->filler)); /* Padding */ + + /* Initialize the video mode-dependent parameters */ + + switch (vmode) + { + case PCX_HERC: /* 720 x 348 Hercules monochrome */ + + max_width = min(width, 720); /* Maximum image width */ + max_height = min(height, 348); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 720; /* Horizontal resolution */ + hdrp->vert_res = 348; /* Vertical resolution */ + hdrp->nplanes = 1; /* Number of color planes */ + + /* Maximum two pages supported */ + + wbp->page_offset = 0x08000000L * (unsigned long) page; + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_herc; /* Set display capture fcn ptr */ + + break; + + case 0x04: /* 320 x 200 4-color CGA */ + case 0x05: /* 320 x 200 4-color CGA (color burst off) */ + + max_width = min(width, 320); /* Maximum image width */ + max_height = min(height, 200); /* Maximum image height */ + + hdrp->bppixel = 2; /* Bits per pixel */ + hdrp->horz_res = 320; /* Horizontal resolution */ + hdrp->vert_res = 200; /* Vertical resolution */ + hdrp->nplanes = 1; /* Number of color planes */ + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 3) >> 2; + + shift = (max_width & 3) << 1; /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_cga; /* Set display capture fcn ptr */ + + break; + + case 0x06: /* 640 x 200 2-color CGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 200); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 200; /* Vertical resolution */ + hdrp->nplanes = 1; /* Number of color planes */ + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_cga; /* Set display capture fcn ptr */ + + break; + + case 0x0d: /* 320 x 200 16-color EGA/VGA */ + + max_width = min(width, 320); /* Maximum image width */ + max_height = min(height, 200); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 320; /* Horizontal resolution */ + hdrp->vert_res = 200; /* Vertical resolution */ + hdrp->nplanes = 4; /* Number of color planes */ + + /* Maximum eight display pages supported */ + + wbp->page_offset = 0x02000000L * (unsigned long) page; + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x0e: /* 640 x 200 16-color EGA/VGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 200); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 200; /* Vertical resolution */ + hdrp->nplanes = 4; /* Number of color planes */ + + /* Maximum four display pages supported */ + + wbp->page_offset = 0x04000000L * (unsigned long) page; + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x0f: /* 640 x 350 2-color EGA/VGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 350); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 350; /* Vertical resolution */ + hdrp->nplanes = 2; /* Number of color planes */ + + /* Maximum two display pages supported */ + + wbp->page_offset = 0x08000000L * (unsigned long) page; + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x10: /* 640 x 350 16-color EGA/VGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 350); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 350; /* Vertical resolution */ + hdrp->nplanes = 4; /* Number of color planes */ + + /* Maximum two display pages supported */ + + wbp->page_offset = 0x08000000L * (unsigned long) page; + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x11: /* 640 x 480 2-color VGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 480); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 480; /* Vertical resolution */ + hdrp->nplanes = 1; /* Number of color planes */ + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x12: /* 640 x 480 16-color VGA */ + + max_width = min(width, 640); /* Maximum image width */ + max_height = min(height, 480); /* Maximum image height */ + + hdrp->bppixel = 1; /* Bits per pixel */ + hdrp->horz_res = 640; /* Horizontal resolution */ + hdrp->vert_res = 480; /* Vertical resolution */ + hdrp->nplanes = 4; /* Number of color planes */ + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = (max_width + 7) >> 3; + + shift = (max_width & 7); /* Calculate mask shift value */ + + wbp->pcx_funcp = pcx_get_ega; /* Set display capture fcn ptr */ + + break; + + case 0x13: /* 320 x 200 256-color VGA */ + + max_width = min(width, 320); /* Maximum image width */ + max_height = min(height, 200); /* Maximum image height */ + + hdrp->bppixel = 8; /* Bits per pixel */ + hdrp->horz_res = 320; /* Horizontal resolution */ + hdrp->vert_res = 200; /* Vertical resolution */ + hdrp->nplanes = 1; /* Number of color planes */ + + /* Calculate number of bytes to copy */ + + wbp->num_bytes = max_width; + + shift = 0; /* Dummy parameter */ + + wbp->pcx_funcp = pcx_get_vga; /* Set display capture fcn ptr */ + + break; + + default: /* Other modes not supported */ + + status = FALSE; + + break; + } + + /* Initialize common video mode-dependent parameters */ + + hdrp->xlr = max_width - 1; /* Lower right x-position */ + hdrp->ylr = max_height - 1; /* Lower right y-position */ + hdrp->scrn_width = hdrp->horz_res; /* Screen width */ + hdrp->scrn_height = hdrp->vert_res; /* Screen height */ + + /* Calculate mask for "white" data */ + + if (shift != 0) + wbp->mask = 0xff >> shift; + else + wbp->mask = 0x00; + + /* Initialize the file header palette */ + + status = pcx_init_palette(hdrp->palette, vmode); + + /* Calculate number of bytes per color plane scan line (must be an */ + /* even number of bytes) */ + + hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2); + + return (status); +} + +/* + ************************************************************************* + * + * PCX_INIT_PALETTE - Initialize File Header Palette + * + * Purpose: To initialize the file header 16-color palette. + * + * Setup: static BOOL pcx_init_palette + * ( + * PCX_PAL *palettep, + * int vmode + * ) + * + * Where: palettep is a pointer to the PCX file header buffer + * "palette" member. + * vmode is the MS-DOS video mode. Valid values are: + * + * 0x04 - 320 x 200 4-color CGA + * 0x05 - 320 x 200 4-color CGA (color burst off) + * 0x06 - 640 x 200 2-color CGA + * Ox07 - 720 x 348 Hercules monochrome + * 0x0d - 320 x 200 16-color EGA/VGA + * 0x0e - 640 x 200 16-color EGA/VGA + * 0x0f - 640 x 350 2-color EGA/VGA + * 0x10 - 640 x 350 16-color EGA/VGA + * 0x11 - 640 x 480 2-color VGA + * 0x12 - 640 x 480 16-color VGA + * 0x13 - 320 x 200 256-color VGA + * + * Return: TRUE if successful; otherwise FALSE. + * + * Note: The CGA color palette is not supported. + * + * If a VGA display adapter is present, the color palette + * registers can be read directly from the adapter using the + * BIOS routine "Read All Palette Registers" (function 0x09). + * + * Unfortunately, the EGA display adapter color palette + * registers are write-only. This means that the current + * color palette for EGA displays cannot in general be read. + * + * The BIOS routine "Set All Palette Registers" (function + * 0x02) will write the current palette register values to a + * buffer called the Dynamic Save Area. The EGA color + * palette can be read from the first 16 bytes of this 256- + * byte RAM block. + * + * The Dynamic Save Area is not statically allocated; it must + * be supplied by the user. The BIOS video services data in + * segment 0x40 includes a pointer at address 0040:00a8 that + * references the Video Services Primary Pointer Table in the + * EGA/VGA BIOS. This table contains seven pointers, the + * second of which is used by the "Set All Palette Registers" + * routine to reference the Dynamic Save Area. Since the + * Dynamic Save Area does not exist at system initialization, + * the value of this pointer is 0000:0000 (in which case the + * the updated palette register values are not saved to RAM + * when they are updated). + * + * To utilize the EGA palette register save feature, the + * user must perform the following: + * + * 1. Save a copy of the pointer at address 0040:00a8. + * 2. Allocate a buffer for a new Primary Pointer Table. + * 3. Copy the existing Primary Pointer Table to the + * allocated buffer. + * 4. Allocate a 256-byte buffer for a Dynamic Save Area. + * 5. Initialize the second pointer of the Primary Pointer + * Table to point to the Dynamic Save Area buffer. + * + * Before the program finishes, the user must also restore + * the saved Primary Pointer Table pointer to address + * 0040:00a8. Failure to do so will mean that subsequent + * calls by other programs to the "Set All Palette + * Registers" routine will result in the color palette + * registers values being written to unallocated memory (or + * memory that has been allocated for another purpose). + * + * The function "pcx_init_dsa" performs the five steps + * outlined above, while the function "pcx_free_dsa" restores + * the saved pointer on completion of your program. + * + * If the Dynamic Save Area pointer is 0000:0000 (the default + * value at system initialization), the BIOS default color + * palette settings for the appropriate mode are stored in + * the file header color palette. + * + ************************************************************************* + */ + +static BOOL pcx_init_palette +( + PCX_PAL *palettep, + int vmode +) +{ + int i; /* Scratch counter */ + int val; /* Current palette register value */ + int red; /* Temporary value */ + int green; /* Temporary value */ + int blue; /* Temporary value */ + unsigned char *ega_palp; /* EGA/VGA palette buffer pointer */ + unsigned char _far *dsap; /* Dynamic Save Area pointer */ + union REGS regs; /* 80x86 register values */ + struct SREGS sregs; /* 80x86 segment register values */ + + if (vmode < 0x0d || vmode > 0x12) + { + /* Clear the file header palette */ + + memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE); + + return (TRUE); + } + + /* Allocate a 16-color (plus border color) EGA/VGA palette buffer */ + + if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char), + (PCX_PAL_SIZE + 1))) == (unsigned char *) NULL) + return (FALSE); + + if (pcx_isvga() == TRUE) /* Check for VGA display adapter */ + { + /* Read the EGA/VGA palette registers */ + + regs.h.ah = 0x10; /* Select "Read All Palette Registers" routine */ + regs.h.al = 0x09; + + /* Get the EGA/VGA palette buffer offset value */ + + regs.x.dx = (unsigned int) ega_palp; + + segread(&sregs); /* Get the current DS segment register value */ + + sregs.es = sregs.ds; + + int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */ + } + else + { + /* Check for a Dynamic Save Area buffer */ + + dsap = *(*((unsigned char _far * _far * _far *) 0x004000a8L) + 1); + + if (dsap != (unsigned char _far *) NULL) + { + /* Copy the current palette into the local EGA/VGA palette buffer */ + + (void) _fmemcpy((unsigned char _far *) ega_palp, dsap, + PCX_PAL_SIZE); + } + else + { + /* Copy the appropriate default palette settings */ + + switch (vmode) + { + case 0x0d: /* 320 x 200 16-color EGA */ + case 0x0e: /* 640 x 200 16-color EGA */ + + memcpy(ega_palp, pcx_EGA_DefPal_1, PCX_PAL_SIZE); + + break; + + case 0x0f: /* 640 x 350 2-color EGA */ + + memcpy(ega_palp, pcx_EGA_DefPal_2, PCX_PAL_SIZE); + + break; + + case 0x10: /* 640 x 350 16-color EGA */ + + memcpy(ega_palp, pcx_EGA_DefPal_3, PCX_PAL_SIZE); + + break; + + default: /* (Should never reach here) */ + + break; + } + } + + /* Map the EGA/VGA palette to the PCX file header palette */ + + for (i = 0; i < PCX_PAL_SIZE; i++) + { + val = (int) ega_palp[i]; /* Get current color palette value */ + + /* Extract color values */ + + red = ((val & 0x20) >> 5) | ((val & 0x04) >> 1); + green = ((val & 0x10) >> 4) | (val & 0x02); + blue = ((val & 0x08) >> 3) | ((val & 0x01) << 1); + + /* Map each color to a 6-bit value. Only the top two bits are */ + /* significant for EGA displays. The lower four bits (which */ + /* repeat the top two bits) are significant when the image is */ + /* presented on a VGA display emulating an EGA display. */ + + palettep[i].red = (BYTE) ((red << 6) | (red << 4) | (red << 2)); + palettep[i].green = (BYTE) ((green << 6) | (green << 4) | (green << + 2)); + palettep[i].blue = (BYTE) ((blue << 6) | (blue << 4) | (blue << 2)); + } + } + + free(ega_palp); /* Free the EGA/VGA palette buffer */ + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_WRITE_LINE - Write PCX Line + * + * Purpose: To write an image scan line to a PCX-format image file. + * + * Setup: static BOOL pcx_write_line + * ( + * unsigned char *linep, + * int buflen, + * FILE *fp + * ) + * + * Where: linep is a PCX scan line buffer pointer. + * buflen is the length of the image scan line buffer in + * bytes. + * fp is a file pointer. + * + * Return: TRUE if successful; otherwise FALSE. + * + * Note: The PCX scan line buffer is assumed to contain the color + * plane scan lines in sequence, with padding for an even + * number of bytes and trailing "white" data for each line as + * appropriate. + * + ************************************************************************* + */ + +static BOOL pcx_write_line +( + unsigned char *linep, + int buflen, + FILE *fp +) +{ + int curr_data; /* Current data byte */ + int prev_data; /* Previous data byte */ + int data_count; /* Data repeat count */ + int line_count; /* Scan line byte count */ + + prev_data = *linep++; /* Initialize the previous data byte */ + data_count = 1; + line_count = 1; + + while (line_count < buflen) /* Encode scan line */ + { + curr_data = *linep++; /* Get the current data byte */ + line_count++; /* Increment the scan line counter */ + + if (curr_data == prev_data) /* Repeating data bytes ? */ + { + data_count++; /* Increment the data repeat count */ + + /* Check for maximum allowable repeat count */ + + if (data_count == PCX_COMP_MASK) + { + /* Encode the data */ + + if (pcx_encode(prev_data, data_count, fp) == FALSE) + return (FALSE); + + data_count = 0; /* Reset the data repeat count */ + } + } + else /* End of repeating data bytes */ + { + if (data_count > 0) + { + /* Encode the data */ + + if (pcx_encode(prev_data, data_count, fp) == FALSE) + return (FALSE); + } + + prev_data = curr_data; /* Current data byte now previous */ + data_count = 1; + } + } + + if (data_count > 0) /* Any remaining data ? */ + { + /* Encode the data */ + + if (pcx_encode(prev_data, data_count, fp) == FALSE) + return (FALSE); + } + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_ENCODE - Encode Byte Pair + * + * Purpose: To write an encoded byte pair (or a single unencoded + * byte) to a PCX-format image file. + * + * Setup: static BOOL pcx_encode + * ( + * int data, + * int count, + * FILE *fp + * ) + * + * Where: data is the data byte to be encoded (if necessary). + * count is the number of times the data byte is repeated in + * the image data. + * fp is a pointer to the PCX-format file the encoded byte + * pair or single byte is to be written to. + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_encode +( + int data, + int count, + FILE *fp +) +{ + if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1) + { + /* Write the count byte */ + + if (putc(PCX_COMP_FLAG | count, fp) == EOF) + return (FALSE); + } + + /* Write the data byte */ + + if (putc(data, fp) == EOF) + return (FALSE); + + return (TRUE); +} + +/* + ************************************************************************* + * + * PCX_WRITE_EXTPAL - Write Extended Palette + * + * Purpose: To read the current 256-color VGA palette and write an + * equivalent extended PCX palette to a PCX-format image + * file. + * + * Setup: static BOOL pcx_write_extpal + * ( + * FILE *fp + * ) + * + * Where: fp is a file pointer. + * + * Return: TRUE if successful; otherwise FALSE. + * + ************************************************************************* + */ + +static BOOL pcx_write_extpal +( + FILE *fp +) +{ + int i; /* Scratch counter */ + BOOL status = TRUE; /* Return status */ + PCX_PAL *palettep; /* Extended PCX palette buffer pointer */ + unsigned char *vga_palp; /* 256-color VGA palette buffer pointer */ + union REGS regs; /* 80x86 register values */ + struct SREGS sregs; /* 80x86 segment register values */ + + /* Allocate an extended PCX palette buffer */ + + if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) == + (PCX_PAL *) NULL) + return (FALSE); + + /* Allocate a 256-color VGA palette buffer */ + + if ((vga_palp = (unsigned char *) calloc(sizeof(unsigned char), 768)) + == (unsigned char *) NULL) + { + free(palettep); /* Free the extended PCX palette buffer */ + return (FALSE); + } + + /* Read the current VGA palette (DAC registers) */ + + regs.h.ah = 0x10; /* Select "Read DAC Registers" BIOS routine */ + regs.h.al = 0x17; + regs.x.bx = 0; /* Read all 256 DAC registers */ + regs.x.cx = 256; + + /* Get the VGA palette buffer offset value */ + + regs.x.dx = (unsigned int) vga_palp; + + segread(&sregs); /* Get the current DS segment register value */ + + sregs.es = sregs.ds; + + int86x(0x10, ®s, ®s, &sregs); /* Call BIOS video service */ + + /* Map the VGA palette to an extended PCX palette */ + + for (i = 0; i < PCX_EPAL_SIZE; i++) + { + palettep[i].red = (BYTE) (vga_palp[i * 3] << 2); + palettep[i].green = (BYTE) (vga_palp[i * 3 + 1] << 2); + palettep[i].blue = (BYTE) (vga_palp[i * 3 + 2] << 2); + } + + /* Write the extended PCX palette indicator byte to the file */ + + if (status == TRUE) + if (fputc(PCX_EPAL_FLAG, fp) == EOF) + status = FALSE; + + /* Write the extended PCX palette to the file */ + + if (status == TRUE) + if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) != + PCX_EPAL_SIZE) + status = FALSE; + + free(palettep); /* Free the extended PCX palette buffer */ + + free(vga_palp); /* Free the VGA palette buffer */ + + return (status); +} + +/* + ************************************************************************* + * + * PCX_GET_HERC - Get Hercules Scan Line + * + * Purpose: To read a Hercules monochrome graphics display adapter + * scan line into a buffer. + * + * Setup: static void pcx_get_herc + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX workblock pointer. + * linep is a pointer to where the scan line is to be + * returned. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_get_herc +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate Hercules display buffer pointer */ + + displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) + + ((line_num >> 2) * 90) + 0x2000 * (line_num & 3); + + /* Copy data from the Hercules display buffer to the scan line buffer */ + + (void) _fmemcpy(linep, displayp, wbp->num_bytes); + + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] |= wbp->mask; + + /* Pad scan line with "white" data byte (if necessary) */ + + if (wbp->num_bytes & 1) + linep[wbp->num_bytes] = 0xff; +} + +/* + ************************************************************************* + * + * PCX_GET_CGA - Get CGA Scan Line + * + * Purpose: To read a CGA display adapter scan line into a buffer. + * + * Setup: static void pcx_get_cga + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX workblock pointer. + * linep is a pointer to where the scan line is to be + * returned. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_get_cga +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate CGA display buffer pointer */ + + displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80) + + 0x2000 * (line_num & 1); + + /* Copy data from the CGA display buffer to the scan line buffer */ + + (void) _fmemcpy(linep, displayp, wbp->num_bytes); + + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] |= wbp->mask; + + /* Pad scan line with "white" data byte (if necessary) */ + + if (wbp->num_bytes & 1) + linep[wbp->num_bytes] = 0xff; +} + +/* + ************************************************************************* + * + * PCX_GET_EGA - Get EGA/VGA Scan Line + * + * Purpose: To read an EGA/VGA display adapter scan line into a + * buffer. + * + * Setup: static void pcx_get_ega + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX workblock pointer. + * linep is a pointer to where the scan line is to be + * returned. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_get_ega +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + int plane_num; /* EGA/VGA color plane number */ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate buffer pointer */ + + displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) + + line_num * 80; + + /* Copy PCX scan line data from each color plane */ + + for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++) + { + /* Select the current color plane in EGA/VGA Read Mode 0 */ + + outpw(0x03ce, (plane_num << 8) | 0x04); + + /* Copy data from the EGA/VGA display to the scan line buffer */ + + (void) _fmemcpy(linep, displayp, wbp->num_bytes); + + /* Mask off unseen pixels */ + + linep[wbp->num_bytes - 1] |= wbp->mask; + + /* Pad plane scan line with "white" data byte (if necessary) */ + + if (wbp->num_bytes & 1) + linep[wbp->num_bytes] = 0xff; + + linep += wbp->header.bppscan; /* Increment plane offset */ + } + + /* Select EGA/VGA Write Mode 0 with all color planes enabled */ + + outpw(0x03c4, 0x0f02); +} + +/* + ************************************************************************* + * + * PCX_GET_VGA - Get VGA Scan Line + * + * Purpose: To read a VGA display adapter scan line into a buffer. + * + * Setup: static void pcx_get_vga + * ( + * PCX_WORKBLK *wbp, + * unsigned char _far *linep, + * int line_num + * ) + * + * Where: wbp is a PCX workblock pointer. + * linep is a pointer to where the scan line is to be + * returned. + * line_num is the scan line number. + * + ************************************************************************* + */ + +static void pcx_get_vga +( + PCX_WORKBLK *wbp, + unsigned char _far *linep, + int line_num +) +{ + unsigned char _far *displayp; /* Display buffer pointer */ + + /* Calculate buffer pointer */ + + displayp = (unsigned char _far *) 0xa0000000L + line_num * 320; + + /* Copy data from the VGA display buffer to the scan line buffer */ + + (void) _fmemcpy(linep, displayp, wbp->num_bytes); + + /* Pad scan line with "white" data byte (if necessary) */ + + if (wbp->num_bytes & 1) + linep[wbp->num_bytes] = 0xff; +} + diff --git a/16/PCX_LIB/PCX_FMT.DOC b/16/PCX_LIB/PCX_FMT.DOC new file mode 100644 index 00000000..224f58a9 --- /dev/null +++ b/16/PCX_LIB/PCX_FMT.DOC @@ -0,0 +1,941 @@ + + +Ian Ashdown +byHeart Software +620 Ballantree Road +West Vancouver, B.C. +Canada V7S 1W3 + +Issue 1: 91/02/12 +Issue 2: 91/03/27 +Issue 3: 91/08/08 +Issue 4: 91/08/11 + + + + + + + + + + + + PCX Graphics + + by + + Ian Ashdown + byHeart Software + +Looking to add monochrome or full-color bit-mapped graphics to your +application programs? If so, you might consider the PCX graphics file +format. Originally developed in 1982 by ZSoft Corporation for their PC +Paintbrush (R) products, it has become a de facto industry standard for +storing and transferring bit-mapped images on MS-DOS machines. It can +support displays of any resolution using palettes of up to 256 +simultaneous colors, and is very simple to implement. Furthermore, it's +not limited to MS-DOS and OS/2-based machines; the PCX format is +applicable to any environment supporting bit-mapped graphics. + +Today, more commercial programs support ZSoft's PCX format than any +other, including Aldus-Microsoft's Tag Image File Format (TIFF). +However, unlike TIFF with its publicly-available technical +specifications, the PCX file format has never been completely documented. +When ZSoft first created PC Paintbrush, the only video displays they had +to contend with were two monochrome adapters (Hercules and Tecmar) and +the IBM Color Graphics Adapter (CGA). They have since quietly modified +and extended their format on several occasions to support EGA, VGA and +SuperVGA displays. Documentation is scarce, incomplete and sometimes +contradictory. There's a small booklet available from ZSoft that +describes the current version (with several omissions), a sample Pascal +program from their CompuServe forum (GO WINAPB), a few magazine articles, +and chapters in a few books (see the references at the end of this +article). + +Personally, I think it's about time to remedy this situation. The +following is a complete set of technical specifications for the current +version of PCX. All of the information has been derived from printed +information provided by ZSoft and conversations with their Technical +Services department. This is it, folks! We now have formal (if not +exactly official) specifications to work with when including the PCX +graphics file format in our application programs. + +My original plan was to include sample C source code for reading and +writing PCX image files. However, both this article and the source code +grew to the extent that one had to go. If you don't want to develop your +own PCX file handling routines from scratch, PCX_LIB is available through +the CUG Library as CUG Volume #???. It includes fully commented C source +code for reading and writing PCX image files, complete with software +drivers for Hercules, CGA, EGA, and VGA display adapters. + + + + + + + + + + + + + + + + + + + + p. 1 + +PCX Specifications + +The PCX graphics file format (Version 5) is designed to store monochrome +and color bit-mapped images of any resolution with palettes of up to 256 +simultaneous colors. It was originally designed for MS-DOS +microcomputers, but is adaptable to other bit-mapped graphic +environments. A simple but effective byte-oriented, run-length encoding +scheme is used to compress the image data. + +There are two or three sections to a PCX graphics file - a 128-byte +header, the encoded image data (which can be of any length) and an +optional 256-color palette (see Figure 1). This palette is appended to +the file only if the image contains more than 16 colors. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 2 + +1. PCX File Header + +The file header describes the graphical environment in which the image is +to be displayed. The information contained in the header is somewhat +device-dependent in that the PCX file format implicitly assumes the +presence of a standard IBM PC-compatible display adapter. Furthermore, +the specific type and video mode of the adapter needed to display the +image correctly cannot be uniquely determined from the file header +information. It is in general the user's responsibility to ensure that +the correct video mode has been selected before displaying a PCX image. + +The file header structure is shown in Figure 2. A complete description +of each structure member is as follows: + +1.1 PCX Flag + +A constant value (0x0a) that signifies a PCX image file. + +1.2 Version + +Indicates the PCX file format version. It can be one of five values: + + 0 - Version 2.5 of PC Paintbrush. + 2 - Version 2.8 (with palette information). + 3 - Version 2.8 (without palette information). + 4 - PC Paintbrush for Windows (not 3.0). + 5 - Version 3.0 and greater of PC Paintbrush and Paintbrush Plus, + including Publisher's Paintbrush. + +Most commercial programs supporting the PCX file format conform to +Version 5. See Section 3, "Color Palettes", for further information. + +1.3 Encoding (1) + +A constant value (0x01) that indicates run-length encoding was used to +encode and compress the image data. + +1.4 Bits per Pixel + +The number of bits per pixel per color plane (typically 1, 2, 4 or 8). + +1.5 Window + +A structure with the following members: + + Name Bytes Description + + xul 2 Upper left corner horizontal position + yul 2 Upper left corner vertical position + xlr 2 Lower right corner horizontal position + ylr 2 Lower right corner vertical position + +These members describe the position and size of the image within the +display, and are measured in pixels (starting with zero). + + + + + + p. 3 + +1.6 HDPI (2) + +"Horizontal dots per inch". The value represents the horizontal +resolution of the device used to create the image. + +1.7 VDPI (2) + +"Vertical dots per inch". The value represents the vertical resolution +of the device used to create the image. + +1.8 Color Map + +The color palette to be used when displaying an image with 16 or fewer +colors. See Section 3, "Color Palettes", for further information. + +1.9 Reserved + +This member was used to indicate the appropriate MS-DOS video mode in +previous PCX file format versions. It is ignored in Version 5, but +should be set to zero. + +1.10 NPlanes + +The number of color planes used to display the image (typically 1 or 4). +See Section 3, "Color Palettes", for further information. + +1.11 Bytes per Line + +The number of bytes required for a buffer when decoding one color plane +scan line. This value should be an even number (for compatibility with +some existing commercial programs). See Section 2, "Image Encoding and +Decoding", for further information. + +1.12 Palette Info (3) + +A bit-mapped variable indicating how to interpret the color palette. +Only the lowest two bits are significant; the others are ignored. It +can have one of two possible values: + + 0x01 - color or black & white + 0x02 - grayscale + +If the variable is set to 0x02 (grayscale), the color palette must be set +to shades of gray. + +1.13 HScreen Size (4) + +Horizontal screen size in pixels. + +1.14 VScreen Size (4) + +Vertical screen size in pixels. + +1.15 Filler + +Blank space to fill out 128-byte header. All bytes within this member +should be set to zero. + + + p. 4 + +Notes + +1. ZSoft has reserved the right to change the encoding scheme for better + image compression performance in future versions. + +2. Horizontal and vertical resolution for video display adapters is + defined as the total number of displayed pixels for the current video + mode. For scanners, it is defined in terms of dots per inch. (These + values are provided for information only. They are not required for + encoding or decoding PCX image files.) + +3. The "palette info" member of the file header was used in previous + versions of the PCX file format to indicate whether the palette + represented a color or grayscale palette. If it was set to 0x02 (as a + bitmap - the upper 6 bits could be set at random), the file decoding + functions could assume a default grayscale palette if necessary. + However, the palette already had a true (and possibly nonlinear) + grayscale, so the "palette info" member was never really used by + ZSoft. The current PC Paintbrush IV and IV Plus products simply + ignore it. + +4. The "HScreen Size" and "VScreen Size" members were added to Version 5 + of the PCX format to support PC Paintbrush IV Version 1.02 and IV Plus + Version 1.0. Since earlier Version 5 PCX files may contain + uninitialized data in place of these members, ZSoft specifically + recommends that they not be used to determine the appropriate video + mode for displaying the files. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 5 + +2. Image Encoding and Decoding + +The PCX graphics file format considers an image to be a contiguous +sequence (block) of eight-bit bytes representing a bit-mapped raster +display. A simple byte-oriented, run-length encoding (RLE) scheme is +used to compress the display data. When the display is represented by +more than one color plane (such as color images on EGA displays), each +scan line is stored sequentially by color plane. + +The run-length encoding scheme uses a byte pair consisting of a "count" +byte and a following "data" byte to represent sequences of display bytes +with the same value. A count byte is uniquely identified by having its +two most significant bits set; its six least significant bits are used to +represent the count value (1 to 63). The following data byte is the +value that is repeated in the display data the number of times indicated +by the count value. + +Any display data byte which is not part of a sequence of bytes of the +same value and which does not have its two most significant bits set is +stored as itself in the encoded image data. Single display data bytes +with a value of 0xc0 or greater are encoded with a count value of one. + +2.1. Decoding + +Decoding display data from encoded image data is done on a line-by-line +basis. The pixel dimensions of the displayed image are calculated as: + + horz_size = Window.xlr - Window.xul + 1 + +and + + vert_size = Window.ylr - Window.yul + 1 + +The number of bytes required to buffer one complete scan line for all +color planes in sequence is: + + buffer_size = NPlanes * Bytes per Line + +Since there are always an integral number of bytes in the buffer, there +may be unused data at the end of each color plane scan line if the number +of bits per pixel is other than eight. This unused data should be masked +off when transferring the line buffer contents to the video display +adapter memory. + +In theory, each color plane scan line may contain an even or odd number +of bytes. However, some application programs expect an even number of +bytes. ZSoft ensures that their products create PCX files with an even +number of bytes per color plane scan line, and recommends that other +programs do the same for compatibility. Of course, decoding functions +should be able to read files with either an even or odd number of bytes +per color plane scan line. + +Decoding begins with the first scan line and proceeds by examining each +byte of the encoded image data. If the two most significant bits of the +byte are set, the lower six bits indicate how many times the next byte is + + + + + p. 6 + +Decoding begins with the first scan line and proceeds by examining each +byte of the encoded image data. If the two most significant bits of the +byte are set, the lower six bits indicate how many times the next byte is +to be duplicated in the line buffer. If these two bits are not set, the +byte itself is copied (once) to the line buffer. A count is kept of the +number of bytes in the line buffer. The current scan line is complete +when its value equals "buffer_size". + +If the display contains more than one color plane, each plane is decoded +in sequence. The order in which they are decoded is device-dependent. +For instance, the Enhanced Graphics Adapter has four color planes ordered +as blue, green, red and intensity. The beginning of each color plane +scan line within the line buffer is given by: + + offset = plane_number * Bytes per Line + +where "plane_number" is a number between 0 and NPlanes - 1. + +A decoding break occurs at the end of each scan line. That is, an +encoding byte pair can only represent a contiguous sequence of bytes +within the current scan line. However, this is not necessarily true for +color planes. An encoding byte pair may represent a contiguous sequence +of identical bytes that extends across two color planes for one display +image scan line. + +Decoding continues until all scan lines (as indicated by "vert_size") +have been decoded. Some older versions of PC Paintbrush padded the image +with extra (uninitialized) scan lines so that all blocks of scan lines (8 +or 16 lines) read from the file were the same size. The image data was +read until end-of-file was returned. ZSoft no longer uses this +technique, since it conflicts with the appended color palette (see +Subsection 3.3, "VGA 256-Color Palettes"). The extra data read could +also overrun the user's image buffer. + +A sample C function to decode a complete image scan line (all color planes) +from a PCX file is shown in Figure 3. + +2.2. Encoding + +Encoding display image data is also done on a line-by-line basis, +following the order of scan lines stored in the display adapter's memory +buffer. The current scan line is encoded for each color plane on a per- +byte basis. As noted above, ZSoft recommends that all color plane scan +lines be padded if necessary to ensure they contain an even number of +bytes. + +ZSoft also recommends that the data used to pad the last one or two bytes +of a scan line represent white data. Apparently, some application +programs display this data when printing or faxing the files. + +A sample C function to encode a single monochrome or color image scan +line for a PCX file is shown in Figure 4. + + + + + + + + p. 7 + +3. Color Palettes + +The PCX file format supports color palettes of up to 16 colors in the +file header. Larger palettes (up to a maximum of 256 colors) are stored +in an optional color palette that is appended to the encoded image data +portion of the file. + +The file header color palette has two different formats, both designed +for IBM PC-compatible machines. A device-specific palette is used for +Color Graphics Adapters (CGA), and a standard R-G-B palette is used for +Enhanced Graphics Adapters (EGA), Multicolor Graphics Adapters (MCGA), +Video Graphics Adapters (VGA) and extended Video Graphics Adapters +(SuperVGA). + +ZSoft's PC Paintbrush products no longer support the CGA color palette. +The following information is provided only for compatibility with older +PCX files. + +3.1. CGA Color Palettes + +The PCX format supports eight possible CGA color palettes for video modes +4 (320x200 4-color graphics) and 5 (320x200 monochrome graphics, color +burst off). Each palette consists of a background color and three +foreground colors (or shades of grey). The background can be one of 16 +colors, the value for which is stored in the first byte of the PCX file +header Color Map member. Only the upper four bits are significant; the +value must be right-shifted by four bits (or divided by 16) to determine +the appropriate CGA hardware palette register value. + +The foreground color palette is specified by the fourth byte of the Color +Map, which has the following structure: + + Name Bit Description + + Color Burst Enable 7 0 - color + 1 - monochrome + Palette 6 0 - yellow + 1 - white + Intensity 5 0 - dim + 1 - bright + +The lower five bits are ignored. + +Most published descriptions of the ROM BIOS call "Set CGA Palette" +(Interrupt 16, Function 11) document only two palettes, obtainable by +setting register BL to 0x00 or 0x01. This is equivalent to the "Palette" +bit above. However, the palette intensity (equivalent to the "Intensity" +bit above) can be selected using bit 4 of the BL register (0 = dim, 1 = +bright). + +The original CGA display adapter was designed for use with NTSC composite +video monitors and color televisions. The "color burst" is a periodic +burst of a 3.58 MHz signal superimposed on the composite video signal to +synchronize the phase of the monitor's internal 3.58 MHz oscillator. +(Without synchronization, the picture has drifting color bars.) The +presence or absence of the burst determines whether the image is +displayed in color or monochrome. + + + p. 8 + +The "Color Burst Enable" bit above actually indicates whether the MS-DOS +video mode is to be 4 (color) or 5 (monochrome). However, the color +burst signal has no meaning for RGB monitors. Video mode 5 will produce +only two distinct color palettes on CGA displays adapters with RGB +monitors, and three distinct palettes on EGA, VGA and SuperVGA display +adapters emulating a CGA display. + +Under video mode 6 (640 x 200 2-color graphics), the first byte of the +CGA color palette specifies the foreground color (i.e. - the color of +the displayed pixels). + +3.2. EGA/VGA 16-Color Palettes + +The 16-color palette for EGA, MCGA, VGA and SuperVGA displays is an array +of 16 elements, each a structure with the following members: + + Name Bytes Description + + Red 1 Red intensity + Green 1 Green intensity + Blue 1 Blue intensity + +All color map entries are stored as unsigned bytes with values ranging +between 0 and 255. Where display adapters support fewer intensity +levels, the value of each color map entry is interpreted by dividing its +value by 256/n, where n is the number of allowable intensity levels +(typically 2, 4 or 16). + +3.3. VGA 256-Color Palettes + +The 256-color palette for MCGA, VGA and SuperVGA displays is an array of +256 elements, each a structure with the same members as the EGA/VGA 16- +color palette, which is appended to the encoded image data portion of the +file (see Figure 1). It is always preceded by a constant byte flag with +the value 0x0c (12 decimal). + +Only Version 5 PCX-format files support 256-color palettes, and then only +when the image has more than 16 colors. ZSoft recommends the following +technique to determine if a 256-color palette is present: first verify +that the file version number is 5, then count back 769 bytes from the end +of the file. If the value of this byte is not 0x0c, the optional 256- +color palette is not present and the EGA/VGA 16-color file header palette +should be used. + +It is possible that a Version 5 PCX-format file with a valid file header +palette can have the value 0x0c in the 769th byte from the end of the +encoded image data. The above technique would then falsely indicate the +presence of an appended 256-color palette. To avoid this problem, it is +necessary to first decode the image and note the file position where the +encoded image data section ends before counting back 769 bytes from the +end of the file. If the supposed 256-color palette flag is located in +the image data section, then the file header palette should be used +instead. + + + + + + + p. 9 + +3.4. 24-Bit Color + +Future versions of ZSoft's Publisher's Paintbrush will support up to 16.7 +million simultaneous colors. The PCX file format will be based on three +color planes (red, green and blue), with 8 bits per pixel per plane. +There will be no color palette, since the color of each pixel will be +fully specified by the encoded image data. + +3.5. Disabling the Palette + +It is occasionally necessary to disable the color palette of a PCX file +in order to correctly display the image. In other words, the current +(default) setting of the display adapter's palette registers are used. +This can be done by changing the PCX file version number from '5' to '3' +(i.e. - PC Paintbrush Version 2.8 without palette information). The file +decoding functions must then check the file version number and ignore the +color palette if it is set to '3'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 10 + +4. Other Environments + +While the PCX file format was designed for MS-DOS machines, it is +nevertheless possible to display PCX images on other machines. It will +generally be necessary to map the image representation (i.e. - window +dimensions, number of color planes, bits per pixel per plane, and the +color palette) to the capabilities of the display hardware. + +It is also necessary to remember that all information in a PCX-format +file is stored as either 8-bit bytes or 16-bit words. Words are stored +in the big-endian format characteristic of 80x86-based machines. That +is, the eight least significant bits (lower byte) are stored first, +followed by the eight most significant bits (upper byte). If PCX-format +files are transferred to little-endian machines (such as those based on +680x0 and Z8000 processors), the order of bytes within each word will +have to be reversed before they can be interpreted. (This applies to the +file header only, since the encoded image data and optional 256-color +palette are stored as bytes.) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 11 + +References + +Azer, S. [1988]. "Working With PCX Files", Microcornucopia, No. 42 +(July-August), p. 42. + +Lindley, C.A. [1990]. Practical Image Processing in C, John Wiley & Sons +Inc., New York, N.Y. + +Luze, M. [1991]. "Printing PCX Files", C Gazette, Vol. 5:2 (Winter 1990 - +1991), pp. 11-22. + +Phoenix Technologies Ltd. [1989]. System BIOS for IBM PC/XT/AT Computers +and Compatibles, Addison-Wesley, Reading, MA. + +Quirk, K. [1989]. "Translating PCX Files", Dr. Dobb's Journal, Vol. 14:8 +(August), pp. 30-36, 105-108. + +Rimmer, S. [1990]. Bit-Mapped Graphics, Windcrest Books, Blue Ridge +Summit, PA. + +ZSoft Corporation [1988]. PCX Technical Reference Manual Revision 4, +ZSoft Corporation, Marietta, GA. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 12 + +Figures + ++--------------------------------------------+ +| File Header (128 bytes) | ++--------------------------------------------+ +| Encoded Image Data (variable length) | ++--------------------------------------------+ +| Optional Color Palette (769 bytes) | ++--------------------------------------------+ + +Figure 1 - Basic PCX File Format + + +Name Bytes Description + +PCX Flag 1 Constant flag +Version 1 PCX version number +Encoding 1 Run-length encoding flag +Bits per Pixel 1 Number of bits per pixel per plane +Window 8 Window dimensions +HDPI 2 Horizontal image resolution +VDPI 2 Vertical image resolution +Color Map 48 Hardware R-G-B color palette +Reserved 1 (Used to contain video mode) +NPlanes 1 Number of color planes +Bytes per Line 2 Number of bytes per scan line +Palette Info 2 Palette interpretation +HScreen Size 2 Horizontal screen size +VScreen Size 2 Vertical screen size +Filler 54 Initialized filler bytes + +Figure 2 - PCX File Header Structure + + +/* Read an encoded scan line (all color planes) from a */ +/* PCX-format image file and write the decoded data to a scan */ +/* line buffer */ + +void pcx_read_line +( + unsigned char *linep, /* PCX scan line buffer pointer */ + FILE *fp, /* PCX image file pointer */ + int bpline /* # bytes per line (all color planes) */ +) +{ + int data; /* Image data byte */ + int count; /* Image data byte repeat count */ + int offset = 0; /* Scan line buffer offset */ + + while (offset < bpline) /* Decode current scan line */ + { + data = getc(fp); /* Get next byte */ + + /* If top two bits of byte are set, lower six bits show how */ + /* many times to duplicate next byte */ + + + + + p. 13 + + if ((data & 0xc0) == 0xc0) + { + count = data & 0x3f; /* Mask off repeat count */ + data = getc(fp); /* Get next byte */ + memset(linep, data, count); /* Duplicate byte */ + linep += count; + offset += count; + } + else + { + *linep++ = (unsigned char) data; /* Copy byte */ + offset++; + } + } +} + +Figure 3 - Decode PCX Image File Scan Line Function + + +/* Encode a scan line and write it to a PCX file (the line is */ +/* assumed to contain the color plane scan lines in sequence, */ +/* with padding for an even number of bytes and trailing white */ +/* data for each line as appropriate) */ + +void pcx_write_line +( + unsigned char *linep, /* Scan line buffer pointer */ + int length, /* Scan line buffer length (in bytes) */ + FILE *fp /* PCX file pointer */ +) +{ + int curr_data; /* Current data byte */ + int prev_data; /* Previous data byte */ + int data_count; /* Data repeat count */ + int line_count; /* Scan line byte count */ + + prev_data = *linep++; /* Initialize the previous data byte */ + data_count = 1; + line_count = 1; + + while (line_count < length) /* Encode scan line */ + { + curr_data = *linep++; /* Get the current data byte */ + line_count++; /* Increment line byte count */ + + if (curr_data == prev_data) /* Repeating data bytes ? */ + { + data_count++; /* Increment data repeat count */ + + if (data_count == 0x3f) /* Max allowable repeat count ? */ + { + pcx_encode(prev_data, data_count, fp); /* Encode data */ + data_count = 0; + } + } + + + + + p. 14 + + else /* End of repeating data bytes */ + { + if (data_count > 0) + pcx_encode(prev_data, data_count, fp); /* Encode data */ + + prev_data = curr_data; /* Current data byte now prev */ + data_count = 1; + } + } + + if (data_count > 0) /* Any remaining data ? */ + { + pcx_encode(prev_data, data_count, fp); /* Encode data */ + } +} + + +/* Write an encoded byte pair (or single byte) to a file */ + +void pcx_encode +( + int data, /* Data byte */ + int count, /* Data byte repeat count */ + FILE *fp /* PCX file pointer */ +) +{ + if (((data & 0xc0) == 0xc0) || count > 1) + { + putc(0xc0 | count, fp); /* Write count byte */ + } + + putc(data, fp); /* Write data byte */ +} + +Figure 4 - Encode Image Scan Line Functions + + + + + + + + + + + + + + + + + + + + + + + + + p. 15 + diff --git a/16/PCX_LIB/PCX_INT.H b/16/PCX_LIB/PCX_INT.H new file mode 100644 index 00000000..49117783 --- /dev/null +++ b/16/PCX_LIB/PCX_INT.H @@ -0,0 +1,195 @@ +/* + ************************************************************************* + * + * PCX_INT.H - PCX_LIB Library Internal Definitions Include File + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/07 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* DEFINITIONS */ + +#define _PCX_INT_H 1 + +#ifndef _PCX_EXT_H +#include "PCX_EXT.H" /* Get external PCX definitions, etc. */ +#endif + +#define PCX_HERC 0xff /* Hercules 720 x 348 monochrome mode */ + +#define PCX_COMP_FLAG 0xc0 /* Compressed data flag mask */ +#define PCX_COMP_MASK 0x3f /* Data repeat count mask */ + +#define PCX_PAL_MASK 0x03 /* Palette interpretation mask */ +#define PCX_EPAL_FLAG 0x0c /* Extended palette flag */ + +#define PCX_PAL_SIZE 16 /* File header palette size */ +#define PCX_EPAL_SIZE 256 /* Extended palette size */ + +#define PCX_MAXLINESZ 640 /* Maximum PCX line buffer size */ + +/* Color graphics adapter color palette macros */ + +#define PCX_CGA_BKGND(x) (x[0].red >> 4) /* Background color */ +#define PCX_CGA_BURST(x) (x[1].red & 0x80) /* Color burst */ +#define PCX_CGA_SELECT(x) (x[1].red & 0x40) /* Palette selector */ +#define PCX_CGA_INTENSITY(x) (x[1].red & 0x20) /* Intensity */ + +typedef unsigned char BYTE; /* 8-bit data type */ +typedef unsigned int WORD; /* 16-bit data type */ + +/* STRUCTURE DECLARATIONS */ + +typedef struct pcx_pal /* PCX palette array element */ +{ + BYTE red; /* Red intensity */ + BYTE green; /* Green intensity */ + BYTE blue; /* Blue intensity */ +} +PCX_PAL; + +typedef struct pcx_hdr /* PCX file header (Version 5) */ +{ + BYTE pcx_id; /* Always 0x0a for PCX files */ + BYTE version; /* Version number */ + BYTE encoding; /* 1 = PCX run length encoding */ + BYTE bppixel; /* Number of bits/pixel per color plane */ + WORD xul; /* X-position of upper left corner */ + WORD yul; /* Y-position of upper left corner */ + WORD xlr; /* X-position of lower right corner */ + WORD ylr; /* Y-position of lower right corner */ + WORD horz_res; /* Horizontal resolution */ + WORD vert_res; /* Vertical resolution */ + PCX_PAL palette[PCX_PAL_SIZE]; /* Hardware R-G-B palette */ + BYTE reserved; /* Unused in Version 5 */ + BYTE nplanes; /* Number of color planes */ + WORD bppscan; /* Number of bytes per plane scan line */ + WORD palette_type; /* Palette interpretation */ + WORD scrn_width; /* Horizontal screen size in pixels */ + WORD scrn_height; /* Vertical screen size in pixels */ + BYTE filler[54]; /* Padding to fill out 128-byte header */ + + /* Notes: */ + /* */ + /* 1. The "version" member may be one of the following: */ + /* */ + /* 0 - PC Paintbrush Version 2.5 */ + /* 2 - PC Paintbrush Version 2.8 (with palette information) */ + /* 3 - PC Paintbrush Version 2.8 (w/o palette information) */ + /* 4 - PC Paintbrush for Windows (PC Paintbrush Plus for */ + /* Windows and Windows 3.0 Paintbrush use Version 5) */ + /* 5 - PC Paintbrush 3.0 and greater (including PC Paintbrush */ + /* Plus and Publisher's Paintbrush) */ + /* */ + /* 2. ZSoft Corporation has reserved the right to change the */ + /* encoding method in future versions for better image */ + /* compression performance. The "encoding" member value may */ + /* change accordingly. */ + /* */ + /* 3. The value of the "bppixel" member depends on the type of */ + /* video display adapter and its video mode. Typical values */ + /* are 1, 2, 4 and 8. */ + /* */ + /* 4. The "xul", "yul", "xlr" and "ylr" members are zero-based and */ + /* and inclusive values indicating the position of the image on */ + /* the screen. The display functions can ignore this */ + /* information if desired. */ + /* */ + /* 5. The "horz_res" and "vert_res" members refer to the "dots per */ + /* inch" resolution of the scanning device used to create the */ + /* image. For images created on video display adapters, these */ + /* values typically refer to the horizontal and vertical */ + /* resolutions in pixels (e.g. - 640 x 350 for an EGA display). */ + /* */ + /* The display function ignore these members, as some programs */ + /* programs do not bother to initialize them when creating PCX */ + /* image files. */ + /* */ + /* 6. The "palette" member is typically left uninitialized if an */ + /* extended 256-color palette is appended to the PCX image */ + /* file. */ + /* */ + /* 7. The "reserved" member used to contain the MS-DOS video mode */ + /* that the PCX image was intended to be displayed under. This */ + /* member is ignored in Version 5. ZSoft recommends that it be */ + /* set to zero. */ + /* */ + /* 8. The value of the "nplanes" member depends on the type of */ + /* video display adapter and its video mode. Typical values */ + /* are 1, 2, 3 and 4. */ + /* */ + /* 9. The value of the "bppscan" member should be an even number */ + /* (for compatibility with some existing commercial programs.) */ + /* It indicates the number of bytes required to buffer a */ + /* decoded scan line for one color plane. */ + /* */ + /* 10. The "palette_type" member indicates whether the palette */ + /* represents a color or grayscale palette. It is a bit-mapped */ + /* variable (only the lowest two bits are significant; the */ + /* others are ignored) with two possible values: */ + /* */ + /* 0x01 - color or black & white */ + /* 0x02 - grayscale */ + /* */ + /* If "grayscale" is indicated, the file color palette must be */ + /* set to shades of gray. The file decoding functions can then */ + /* either use this palette or assume a default grayscale */ + /* palette if necessary. */ + /* */ + /* PC Paintbrush IV and IV Plus ignore this member. */ + /* */ + /* 11. The "scrn_width" and "scrn_height" members were added for */ + /* PC Paintbrush IV Version 1.02 and IV Plus Version 1.0. They */ + /* may not be initialized in some older Version 5 PCX files, or */ + /* the "scrn_width" member may be initialized with the screen */ + /* height and the "scrn_height" member uninitialized. ZSoft */ + /* recommends that this information be ignored. */ + /* */ + /* 12. ZSoft recommends that the "filler" bytes be set to zero. */ +} +PCX_HDR; + +typedef struct pcx_workblk /* PCX image file workblock */ +{ + /* File header */ + + FILE *fp; /* PCX image file pointer */ + PCX_HDR header; /* PCX image file header */ + PCX_PAL *palettep; /* Color palette pointer */ + BOOL epal_flag; /* Extended color palette flag */ + + /* Image manipulation variables */ + + int num_bytes; /* Number of bytes to display */ + int mask; /* Unseen pixels mask */ + unsigned long page_offset; /* Display page address offset */ + + /* Image manipulation function pointer */ + + void (*pcx_funcp)(struct pcx_workblk *, unsigned char _far *, int); +} +PCX_WORKBLK; + +/* FUNCTIONS PROTOTYPES */ + +extern BOOL pcx_close(PCX_WORKBLK *); + +extern PCX_WORKBLK *pcx_open(char *, BOOL); + diff --git a/16/PCX_LIB/PCX_LIB.BAT b/16/PCX_LIB/PCX_LIB.BAT new file mode 100644 index 00000000..8c6dec6e --- /dev/null +++ b/16/PCX_LIB/PCX_LIB.BAT @@ -0,0 +1,13 @@ +ECHO OFF +REM Batch File To Compile PCX_LIB Demonstration Programs +REM Compiler: Microsoft C V6.0 +ECHO byHeart Software's PCX_LIB Demonstration Programs +ECHO Now compiling source code files ... +cl /c /W4 pcx_comm.c pcx_disp.c pcx_exam.c pcx_file.c rd_demo.c wr_demo.c +ECHO Now linking PCX_EXAM ... +link pcx_exam; +ECHO Now linking RD_DEMO ... +link rd_demo pcx_disp pcx_comm; +ECHO Now linking WR_DEMO ... +link wr_demo pcx_disp pcx_file pcx_comm; + diff --git a/16/PCX_LIB/PCX_LIB.DOC b/16/PCX_LIB/PCX_LIB.DOC new file mode 100644 index 00000000..c6e3e9e5 --- /dev/null +++ b/16/PCX_LIB/PCX_LIB.DOC @@ -0,0 +1,387 @@ +byHeart Software +620 Ballantree Road +West Vancouver, B.C. +Canada V7S 1W3 + +Tel. (604) 922-6148 +Fax. (604) 987-7621 + + + + + + + + + + + + + PCX_LIB Documentation + --------------------- + Version 1.00B + + + by Ian Ashdown, P.Eng. + + + + + + + + + + + + + + + + + + + + + + + + Released into the Public Domain 91/04/01 + +1. Introduction + + PCX_LIB is a library of functions for displaying and storing ZSoft's + Paintbrush (R) PCX-format image files. It was developed expressly + for release into the Public Domain. Fully commented ANSI C source + code is provided for all functions, along with complete technical + specifications for ZSoft's PCX image file format. + + Version 1.00B supports the display and storage of images on MS-DOS + systems equipped with the following display adapters: + + Hercules - monochrome + CGA - Color Graphics Adapter + EGA - Enhanced Graphics Adapter + MCGA - MultiColor Graphics Adapter + VGA - Video Graphics Adapter + + All valid MS-DOS graphic modes are supported. + + SuperVGA and XGA display adapters are not supported in this release. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 1 + +2. DISCLAIMER: + + IN NO EVENT SHALL BYHEART SOFTWARE BE LIABLE FOR ANY DAMAGES + WHATSOEVER INCLUDING, WITHOUT LIMITATION, PERSONAL DAMAGES, DAMAGES + FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS + INFORMATION, OR OTHER PECUNIARY LOSS, ARISING OUT OF THE USE OR + INABILITY TO USE THIS PRODUCT, EVEN IF BYHEART SOFTWARE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 2 + +3. Disk Contents + + The disk includes the following files: + + +3.1. Documentation + + PCX_LIB.DOC - PCX_LIB documentation (this file) + PCX_FMT.DOC - PCX image file format specifications + + +3.2. ANSI C Source Code + + PCX_COMM.C - PCX image file common functions + PCX_DISP.C - PCX image file display functions + PCX_EXAM.C - PCX image file header examination utility + PCX_FILE.C - PCX image capture functions + RD_DEMO.C - PCX image file display demonstration program + WR_DEMO.C - PCX image file capture demonstration program + + PCX_EXT.H - PCX_LIB external definitions include file + PCX_INT.H - PCX_LIB internal definitions include file + + +3.3. MS-DOS Executables + + PCX_EXAM.EXE - PCX image file header examination utility + RD_DEMO.EXE - PCX image file display demonstration program + WR_DEMO.EXE - PCX image file capture demonstration program + + +3.4. Sample PCX Image Files + + TEST_04.PCX - 320 x 200 4-color CGA test image (mode 4) + TEST_06.PCX - 640 x 200 2-color CGA test image (mode 6) + TEST_16.PCX - 640 x 350 16-color EGA test image (mode 16) + TEST_19.PCX - 320 x 200 256-color VGA test image (mode 19) + + +3.5. Miscellaneous + + PCX_LIB.BAT - Microsoft C V6.0 program build batch file + + + + + + + + + + + + + p. 3 + +4. Trying It Out + + Four test images are included on the disk, one each for MS-DOS video + modes 4, 6, 16 and 19. + + +4.1. PCX_EXAM + + PCX_EXAM reads a PCX-format image file and displays a summary of + the information contained in the file header. A full explanation + of this information is presented in PCX_FMT.DOC. + + To run PCX_EXAM with a file (e.g. - "MY_PICT.PCX"), enter: + + PCX_EXAM my_pict.pcx + + +4.2. RD_DEMO + + To display any of these images, enter: + + RD_DEMO test_xx.pcx xx + + where "xx" is the video mode (e.g. - "RD_DEMO test_06.pcx 6"). + Your display adapter must be capable of emulating the specified + video mode in order to display the image. + + Once the image is displayed, press any key to clear the screen and + return to DOS. + + RD_DEMO will also display a PCX-format image if your display + adapter supports its appropriate video mode. For example, to + display a PCX-format image file "MY_PICT.PCX" that was created for + display on 320 x 200 256-color VGA displays, enter: + + RD_DEMO my_pict.pcx 19 + + +4.3. WR_DEMO + + The demonstration program WR_DEMO will first display a PCX-format + image file, then capture the image directly from the display + adapter's memory and create a PCX-format image file called + "PCX_DEMO.PCX". + + To run WR_DEMO, enter: + + WR_DEMO test_xx.pcx xx + + where "xx" is the video mode (e.g. - "WR_DEMO test_06.pcx 6"). + Your display adapter must be capable of emulating the specified + video mode in order to display and capture the image. + + + p. 4 + + Once the image is displayed, WR_DEMO will automatically capture + it and create the file "PCX_DEMO.PCX" before clearing the screen + and returning to DOS. + + WR_DEMO will also display and capture a PCX-format image if your + display adapter supports its appropriate video mode. For example, + to capture a PCX-format image file "MY_PICT.PCX" that was created + for display on 320 x 200 256-color VGA displays, enter: + + WR_DEMO my_pict.pcx 19 + + WR_DEMO captures the entire screen and all color planes, so the + size of the resultant PCX_DEMO.PCX file may be different than the + file it displayed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 5 + +5. Using The Library + + The public functions in PCX_LIB (i.e. - those meant to be called by + application programs) are: + + pcx_read - display a PCX-format image file + pcx_write - capture a displayed image to a PCX-format file + + pcx_isvga - determine whether a display adapter supports + VGA BIOS calls + + pcx_init_dsa - set up BIOS to capture EGA color palette + register updates + pcx_free_dsa - reset BIOS to state before call to + "pcx_inst_dsa" + + All functions are fully and exhaustively documented in the source + code files. Example calls to the public functions may be found in + the source code files RD_DEMO.C and WR_DEMO.C. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + p. 6 + diff --git a/16/PCX_LIB/RD_DEMO.C b/16/PCX_LIB/RD_DEMO.C new file mode 100644 index 00000000..72fce199 --- /dev/null +++ b/16/PCX_LIB/RD_DEMO.C @@ -0,0 +1,169 @@ +/* + ************************************************************************* + * + * RD_DEMO.C - PCX_LIB PCX Image File Read Demonstration Program + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/06 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include +#include +#include "pcx_ext.h" + +/* FORWARD REFERENCES */ + +/* GLOBALS */ + +static char *use_msg[] = /* Program usage message */ +{ + " Synopsis: This public domain program displays a Paintbrush (R) PCX", + "-format\n image file.\n\n Usage: RD_DEMO filename vi", + "deo_mode\n\n where \"filename\" is the name of a PCX-form", + "at image file and\n \"video_mode\" is an MS-DOS video mod", + "e. Valid values are:\n\n 4 - 320 x 200 4-color CGA", + "\n 5 - 320 x 200 4-color CGA (color burst off)\n ", + " 6 - 640 x 200 2-color CGA\n 13 - 320 x ", + "200 16-color EGA/VGA\n 14 - 640 x 200 16-color EGA/VG", + "A\n 15 - 640 x 350 2-color EGA/VGA\n 16", + " - 640 x 350 16-color EGA/VGA\n 17 - 640 x 480 2-co", + "lor VGA\n 18 - 640 x 480 16-color VGA\n ", + " 19 - 320 x 200 256-color VGA\n\n The file must be comp", + "atible with the indicated video mode.\n", + (unsigned char *) NULL +}; + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * MAIN - Executive Function + * + * Purpose: To read and display a PCX-format image file. + * + * Setup: int main + * ( + * int argc, + * char **argv + * ) + * + * Where: argc is the number of command-line arguments. + * argv is a pointer to an array of command-line argument + * strings. + * + * Return: 0 if successful; otherwise 2. + * + * Note: Usage is: + * + * RD_DEMO filename video_mode + * + * where: + * + * filename is the name of a PCX-format image file. + * video_mode is the MS-DOS video mode. Valid values are: + * + * 4 - 320 x 200 4-color CGA + * 5 - 320 x 200 4-color CGA (color burst off) + * 6 - 640 x 200 2-color CGA + * 13 - 320 x 200 16-color EGA/VGA + * 14 - 640 x 200 16-color EGA/VGA + * 15 - 640 x 350 2-color EGA/VGA + * 16 - 640 x 350 16-color EGA/VGA + * 17 - 640 x 480 2-color VGA + * 18 - 640 x 480 16-color VGA + * 19 - 320 x 200 256-color VGA + * + ************************************************************************* + */ + +int main +( + int argc, + char **argv +) +{ + int i; /* Scratch counter */ + int vmode; /* Video mode */ + BOOL status = FALSE; /* Return status */ + + /* Display program title */ + + puts("\nRD_DEMO - PCX Image File Display Demonstration Program\n"); + + if (argc == 3) /* Check for filename and video mode parameters */ + { + vmode = atoi(argv[2]); /* Get the video mode */ + + /* Validate the video mode (must be valid MS-DOS graphics mode) */ + + if ((vmode >= 4 && vmode <= 6) || (vmode >= 13 && vmode <= 19)) + status = TRUE; + } + + if (status == TRUE) + { + if (_setvideomode(vmode) == 0) /* Set the video mode */ + { + /* Report error */ + + fprintf(stderr, + "ERROR: could not set display adapter to mode %d.\n", vmode); + + return (2); + } + + /* Read and display the file (assume video page zero) */ + + if ((status = pcx_read(argv[1], vmode, 0)) == TRUE) + { + while (!kbhit()) /* Wait for a keystroke */ + ; + + (void) getch(); /* Clear the keyboard buffer */ + } + + (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */ + + if (status == FALSE) + { + /* Report error */ + + fprintf(stderr, "\nRD_DEMO - PCX Image File Display Demonstration"); + fprintf(stderr, " Program\n\nERROR: Could not read file %s.\n", + argv[1]); + } + } + else /* Display usage information */ + { + while (use_msg[i] != (unsigned char *) NULL) + fputs(use_msg[i++], stderr); + } + + if (status == TRUE) + return (0); + else + return (2); +} + diff --git a/16/PCX_LIB/RD_DEMO.EXE b/16/PCX_LIB/RD_DEMO.EXE new file mode 100644 index 00000000..02bbae17 Binary files /dev/null and b/16/PCX_LIB/RD_DEMO.EXE differ diff --git a/16/PCX_LIB/TEST_04.PCX b/16/PCX_LIB/TEST_04.PCX new file mode 100644 index 00000000..c5194b29 Binary files /dev/null and b/16/PCX_LIB/TEST_04.PCX differ diff --git a/16/PCX_LIB/TEST_06.PCX b/16/PCX_LIB/TEST_06.PCX new file mode 100644 index 00000000..0d1068cf Binary files /dev/null and b/16/PCX_LIB/TEST_06.PCX differ diff --git a/16/PCX_LIB/TEST_16.PCX b/16/PCX_LIB/TEST_16.PCX new file mode 100644 index 00000000..dabf401d Binary files /dev/null and b/16/PCX_LIB/TEST_16.PCX differ diff --git a/16/PCX_LIB/TEST_19.PCX b/16/PCX_LIB/TEST_19.PCX new file mode 100644 index 00000000..9114e303 Binary files /dev/null and b/16/PCX_LIB/TEST_19.PCX differ diff --git a/16/PCX_LIB/WR_DEMO.C b/16/PCX_LIB/WR_DEMO.C new file mode 100644 index 00000000..9ea6e668 --- /dev/null +++ b/16/PCX_LIB/WR_DEMO.C @@ -0,0 +1,209 @@ +/* + ************************************************************************* + * + * WR_DEMO.C - PCX_LIB PCX Image File Write Demonstration Program + * + * Version: 1.00B + * + * History: 91/02/14 - Created + * 91/04/01 - Release 1.00A + * 91/04/06 - Release 1.00B + * + * Compiler: Microsoft C V6.0 + * + * Author: Ian Ashdown, P.Eng. + * byHeart Software + * 620 Ballantree Road + * West Vancouver, B.C. + * Canada V7S 1W3 + * Tel. (604) 922-6148 + * Fax. (604) 987-7621 + * + * Copyright: Public Domain + * + ************************************************************************* + */ + +/* INCLUDE FILES */ + +#include +#include +#include +#include +#include "pcx_ext.h" + +/* FORWARD REFERENCES */ + +/* GLOBALS */ + +static char *use_msg[] = /* Program usage message */ +{ + " Synopsis: This public domain program displays a Paintbrush (R) PCX", + "-format\n image file, then captures the image directly fr", + "om the display\n and writes it to the file PCX_DEMO.PCX.", + "\n\n Usage: WR_DEMO filename video_mode\n\n where \"", + "filename\" is the name of the PCX-format image file to be\n ", + " written and \"video_mode\" is an MS-DOS video mode. Valid values", + "\n are:\n\n 4 - 320 x 200 4-color CGA\n ", + " 5 - 320 x 200 4-color CGA (color burst off)\n ", + " 6 - 640 x 200 2-color CGA\n 13 - 320 x 200", + " 16-color EGA/VGA\n 14 - 640 x 200 16-color EGA/VGA\n", + " 15 - 640 x 350 2-color EGA/VGA\n 16 ", + "- 640 x 350 16-color EGA/VGA\n 17 - 640 x 480 2-color", + " VGA\n 18 - 640 x 480 16-color VGA\n 19", + " - 320 x 200 256-color VGA\n", + (unsigned char *) NULL +}; + +/* PUBLIC FUNCTIONS */ + +/* + ************************************************************************* + * + * MAIN - Executive Function + * + * Purpose: To write a PCX-format image file. + * + * Setup: int main + * ( + * int argc, + * char **argv + * ) + * + * Where: argc is the number of command-line arguments. + * argv is a pointer to an array of command-line argument + * strings. + * + * Return: 0 if successful; otherwise 2. + * + * Note: Usage is: + * + * WR_DEMO filename video_mode + * + * where: + * + * filename is the name of a PCX-format image file. + * video_mode is the MS-DOS video mode. Valid values are: + * + * 4 - 320 x 200 4-color CGA + * 5 - 320 x 200 4-color CGA (color burst off) + * 6 - 640 x 200 2-color CGA + * 13 - 320 x 200 16-color EGA/VGA + * 14 - 640 x 200 16-color EGA/VGA + * 15 - 640 x 350 2-color EGA/VGA + * 16 - 640 x 350 16-color EGA/VGA + * 17 - 640 x 480 2-color VGA + * 18 - 640 x 480 16-color VGA + * 19 - 320 x 200 256-color VGA + * + ************************************************************************* + */ + +int main +( + int argc, + char **argv +) +{ + int i; /* Scratch counter */ + int vmode; /* Video mode */ + BOOL status = FALSE; /* Return status */ + PCX_VSB *vsbp; /* Video services data save buffer ptr */ + + vsbp = (PCX_VSB *) NULL; /* Initialize video services buffer ptr */ + + /* Display program title */ + + puts("\nWR_DEMO - PCX Image File Write Demonstration Program\n"); + + if (argc == 3) /* Check for filename and video mode parameters */ + { + vmode = atoi(argv[2]); /* Get the video mode */ + + /* Validate the video mode (must be valid MS-DOS graphics mode) */ + + if ((vmode >= 4 && vmode <= 6) || (vmode >= 13 && vmode <= 19)) + status = TRUE; + } + + if (status == TRUE) + { + if (_setvideomode(vmode) == 0) /* Set the video mode */ + { + /* Report error */ + + fprintf(stderr, + "ERROR: could not set display adapter to mode %d.\n", vmode); + + return (2); + } + + if (vmode >= 13 && vmode <= 18) /* EGA-compatible video mode ? */ + { + if (pcx_isvga() == TRUE) /* Is a VGA display present ? */ + { + /* An EGA display adapter is present - instantiate a Dynamic */ + /* Save Area buffer to capture the color palette settings each */ + /* time the palette is updated */ + + status = pcx_init_dsa(&vsbp); + } + } + + if (status == TRUE) + { + /* Read and display the file (assume video page zero) */ + + if ((status = pcx_read(argv[1], vmode, 0)) == TRUE) + { + /* Capture the entire screen as a PCX-format file */ + + status = pcx_write("PCX_DEMO.PCX", vmode, 0, 640, 480); + + (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */ + + if (status == FALSE) + { + /* Report error */ + + fprintf(stderr, + "\nWR_DEMO - PCX Image File Write Demonstration"); + fprintf(stderr, + " Program\n\nERROR: Could not write file %s.\n", argv[1]); + } + } + else + { + (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */ + + /* Report error */ + + fprintf(stderr, "\nWR_DEMO - PCX Image File Write Demonstration"); + fprintf(stderr, " Program\n\nERROR: Could not read file %s.\n", + argv[1]); + } + + /* Free the Dynamic Save Area (if necessary) */ + + if (vsbp != (PCX_VSB *) NULL) + pcx_free_dsa(vsbp); + } + else + { + (void) _setvideomode(_DEFAULTMODE); /* Reset the video mode */ + + fputs("ERROR: out of memory.\n", stderr); /* Report error */ + } + } + else /* Display usage information */ + { + while (use_msg[i] != (unsigned char *) NULL) + fputs(use_msg[i++], stderr); + } + + if (status == TRUE) + return (0); + else + return (2); +} + diff --git a/16/PCX_LIB/WR_DEMO.EXE b/16/PCX_LIB/WR_DEMO.EXE new file mode 100644 index 00000000..8c74b5fd Binary files /dev/null and b/16/PCX_LIB/WR_DEMO.EXE differ diff --git a/16/modex105.zip b/16/modex105.zip new file mode 100644 index 00000000..9457bd98 Binary files /dev/null and b/16/modex105.zip differ diff --git a/16/modex105/ASM.BAT b/16/modex105/ASM.BAT new file mode 100644 index 00000000..2e5785f9 --- /dev/null +++ b/16/modex105/ASM.BAT @@ -0,0 +1 @@ +MASM modex,modex,modex,nul \ No newline at end of file diff --git a/16/modex105/DEMOS/BASIC7/CHARDEMO.BAS b/16/modex105/DEMOS/BASIC7/CHARDEMO.BAS new file mode 100644 index 00000000..627e3278 --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/CHARDEMO.BAS @@ -0,0 +1,164 @@ +DEFINT A-Z +DECLARE SUB PRINT.STRING (Text$, Xpos%, Ypos%, Colour%) +DECLARE FUNCTION MakePal$ (Red%, Green%, Blue%) +DECLARE SUB LOAD.FONT (FontFile$, FontNum%) +DECLARE SUB ERROR.OUT (Text$) + + REM $INCLUDE: 'MODEX.BI' + + REM $INCLUDE: 'UTILS.BI' + +TYPE FONT + SetData AS STRING * 1024 +END TYPE + + +TYPE VGAPalette + PalData AS STRING * 768 +END TYPE + + + ' Alternate form of LOAD_DAC_REGISTERS so we can pass an offset into + ' a String instead of the Address of the String + +DECLARE SUB LOAD.DACS ALIAS "LOAD_DAC_REGISTERS" (BYVAL Addr&, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) + + + ' + 'MODE X DEMO of Multiple Character Sets and Block Color Cycling + ' + 'By Matt Pritchard + ' + +COMMON SHARED CharSet() AS FONT + +DIM Pal AS VGAPalette + + REM $DYNAMIC + +DIM SHARED CharSet(0 TO 3) AS FONT + + + LOAD.FONT "SYSTEM.FNT", 0 + LOAD.FONT "ROM_8x8.FNT", 1 + LOAD.FONT "SPACEAGE.FNT", 2 + + + IF SET.MODEX(Mode320x240) = False THEN + ERROR.OUT "ERROR SETTING MODE X" + END IF + + + A$ = "": B$ = "" + FOR X = 0 TO 31: A$ = A$ + MakePal$(31 - X, X, 0): NEXT X + FOR X = 0 TO 31: A$ = A$ + MakePal$(0, 31 - X, X): NEXT X + FOR X = 0 TO 31: A$ = A$ + MakePal$(X, 0, 31 - X): NEXT X + + FOR X = 0 TO 31: B$ = B$ + MakePal$(31 - X, X, X): NEXT X + FOR X = 0 TO 31: B$ = B$ + MakePal$(X, 31 - X, X): NEXT X + FOR X = 0 TO 31: B$ = B$ + MakePal$(X, X, 31 - X): NEXT X + + Black$ = STRING$(192, 0) + White$ = STRING$(128 * 3, 48) + + Pal1$ = Black$ + A$ + A$ + B$ + B$ + A$ + + LOAD.DACS SSEGADD(Black$), 64, 127, 1 + LOAD.DACS SSEGADD(Black$), 20, 63, 0 + + LOAD.DACS SSEGADD(White$), 128, 255, 0 + + '*** Background *** + + FOR X = 0 TO 319 + FOR Y = 0 TO 239 + IF ((X + Y) AND 1) = 1 THEN SET.POINT X, Y, 64 + X \ 5 ELSE SET.POINT X, Y, 20 + Y \ 6 + NEXT Y + NEXT X + + '*** Draw Font Displays *** + + PRINT.STRING "FONT: SYSTEM.FNT", 11, 7, 15 + PRINT.STRING "FONT: ROM_8x8.FNT", 11, 17, 15 + PRINT.STRING "FONT: SPACEAGE.FNT", 11, 27, 15 + PRINT.STRING "PRESS ANY KEY TO CONTINUE", 8, 29, 14 + + + FOR F = 0 TO 2 + SET.DISPLAY.FONT CharSet(F), 1 + Yp = F * 80 + 10 + FOR Y = 0 TO 96 STEP 32 + FOR X = 0 TO 31 + TGPRINTC 128 + Y + X, X * 10 + 1, Yp, 128 + Y + NEXT X + Yp = Yp + 10 + NEXT Y + NEXT F + + DO + LOOP UNTIL SCAN.KEYBOARD + + Offset = 0 + Restart = 192 + MaxOfs = 192 + 96 * 6 + + Delay = 100 + + Offset2 = 0 + Offset2Dir = 3 + Offset2Min = 192 + Offset2Max = Offset2Min + 192 * 6 + + DO + LOAD.DACS SSEGADD(Pal1$) + Offset, 64, 127, 1 + Offset = Offset + 3 + IF Offset >= MaxOfs THEN Offset = Restart + IF Delay THEN + Delay = Delay - 1 + ELSE + LOAD.DACS SSEGADD(Pal1$) + Offset2, 20, 60, 0 + IF Offset2 = Offset2Max THEN Offset2Dir = -3 + IF Offset2 = Offset2Min THEN Offset2Dir = 3 + Offset2 = Offset2 + Offset2Dir + END IF + + LOOP UNTIL SCAN.KEYBOARD + + ERROR.OUT "DEMO OVER" + +REM $STATIC +SUB ERROR.OUT (Text$) + + SET.VIDEO.MODE 3 + + DOS.PRINT Text$ + + END + +END SUB + +SUB LOAD.FONT (FontFile$, FontNum) STATIC + + IF LEN(DIR$(FontFile$)) = 0 THEN ERROR.OUT "FILE NOT FOUND: " + FontFile$ + + OPEN FontFile$ FOR BINARY AS #1 + + SEEK #1, 1 + GET #1, , CharSet(FontNum) + + CLOSE #1 + +END SUB + +FUNCTION MakePal$ (Red, Green, Blue) STATIC + + MakePal$ = CHR$(Red) + CHR$(Green) + CHR$(Blue) + +END FUNCTION + +SUB PRINT.STRING (Text$, Xpos, Ypos, Colour) + + TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos * 8, Ypos * 8, Colour + +END SUB + diff --git a/16/modex105/DEMOS/BASIC7/MAKE-LIB.BAT b/16/modex105/DEMOS/BASIC7/MAKE-LIB.BAT new file mode 100644 index 00000000..fc0b3b5c --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/MAKE-LIB.BAT @@ -0,0 +1,5 @@ +ECHO ... Building MODEX.QLB for BASIC PDS 7.1 +LIB MODEX -+MODEX,, +LIB MODEX -+UTILS,, +DEL MODEX.BAK +LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\BC7\LIB\QBXQLB.LIB; diff --git a/16/modex105/DEMOS/BASIC7/MODEX.BI b/16/modex105/DEMOS/BASIC7/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/modex105/DEMOS/BASIC7/MODEX.LIB b/16/modex105/DEMOS/BASIC7/MODEX.LIB new file mode 100644 index 00000000..0a0364a3 Binary files /dev/null and b/16/modex105/DEMOS/BASIC7/MODEX.LIB differ diff --git a/16/modex105/DEMOS/BASIC7/MODEX.QLB b/16/modex105/DEMOS/BASIC7/MODEX.QLB new file mode 100644 index 00000000..70d22db3 Binary files /dev/null and b/16/modex105/DEMOS/BASIC7/MODEX.QLB differ diff --git a/16/modex105/DEMOS/BASIC7/TEST6.BAS b/16/modex105/DEMOS/BASIC7/TEST6.BAS new file mode 100644 index 00000000..220a67ba --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/TEST6.BAS @@ -0,0 +1,562 @@ +'File: TEST6.BAS +'Descp.: A Mode "X" demonstration +'Author: Matt Pritchard +'Date: 14 April, 1993 +' +DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%) +DECLARE SUB ERROR.OUT (Message$) +DECLARE FUNCTION GET.KEY% () +DECLARE SUB LOAD.SHAPES () +DECLARE SUB PAGE.DEMO () +DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%) +DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%) +DEFINT A-Z + + +TYPE ShapeType + ImgData AS STRING * 512 + xWidth AS INTEGER + yWidth AS INTEGER +END TYPE + +TYPE Sprite + Xpos AS INTEGER + Ypos AS INTEGER + XDir AS INTEGER + YDir AS INTEGER + Shape AS INTEGER +END TYPE + + +CONST MaxShapes = 32 + + REM $INCLUDE: 'UTILS.BI' + REM $INCLUDE: 'MODEX.BI' + +DIM SHARED Img(32) AS ShapeType +COMMON SHARED Img() AS ShapeType + + + CALL INIT.RANDOM + + CALL LOAD.SHAPES + + CALL DEMO.RES(Mode320x200, 320, 200) + CALL DEMO.RES(Mode320x400, 320, 400) + + CALL DEMO.RES(Mode360x200, 360, 200) + CALL DEMO.RES(Mode360x400, 360, 400) + + CALL DEMO.RES(Mode320x240, 320, 240) + CALL DEMO.RES(Mode320x480, 320, 480) + + CALL DEMO.RES(Mode360x240, 360, 240) + CALL DEMO.RES(Mode360x480, 360, 480) + + CALL PAGE.DEMO + + SET.VIDEO.MODE 3 + DOS.PRINT "THIS MODE X DEMO IS FINISHED" + END + +SUB DEMO.RES (Mode, Xmax, Ymax) + + IF SET.MODEX%(Mode) = 0 THEN + ERROR.OUT "Unable to SET_MODEX" + STR$(Mode) + END IF + + XCenter = Xmax \ 2 + + X1 = 10 + Y1 = 10 + X2 = Xmax - 1 + Y2 = Ymax - 1 + + FOR Z = 0 TO 3 + Colr = 31 - Z * 2 + DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr + DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr + DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr + DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr + NEXT Z + + XChars = Xmax \ 10 + YChars = Ymax \ 10 + + FOR X = 0 TO XChars - 1 + TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7) + DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15 + NEXT X + + FOR Y = 0 TO YChars - 1 + TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7) + DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15 + NEXT Y + + ' Draw Lines + + FOR X = 0 TO 63 + N = 15 + X * .75 + SET.DAC.REGISTER 64 + X, N, N, N + SET.DAC.REGISTER 128 + X, 0, N, N + + DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X + DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X + + NEXT X + TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE + + Y = 60: Gap = 0 + FOR X = 0 TO 9 + FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X + FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X + FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X + Y = Y + Gap + 2 + Gap = Gap + 1 + NEXT X + TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN + + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + SET.POINT X, Y, X + Y + X + Y + NEXT Y + NEXT X + + TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + ERROR.OUT "READ.PIXEL Failure" + END IF + NEXT Y + NEXT X + + + + Msg$ = " This is a MODE X demo " + PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE + Msg$ = "Screen Resolution is by " + Xp = XCenter - (LEN(Msg$) * 4) + PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK + + PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK + PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK + + FOR X = 0 TO 15 + SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3 + DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X + NEXT X + TPRINT.TEXT "Press to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW + + X = GET.KEY% + IF X = KyESC THEN ERROR.OUT "ABORT" + +END SUB + +SUB ERROR.OUT (Message$) + + SET.VIDEO.MODE 3 + DOS.PRINT Message$ + END + +END SUB + +FUNCTION GET.KEY% + + DO + X = SCAN.KEYBOARD + LOOP UNTIL X + + GET.KEY% = X + +END FUNCTION + +SUB LOAD.SHAPES + +DIM Grid(1 TO 32, 1 TO 32) + + FOR Shape = 0 TO MaxShapes - 1 + + FOR Y = 1 TO 32 + FOR X = 1 TO 32 + Grid(X, Y) = 0 + NEXT X + NEXT Y + + Style = RANDOM.INT(6) + Colour = 1 + RANDOM.INT(15) + + SELECT CASE Style + + CASE 0: ' Solid Box + + DO + xWidth = 3 + RANDOM.INT(30) + yWidth = 3 + RANDOM.INT(30) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + CASE 1: ' Hollow Box + + DO + xWidth = 5 + RANDOM.INT(28) + yWidth = 5 + RANDOM.INT(28) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1) + HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1) + + FOR Y = HollowY + 1 TO yWidth - HollowY + FOR X = HollowX + 1 TO xWidth - HollowX + Grid(X, Y) = nil + NEXT X + NEXT Y + + CASE 2: ' Solid Diamond + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + NEXT X + NEXT Y + + + CASE 3: ' Hollow Diamond + + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + sWidth = RANDOM.INT(Centre) + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + IF X + (Centre - Y) >= sWidth THEN + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + END IF + NEXT X + NEXT Y + + CASE 4: ' Ball + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + CASE 5: ' Ball + + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + sWidth = RANDOM.INT(xWidth) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + END SELECT + + Img(Shape).xWidth = xWidth + Img(Shape).yWidth = yWidth + + A$ = STRING$(xWidth * yWidth, nil) + + c = 1 + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + MID$(A$, c, 1) = CHR$(Grid(X, Y)) + c = c + 1 + NEXT X + NEXT Y + + Img(Shape).ImgData = A$ + + + NEXT Shape + +END SUB + +SUB PAGE.DEMO + +CONST MaxSprites = 64 + +DIM Obj(MaxSprites) AS Sprite +DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1) +DIM LastObjects(1) + + ScreenX = 360: ScreenY = 240 + + IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN + ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode) + END IF + + SET.ACTIVE.PAGE 0 + + CLEAR.VGA.SCREEN c.BLACK + + PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK + + DRAW.LINE 10, 18, 350, 18, c.YELLOW + PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK + PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK + PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK + PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK + + PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK + PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK + PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK + + PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK + PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK + PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK + + PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK + PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK + PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK + PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK + PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK + + + FOR X = 0 TO 60 + SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X + SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X + NEXT X + + c = 0: DC = 1 + FOR X = 0 TO ScreenX \ 2 + DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50 + DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50 + c = c + DC + IF c = 0 OR c = 60 THEN DC = -DC + NEXT X + + TPRINT.TEXT "Press to Continue", 72, 190, c.bWHITE + TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN + TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN + + TGPRINTC 43, 80, 204, c.YELLOW + TGPRINTC 45, 200, 204, c.YELLOW + + TGPRINTC 25, 40, 218, c.YELLOW + TGPRINTC 24, 200, 218, c.YELLOW + + COPY.PAGE 0, 1 + COPY.PAGE 0, 2 + + FOR X = 1 TO MaxSprites + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + + Obj(X).Shape = X MOD MaxShapes + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2) + Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2) + + LastX(X, 0) = Obj(X).Xpos + LastX(X, 1) = Obj(X).Xpos + LastY(X, 0) = Obj(X).Ypos + LastY(X, 1) = Obj(X).Ypos + NEXT X + + CurrentPage = 0 + + 'View Shift... + + ViewX = 0 + ViewY = 0 + ViewMax = 3 + ViewCnt = 0 + ViewXD = 1 + ViewYD = 1 + + SetColor = 3: SDir = 1 + PrevColor = 0: PDir = 1 + + VisObjects = MaxSprites \ 2 + LastObjects(0) = 0 + LastObjects(1) = 0 + +DRAW.LOOP: + + + SET.ACTIVE.PAGE CurrentPage + + ' Erase Old Images + + FOR X = 1 TO LastObjects(CurrentPage) + + X1 = LastX(X, CurrentPage) AND &HFFFC + Y1 = LastY(X, CurrentPage) + X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3 + Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1 + + COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1 + + NEXT X + + ' Draw new images + + FOR X = 1 TO VisObjects + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + ' Move Sprite + +REDOX: + NewX = Obj(X).Xpos + Obj(X).XDir + IF NewX < 0 OR NewX + SpriteX > ScreenX THEN + Obj(X).XDir = -Obj(X).XDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOX + END IF + END IF + Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir + +REDOY: + NewY = Obj(X).Ypos + Obj(X).YDir + IF NewY < 0 OR NewY + SpriteY > ScreenY THEN + Obj(X).YDir = -Obj(X).YDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOY + END IF + END IF + Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir + + 'Draw Sprite + + TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY + + LastX(X, CurrentPage) = Obj(X).Xpos + LastY(X, CurrentPage) = Obj(X).Ypos + + NEXT X + + LastObjects(CurrentPage) = VisObjects + + ' Pan Screen Back & Forth + + ViewCnt = ViewCnt + 1 + IF ViewCnt >= ViewMax THEN + ViewX = ViewX + ViewXD + IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD + IF ViewXD < 0 THEN + ViewY = ViewY + ViewYD + IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD + END IF + + SET.WINDOW CurrentPage, ViewX, ViewY + + ViewCnt = 0 + ELSE + SET.DISPLAY.PAGE CurrentPage + END IF + + ' Cycle Colors + + SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor + + SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor + + SetColor = SetColor + SDir + IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir + + PrevColor = PrevColor + PDir + IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir + + CurrentPage = 1 - CurrentPage + + Code = SCAN.KEYBOARD + + IF Code = False THEN GOTO DRAW.LOOP + + IF Code = KyPlus THEN + IF ViewMax < 12 THEN ViewMax = ViewMax + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyMinus THEN + IF ViewMax > 1 THEN ViewMax = ViewMax - 1 + IF ViewCnt >= ViewMax THEN ViewCnt = 0 + GOTO DRAW.LOOP + END IF + + IF Code = KyUp THEN + IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyDown THEN + IF VisObjects > 1 THEN VisObjects = VisObjects - 1 + GOTO DRAW.LOOP + END IF + + +END SUB + +SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB) + + IF LEN(Text$) = 0 THEN EXIT SUB + + PRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB + + +END SUB + +SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF) + + IF LEN(Text$) = 0 THEN EXIT SUB + + TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF + +END SUB + diff --git a/16/modex105/DEMOS/BASIC7/UASM-BC7.BAT b/16/modex105/DEMOS/BASIC7/UASM-BC7.BAT new file mode 100644 index 00000000..5ad67fb5 --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/UASM-BC7.BAT @@ -0,0 +1 @@ +MASM /DFARSTRINGS utils, utils, utils, nul; \ No newline at end of file diff --git a/16/modex105/DEMOS/BASIC7/UTILS.ASM b/16/modex105/DEMOS/BASIC7/UTILS.ASM new file mode 100644 index 00000000..811b8f8e --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/UTILS.ASM @@ -0,0 +1,406 @@ +;======================================================= +;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + +IFDEF FARSTRINGS + + EXTRN stringaddress:far + EXTRN stringlength:far + +ENDIF + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;================= +;DOS_PRINT (Text$) +;================= +; +; Prints Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DW ? ; Address of Text$ Descriptor +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;================== +;DOS_PRINTS (Text$) +;================== +; +; Print Text$ Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;====================== +;SET_VIDEO_MODE (Mode%) +;====================== +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;============== +;SCAN_KEYBOARD% +;============== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + int 16H ; Call Keyboard Driver + jz @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + int 16H ; Get Keycode in AX + + or AL, AL ; Low Byte Set (Ascii?) + jz @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + jmp s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;==================== +;RANDOM_INT (MaxInt%) +;==================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;=========== +;INIT_RANDOM +;=========== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + + +;==================== +;INT_SQR (X%, Round%) +;==================== +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + + +;============ +;TIMER_COUNT& +;============ +; +; Returns the current timer value as an integer/long integer +; + + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX ; use ES to get at data + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Return value in DX:AX + +TIMER_COUNT ENDP + + + END diff --git a/16/modex105/DEMOS/BASIC7/UTILS.BI b/16/modex105/DEMOS/BASIC7/UTILS.BI new file mode 100644 index 00000000..aeafeef4 --- /dev/null +++ b/16/modex105/DEMOS/BASIC7/UTILS.BI @@ -0,0 +1,51 @@ + + ' Misc Constants + +CONST True = -1, False = 0, nil = 0 + + ' Keyboard Codes: Extended + +CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00 +CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400 + +CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000 +CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000 + +CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100 +CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100 + +CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00 +CONST KySIns = &HC200, KySDel = &HC300 + +CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000 +CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300 +CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600 +CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900 +CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400 +CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00 +CONST KyAltY = &H1500, KyAltZ = &H2C00 + + ' Keyboard Codes: Ascii + +CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F +CONST KyPlus = 45, KyMinus = 43 + + ' Color Constants + +CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3 +CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7 +CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11 +CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15 +CONST c.BRIGHT = 8 + + ' From UTILS.ASM + +DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$) +DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$) +DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%) +DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD" +DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%) +DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM" +DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT" +DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%) + diff --git a/16/modex105/DEMOS/C/C_UTILS.ASM b/16/modex105/DEMOS/C/C_UTILS.ASM new file mode 100644 index 00000000..8302561a --- /dev/null +++ b/16/modex105/DEMOS/C/C_UTILS.ASM @@ -0,0 +1,405 @@ +;======================================================= +;=== C_UTILS.ASM - Asm Utilities for C/C++ === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;=========================================== +;void far pascal dos_print (far char *Text) +;=========================================== +; +; - Print Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DD ? ; Far Address of Text to print +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor + + ; Compute Length of string + + CLR CX ; Length = 0 + mov SI, DX ; DS:SI = String data + +@@DP_Scan_it: + + cmp b [SI], 0 ; Null Byte found? + je @@DP_Got_Len ; exit loop if so + + inc CX ; Len++ + inc SI ; Point to next char + jmp s @@DP_Scan_it ; check again... + +@@DP_Got_len: + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 4 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;=========================================== +;void far pascal dos_prints (char far *Text) +;=========================================== +; +; Print Text Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor + + ; Compute Length of string + + CLR CX ; Length = 0 + mov SI, DX ; DS:SI = String data + +@@DPS_Scan_it: + + cmp b [SI], 0 ; Null Byte found? + je @@DPS_Got_Len ; exit loop if so + + inc CX ; Len++ + inc SI ; Point to next char + jmp s @@DPS_Scan_it ; check again... + +@@DPS_Got_len: + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;========================================= +;void far pascal set_video_mode (int Mode) +;========================================= +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;=================================== +;int far pascal scan_keyboard (void) +;=================================== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + INT 16H ; Call Keyboard Driver + JZ @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + INT 16H ; Get Keycode in AX + + OR AL, AL ; Low Byte Set (Ascii?) + JZ @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + JMP s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;======================================== +;int far pascal random_int (int MaxValue) +;======================================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;================================== +;void far pascal init_random (void) +;================================== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + CLR AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + +;========================================= +;int far pascal int_sqr (int X, int Round) +;========================================= +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + +;================================= +;int far pascal timer_count (void) +;================================= +; +; Returns the current timer value as an integer/long integer +; + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + CLR AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Clean Up Stack + +TIMER_COUNT ENDP + + + END diff --git a/16/modex105/DEMOS/C/C_UTILS.H b/16/modex105/DEMOS/C/C_UTILS.H new file mode 100644 index 00000000..ed0e188f --- /dev/null +++ b/16/modex105/DEMOS/C/C_UTILS.H @@ -0,0 +1,117 @@ + +#ifndef __C_UTILS_H +#define __C_UTILS_H + + + /* Misc Constants */ + +#define True -1 +#define False 0 +#define nil 0 + + /* Color Constants */ + +#define c_BLACK 0 +#define c_BLUE 1 +#define c_GREEN 2 +#define c_CYAN 3 +#define c_RED 4 +#define c_PURPLE 5 +#define c_BROWN 6 +#define c_WHITE 7 +#define c_GREY 8 +#define c_bBLUE 9 +#define c_bGREEN 10 +#define c_bCYAN 11 +#define c_bRED 12 +#define c_bPURPLE 13 +#define c_YELLOW 14 +#define c_bWHITE 15 +#define c_BRIGHT 16 + + +#define Ky_F1 0x3B00 +#define Ky_F2 0x3C00 +#define Ky_F3 0x3D00 +#define Ky_F4 0x3E00 +#define Ky_F5 0x3F00 +#define Ky_F6 0x4000 +#define Ky_F7 0x4100 +#define Ky_F8 0x4200 +#define Ky_F9 0x4300 +#define Ky_F10 0x4400 + +#define Ky_Up 0x4800 +#define Ky_Left 0x4B00 +#define Ky_Right 0x4D00 +#define Ky_Down 0x5000 +#define Ky_SUp 0xC800 +#define Ky_SLeft 0xCB00 +#define Ky_SRight 0xCD00 +#define Ky_SDown 0xD000 + +#define Ky_Home 0x4700 +#define Ky_End 0x4F00 +#define Ky_PgUp 0x4900 +#define Ky_PgDn 0x5100 +#define Ky_SHome 0xC700 +#define Ky_SEnd 0xCF00 +#define Ky_SPgUp 0xC900 +#define Ky_SPgDn 0xD100 + +#define Ky_Ins 0x5200 +#define Ky_Del 0x5300 +#define Ky_SIns 0xC200 +#define Ky_SDel 0xC300 + +#define Ky_Tab 0x0009 +#define Ky_RvsTab 0x8F00 +#define Ky_STab 0x8F00 + +#define Ky_BS 0x0008 +#define Ky_CR 0x000D +#define Ky_ESC 0x001B +#define Ky_Clr 0x007F + +#define Ky_Plus 0x002D +#define Ky_Minus 0x002B + +#define Ky_AltA 0x1E00 +#define Ky_AltB 0x3000 +#define Ky_AltC 0x2E00 +#define Ky_AltD 0x2000 +#define Ky_AltE 0x1200 +#define Ky_AltF 0x2100 +#define Ky_AltG 0x2200 +#define Ky_AltH 0x2300 +#define Ky_AltI 0x1700 +#define Ky_AltJ 0x2400 +#define Ky_AltK 0x2500 +#define Ky_AltL 0x2600 +#define Ky_AltM 0x3200 +#define Ky_AltN 0x3100 +#define Ky_AltO 0x1800 +#define Ky_AltP 0x1900 +#define Ky_AltQ 0x1000 +#define Ky_AltR 0x1300 +#define Ky_AltS 0x1F00 +#define Ky_AltT 0x1400 +#define Ky_AltU 0x1600 +#define Ky_AltV 0x2F00 +#define Ky_AltW 0x1100 +#define Ky_AltX 0x2D00 +#define Ky_AltY 0x1500 +#define Ky_AltZ 0x2C00 + + /* .ASM Functions From C_UTILS.ASM */ + +void far pascal dos_print (char far *Text); +void far pascal dos_prints (char far *Text); +void far pascal set_video_mode (int Mode); +int far pascal scan_keyboard (void); +int far pascal random_int (int MaxValue); +void far pascal init_random (void); +int far pascal int_sqr (int X, int Round); +int far pascal timer_count (void); + +#endif \ No newline at end of file diff --git a/16/modex105/DEMOS/C/MODEX.H b/16/modex105/DEMOS/C/MODEX.H new file mode 100644 index 00000000..7de25a63 --- /dev/null +++ b/16/modex105/DEMOS/C/MODEX.H @@ -0,0 +1,76 @@ + +#ifndef __MODEX_H +#define __MODEX_H + + /* ===== SCREEN RESOLUTIONS ===== */ + +#define Mode_320x200 0 +#define Mode_320x400 1 +#define Mode_360x200 2 +#define Mode_360x400 3 +#define Mode_320x240 4 +#define Mode_320x480 5 +#define Mode_360x240 6 +#define Mode_360x480 7 + + /* ===== MODE X SETUP ROUTINES ===== */ + +int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages); +int far pascal set_modex (int Mode); + + /* ===== BASIC GRAPHICS PRIMITIVES ===== */ + +void far pascal clear_vga_screen (int Color); +void far pascal set_point (int Xpos, int Ypos, int Color); +int far pascal read_point (int Xpos, int Ypos); +void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); +void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); + + /* ===== DAC COLOR REGISTER ROUTINES ===== */ + +void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue); +void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue); +void far pascal load_dac_registers (char far *PalData, int StartReg, + int EndReg, int VSync); +void far pascal readd_dac_registers (char far *PalData, int StartReg, + int EndReg); + + /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */ + +void far pascal set_active_page (int PageNo); +int far pascal get_active_page (void); +void far pascal set_display_page (int PageNo); +int far pascal get_display_page (void); +void far pascal set_window (int DisplayPage, int XOffset, int YOffset); +int far pascal get_x_offset (void); +int far pascal get_y_offset (void); +void far pascal sync_display (void); + + /* ===== TEXT DISPLAY ROUTINES ===== */ + +void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF, + int ColorB); +void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF); +void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF, int ColorB); +void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF); +void far pascal set_display_font (char far *FontData, int FontNumber); + + /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */ + +void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); +void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); + + /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */ + +void far pascal copy_page (int SourcePage, int DestPage); +void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2, + int DestPage, int DestX1, int DestY1); + + +#endif diff --git a/16/modex105/DEMOS/C/UTLS-ASM.BAT b/16/modex105/DEMOS/C/UTLS-ASM.BAT new file mode 100644 index 00000000..d996978f --- /dev/null +++ b/16/modex105/DEMOS/C/UTLS-ASM.BAT @@ -0,0 +1 @@ +MASM c_utils, c_utils, c_utils, nul; \ No newline at end of file diff --git a/16/modex105/DEMOS/C/X-DEMO.C b/16/modex105/DEMOS/C/X-DEMO.C new file mode 100644 index 00000000..a5ac59b1 --- /dev/null +++ b/16/modex105/DEMOS/C/X-DEMO.C @@ -0,0 +1,780 @@ +/* X-DEMO.C - a Mode "X" Demo */ +/* By Matt Pritchard, 14 Apr, 1993 */ + +#include +#include + +#include "modex.h" +#include "c_utils.h" + +#define MAX_SHAPES 32 +#define MAX_SPRITES 64 + + /* routines in this file */ + +void demo_res (int, int, int); +int get_key (void); +void error_out (char*); +void load_shapes (void); +int int_sqrt (int, int); +void page_demo (void); + + /* Structures for Sprites */ + +struct Shape +{ + unsigned char Image[512]; + int X_Width; + int Y_Width; +} Img [MAX_SHAPES]; + +struct Sprite +{ + int X_pos; + int Y_pos; + int X_Dir; + int Y_Dir; + int Shape; + int Last_X [2]; + int Last_Y [2]; +} Obj [MAX_SPRITES]; + + + /* MAIN */ + + +int main(int argc, char *argv[]) +{ + + /* if (argc > 0) + { + while (argc > 0) + { + dos_print ("Unknown Argument: "); + dos_print (makefp argv[argc]); + argc--; + } + return (0); + + } + */ + + init_random (); + + load_shapes (); + + demo_res ( Mode_320x200, 320, 200 ); + demo_res ( Mode_320x400, 320, 400 ); + + demo_res ( Mode_360x200, 360, 200 ); + demo_res ( Mode_360x400, 360, 400 ); + + demo_res ( Mode_320x240, 320, 240 ); + demo_res ( Mode_320x480, 320, 480 ); + + demo_res ( Mode_360x240, 360, 240 ); + demo_res ( Mode_360x480, 360, 480 ); + + page_demo (); + + set_video_mode (3); + dos_print ("This Mode X Demo is Finished"); + return (0); + +} + + + /* Demonstrate a given resolution */ + + +void demo_res (int Screen_Mode, int X_max, int Y_max) +{ + +char *Error1 = "Failure while calling SET_MODEX"; +char *Error2 = "Failure during READ_PIXEL test"; + +char *Abort_Msg = "Demo aborted by User"; + +char *Demo_Msg = " This is a MODE X demo "; +char *Scrn_Msg = "Screen Resolution is by "; +char *Cont_Msg = "Press to Continue"; + +char *Line_Msg = "LINE TEST"; +char *Fill_Msg = "FILL TEST"; +char *Pixel_Msg = "PIXEL TEST"; + +char Text[10]; + +int x1, y1, x2, y2 = 0; +int x, y, z = 0; +int X_Center, gap = 0; + + + if (set_modex (Screen_Mode) == 0) + { + error_out (Error1); + } + + X_Center = X_max / 2; + + x1 = 10; + y1 = 10; + x2 = X_max - 1; + y2 = Y_max - 1; + + for (z = 0; z <= 3; z++) + { + y = 31 - z -z; + draw_line (x1+z, y1+z, x2-z, y1+z, y); + draw_line (x1+z, y1+z, x1+z, y2-z, y); + draw_line (x1+z, y2-z, x2-z, y2-z, y); + draw_line (x2-z, y1+z, x2-z, y2-z, y); + } + + for (x = 0; x < (X_max / 10); x++) + { + tgprintc (48 + ((x+1) % 10), x*10+1, 1, 9 + ((x/8) % 7) ); + draw_line (x*10+9, 0, x*10+9, 3, c_bWHITE); + } + + for (y = 0; y < (Y_max / 10); y++) + { + tgprintc (48 + ((y+1) % 10), 1, y*10+1, 9 + ((y/10) % 7) ); + draw_line (0, y*10+9, 3, y*10+9, c_bWHITE); + } + + for (x = 0; x <= 63; x++) + { + z = 15 + (x * 3 / 4); + set_dac_register (64+x, z, z, z); + set_dac_register (128+x, 0, z, z); + + draw_line (103-x, 60, 40+x, 123, 64+x); + draw_line (40, 60+x, 103, 123-x, 128+x); + + } + + tprint_str (Line_Msg, 9, 37, 130, c_BLUE); + + y = 60; + gap = 0; + for (x = 0; x <= 9; x++) + { + fill_block (120, y, 120+x, y+gap, 64+x); + fill_block (140 - (15-x), y, 150+x, y+gap, 230+x); + fill_block (170 - (15-x), y, 170, y+gap, 128+x); + y = y + gap + 2; + gap++; + } + + tprint_str (Fill_Msg, 9, 110, 46, c_GREEN); + + for (x = 190; x <= 250; x+=2) + { + for (y = 60; y <= 122; y+=2) + { + z = (x+x+y+y) & 0xff; + set_point (x, y, z); + } + } + + tprint_str (Pixel_Msg, 10, 182, 130, c_RED); + + for (x = 190; x <= 250; x+=2) + { + for (y = 60; y <= 122; y+=2) + { + z = (x+x+y+y) & 0xff; + if (read_point(x, y) != z) + { + error_out (Error2); + } + } + } + + print_str (Demo_Msg, 23, X_Center - 92, 20, c_bRED, c_BLUE); + + x = X_Center - 124; + print_str (Scrn_Msg, 28, x, 30, c_bGREEN, c_BLACK); + + sprintf (Text, "%3d", X_max); + print_str (Text, 3, x+168, 30, c_bPURPLE, c_BLACK); + + sprintf (Text, "%3d", Y_max); + print_str (Text, 3, x + 224, 30, c_bWHITE, c_BLACK); + + for (x = 0; x <= 15; x++) + { + set_dac_register (230+x, 63-x*4, 0, 15+x*3); + draw_line (30+x, Y_max-6-x, X_max-20-x, Y_max-6-x, 230+x); + } + + tprint_str (Cont_Msg, 27, X_Center - 103, Y_max-18, c_YELLOW); + + if (get_key () == Ky_ESC) + { + error_out (Abort_Msg); + } + + return ; + +} + + + /* Wait for a Keystroke */ + + +int get_key(void) +{ + +int c = 0; + + while (c == 0) + { + c = scan_keyboard (); + } + + return (c); + +} + + + /* Error Handling Routine */ + + +void error_out (char * text) +{ + + set_video_mode (3); + dos_print (text); + exit (EXIT_SUCCESS); + +} + + + /* Routine to generate random sprites */ + + +void load_shapes () +{ + +unsigned char Grid[33][33]; + +char *Error1 = "Bad Shape Selected Error"; + +int Shape; +int x, y, z; +int Style, Color; +int X_Width, Y_Width, Center, S_Width; +int Hollow_X, Hollow_Y; + + for (Shape = 0; Shape < MAX_SHAPES; Shape++) + { + for (y = 0; y <= 32; y++) + { + for (x = 0; x <= 32; x++) + { + Grid[x][y] = c_BLACK; + } + } + + Style = random_int (6); + Color = 1 + random_int (15); + + switch (Style) + + { + /* SOLID BOXES */ + + case 0: + + { + do + { + X_Width = 3 + random_int(30); + Y_Width = 3 + random_int(30); + + } while ( (X_Width * Y_Width) >= 512); + + for (x = 1; x <= X_Width; x++) + { + for (y = 1; y <= Y_Width; y++) + { + Grid[x][y] = Color; + } + } + + break; + + } + /* HOLLOW BOXES */ + + case 1: + + { + do { + X_Width = 6 + random_int(27); + Y_Width = 6 + random_int(27); + } while ( (X_Width * Y_Width) >= 512); + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + Grid[x][y] = Color; + } + } + + Hollow_X = 1 + random_int ((X_Width / 2) -1); + Hollow_Y = 1 + random_int ((Y_Width / 2) -1); + + for (y = Hollow_Y+1; y <= Y_Width-Hollow_Y; y++) + { + for (x = Hollow_X+1; x <= X_Width-Hollow_X; x++) + { + Grid[x][y] = c_BLACK; + } + } + + break; + + } + + /* SOLID DIAMOND */ + + case 2: + + { + + X_Width = 3 + 2 * random_int(10); + Y_Width = X_Width; + Center = X_Width / 2; + + for (y = 0; y <= Center; y++) + { + for (x = 0; x <= y; x++) + { + Grid [Center-x+1][y+1] = Color; + Grid [Center+x+1][y+1] = Color; + Grid [Center-x+1][Y_Width-y] = Color; + Grid [Center+x+1][Y_Width-y] = Color; + } + } + + break; + + } + + /* HOLLOW DIAMOND */ + + case 3: + + { + + X_Width = 3 + 2 * random_int(10); + Y_Width = X_Width; + Center = X_Width / 2; + S_Width = random_int (Center); + + for (y = 0; y <= Center; y++) + { + for (x = 0; x <= y; x++) + { + if ( x+(Center-y) >= S_Width ) + { + Grid [Center-x+1][y+1] = Color; + Grid [Center+x+1][y+1] = Color; + Grid [Center-x+1][Y_Width-y] = Color; + Grid [Center+x+1][Y_Width-y] = Color; + } + } + } + + break; + + } + + /* BALL */ + + case 4: + + { + + X_Width = 7 + 2 * random_int (8); + Y_Width = X_Width; + Center = 1 + X_Width / 2; + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + z = int_sqrt(Center-x, Center-y); + if (z < Center) + { + Grid[x][y] = 150 + Color * 2 + z * 3; + } + } + } + + break; + } + + /* HOLLOW BALLS */ + + case 5: + + { + X_Width = 7 + 2 * random_int (8); + Y_Width = X_Width; + Center = 1 + X_Width / 2; + S_Width = random_int (X_Width); + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + z = int_sqrt(Center-x, Center-y); + if ( (z < Center) && (z >= S_Width) ) + { + Grid[x][y] = 150 + Color * 2 + z * 3; + } + } + } + + + break; + } + + default: + + { + error_out (Error1); + break; + + } + + } + + z = 0; + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + Img[Shape].Image[z] = Grid[x][y]; + z++; + } + } + + Img[Shape].X_Width = X_Width; + Img[Shape].Y_Width = Y_Width; + + } + + return; +} + + + /* Quickie Psuedo Integer Square Root Routine */ + + +int int_sqrt ( int x, int y ) +{ + +int Sqr_Table[12] = {1, 4, 9, 6, 25, 36, 49, 64, 81, 100, 121, 144}; + +int r, d; + + d = (x * x) + (y * y); + r = 0; + + while ( d >= Sqr_Table[r] ) + { + r++; + } + + return (r); + +} + + + /* The Bit Sprite Demo */ + + +void page_demo () +{ + +char *Error1 = "Failure during SET_VGA_MODEX (0, 360, 240, 3) call"; + +int Last_Objects[2], Visible_Objects; + +int Screen_X = 360; +int Screen_Y = 240; + +int x, y, z; +int c, dc; +int x1, y1, x2, y2; + +int Sprite_X, Sprite_Y; +int Current_Page; +int New_X, New_Y; + +int View_X, View_Y, View_Max, View_Cnt, View_XD, View_YD; +int Set_Color, Prev_Color, S_Dir, P_Dir; + +int Demo_Running = True; +int redo, code; + + if (set_vga_modex(Mode_320x200, Screen_X, Screen_Y, 3) == 0) + { + error_out (Error1); + } + + set_active_page (0); + clear_vga_screen (c_BLACK); + + print_str ("This is a Test of the Following Functions:", 99, 10, 9, c_bWHITE, c_BLACK); + + draw_line (10, 18, 350, 18, c_YELLOW); + print_str ("SET_ACTIVE_PAGE", 99, 10, 20, c_bBLUE, c_BLACK); + print_str ("SET_DISPLAY_PAGE", 99, 10, 30, c_GREEN, c_BLACK); + print_str ("SET_DAC_REGISTER", 99, 10, 40, c_RED, c_BLACK); + print_str ("CLEAR_VGA_SCREEN", 99, 10, 50, c_CYAN, c_BLACK); + + print_str ("TDRAW_BITMAP", 99, 10, 60, c_PURPLE, c_BLACK); + print_str ("COPY_PAGE", 99, 10, 70, c_GREEN, c_BLACK); + print_str ("COPY_BITMAP", 99, 10, 80, c_CYAN, c_BLACK); + + print_str ("GPRINTC", 99, 10, 90, c_BLUE, c_BLACK); + print_str ("TGPRINTC", 99, 10, 100, c_GREEN, c_BLACK); + print_str ("SET_WINDOW", 99, 10, 110, c_RED, c_BLACK); + + print_str ("VIRTUAL SCREEN SIZES", 20, 190, 20, c_bBLUE, c_BLACK); + print_str (" SMOOTH SCROLLING", 20, 190, 30, c_GREEN, c_BLACK); + print_str (" SPRITE ANIMATION", 20, 190, 40, c_CYAN, c_BLACK); + print_str (" PAGE FLIPPING", 20, 190, 50, c_RED, c_BLACK); + print_str (" COLOR CYCLING", 20, 190, 60, c_PURPLE, c_BLACK); + + for (x = 0; x <=60; x++) + { + set_dac_register (50 + x, 3 + x, 0, 60 - x); + set_dac_register (150 + x, 3 + x, 0, 60 - x); + } + + c = 0; + dc = 1; + for (x = 0; x <= (Screen_X / 2); x++) + { + draw_line (Screen_X / 2 - 1, Screen_Y / 4, x, Screen_Y - 1, c + 50); + draw_line (Screen_X / 2, Screen_Y / 4, Screen_X - x - 1, Screen_Y - 1, c + 50); + c+= dc; + if ((c == 0) || (c == 60) ) { dc = -dc;} + } + + tprint_str ("Press to Continue", 99, 72, 190, c_bWHITE); + tprint_str ("< > = Faster < > = Slower", 99, 72, 204, c_bGREEN); + tprint_str ("< > = Fewer Shapes < > = More Shapes", 99, 32, 218, c_bCYAN); + + tgprintc (43, 80, 204, c_YELLOW); + tgprintc (45, 200, 204, c_YELLOW); + + tgprintc (25, 40, 218, c_YELLOW); + tgprintc (24, 200, 218, c_YELLOW); + + copy_page (0, 1); + copy_page (0, 2); + + for (x = 0; x < MAX_SPRITES; x++) + { + do { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + + Obj[x].Shape = x % MAX_SHAPES; + + Sprite_X = Img[Obj[x].Shape].X_Width; + Sprite_Y = Img[Obj[x].Shape].Y_Width; + + Obj[x].X_pos = 1 + random_int(Screen_X - Sprite_X - 2); + Obj[x].Y_pos = 1 + random_int(Screen_Y - Sprite_Y - 2); + + Obj[x].Last_X[0] = Obj[x].X_pos; + Obj[x].Last_X[1] = Obj[x].X_pos; + Obj[x].Last_Y[0] = Obj[x].Y_pos; + Obj[x].Last_Y[1] = Obj[x].Y_pos; + + } + + Current_Page = 0; + + View_X = 0; + View_Y = 0; + View_Max = 3; + View_Cnt = 0; + View_XD = 1; + View_YD = 1; + + Set_Color = 3; + S_Dir = 1; + Prev_Color = 0; + P_Dir = 1; + + Visible_Objects = MAX_SPRITES / 2; + Last_Objects[0] = 0; + Last_Objects[1] = 0; + + while (Demo_Running) + { + + set_active_page (Current_Page); + + /* Erase Old Images */ + + for (x = 0; x <= Last_Objects[Current_Page]; x++) + { + z = 2; + y = Obj[x].Shape; + x1 = Obj[x].Last_X[Current_Page]; + y1 = Obj[x].Last_Y[Current_Page]; + x2 = x1 + Img[y].X_Width -1; + y2 = y1 + Img[y].Y_Width -1; + + x1 = x1 & 0xfffc; + x2 = x2 | 0x0003; + + copy_bitmap (z, x1, y1, x2, y2, Current_Page, x1, y1); + } + + /* Draw new images */ + + for (x = 0; x <= Visible_Objects; x++) + { + Sprite_X = Img[Obj[x].Shape].X_Width; + Sprite_Y = Img[Obj[x].Shape].Y_Width; + + /* Move Sprite */ + + do + { + redo = False; + New_X = Obj[x].X_pos + Obj[x].X_Dir; + + if (( New_X < 0 ) || (New_X + Sprite_X > Screen_X) ) + { + Obj[x].X_Dir = -Obj[x].X_Dir; + if (random_int(20) == 1) + { + do + { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + redo = True; + } + } + } while (redo); + Obj[x].X_pos = Obj[x].X_pos + Obj[x].X_Dir; + + + do + { + redo = False; + New_Y = Obj[x].Y_pos + Obj[x].Y_Dir; + + if ( (New_Y < 0) || (New_Y + Sprite_Y > Screen_Y) ) + { + Obj[x].Y_Dir = -Obj[x].Y_Dir; + if (random_int(20) == 1) + { + do + { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + redo = True; + } + } + } while (redo); + + Obj[x].Y_pos = Obj[x].Y_pos + Obj[x].Y_Dir; + + /* Draw Sprite */ + + tdraw_bitmap ((char far*) &Img[Obj[x].Shape], Obj[x].X_pos, Obj[x].Y_pos, Sprite_X, Sprite_Y); + + Obj[x].Last_X[Current_Page] = Obj[x].X_pos; + Obj[x].Last_Y[Current_Page] = Obj[x].Y_pos; + + } + + Last_Objects[Current_Page] = Visible_Objects; + + + /* Pan Screen Back & Forth */ + + View_Cnt++; + if (View_Cnt >= View_Max) + { + View_X+= View_XD; + if ( (View_X == 0) || (View_X == 39) ) {View_XD = -View_XD;} + if (View_XD < 0) + { + View_Y+= View_YD; + if ( (View_Y == 0) || (View_Y == 39) ) {View_YD = -View_YD;} + } + + set_window (Current_Page, View_X, View_Y); + + View_Cnt = 0; + } + else + { + set_display_page (Current_Page); + } + + /* Cycle Colors */ + + set_dac_register (50 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color); + set_dac_register (50 + Set_Color, Set_Color, 10, 63 - Set_Color); + + set_dac_register (150 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color); + set_dac_register (150 + Set_Color, 63, 63, Set_Color); + + Set_Color+= S_Dir; + if ( (Set_Color == 60) || (Set_Color == 0) ) {S_Dir = -S_Dir;} + + Prev_Color+= P_Dir; + if ( (Prev_Color == 60) || (Prev_Color == 0) ) {P_Dir = -P_Dir;} + + /* Check for Keystroke */ + + Current_Page = Current_Page ^ 0x01; + + code = scan_keyboard (); + + if (code == Ky_ESC) {Demo_Running = False;} + + if (code == Ky_Plus) + { + if (View_Max < 12) {View_Max++;} + } + + if (code == Ky_Minus) + { + if (View_Max > 1) {View_Max--;} + if (View_Cnt >= View_Max) {View_Cnt = 0;} + } + + if (code == Ky_Up) + { + if (Visible_Objects < MAX_SPRITES-1) {Visible_Objects++;} + } + + if (code == Ky_Down) + { + if (Visible_Objects > 0) {Visible_Objects--;} + } + + } + +} diff --git a/16/modex105/DEMOS/C/X-DEMO.EXE b/16/modex105/DEMOS/C/X-DEMO.EXE new file mode 100644 index 00000000..7742d145 Binary files /dev/null and b/16/modex105/DEMOS/C/X-DEMO.EXE differ diff --git a/16/modex105/DEMOS/C/X-DEMO.PRJ b/16/modex105/DEMOS/C/X-DEMO.PRJ new file mode 100644 index 00000000..7bc4a069 Binary files /dev/null and b/16/modex105/DEMOS/C/X-DEMO.PRJ differ diff --git a/16/modex105/DEMOS/CHARDEMO.EXE b/16/modex105/DEMOS/CHARDEMO.EXE new file mode 100644 index 00000000..4015bdf1 Binary files /dev/null and b/16/modex105/DEMOS/CHARDEMO.EXE differ diff --git a/16/modex105/DEMOS/PASCAL/TEST5.PAS b/16/modex105/DEMOS/PASCAL/TEST5.PAS new file mode 100644 index 00000000..7cc56bbb --- /dev/null +++ b/16/modex105/DEMOS/PASCAL/TEST5.PAS @@ -0,0 +1,488 @@ +{ ModeX Turbo Pascal Demo Program } +{ Converted to Turbo Pascal by Scott Wyatt } +{ Original program written in QuickBasic by Matt Prichard } +{ Released to the Public Domain } +{ } +{ Thanks to Matt Prichard for his *EXCELLENT* ModeX Library } +{ Additional Comments by Matt Pritchard } + +Uses Crt; + +{$L modex2.obj} { This file is the external ModeX Library .OBJ } +{$F+} + + { Mode Setting Routines } + +Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer; external; +Function SET_MODEX (Mode:integer) : Integer; external; + + { Graphics Primitives } + +Procedure CLEAR_VGA_SCREEN (Color:integer); external; +Procedure SET_POINT (Xpos,Ypos,Color : integer); external; +Function READ_POINT (Xpos,Ypos:integer) : integer; external; +Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external; +Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external; + + { VGA DAC Routines } + +Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external; +Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external; + + { Page and Window Control Routines } + +Procedure SET_ACTIVE_PAGE (PageNo:integer); external; +Function GET_ACTIVE_PAGE : integer; external; +Procedure SET_DISPLAY_PAGE (PageNo:integer); external; +Function GET_DISPLAY_PAGE : integer; external; +Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer); external; +Function GET_X_OFFSET : integer; external; +Function GET_Y_OFFSET : integer; external; +Procedure SYNC_DISPLAY; external; + + { Text Display Routines } + +Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer); external; +Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer); external; +Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer); external; +Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer); external; +Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer); external; + + { Sprite and VGA memory -> Vga memory Copy Routines } + +Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external; +Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external; +Procedure COPY_PAGE (SourcePage,DestPage:integer); external; +Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer); external; + +{$F-} + + +TYPE Sprite = Record + Xpos : INTEGER; + Ypos : INTEGER; + XDir : INTEGER; + YDir : INTEGER; + Shape : INTEGER; + LastX : INTEGER; + LastY : INTEGER; + END; + + +CONST MaxShapes = 32; + Circle_16 : Array[1..16,1..16] of byte = + (( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0), + ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0), + ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0), + ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0), + ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0), + ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0), + ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0), + ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0), + ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0)); + Square_16 : Array[1..16,1..16] of byte = + (( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21)); + Diamond : Array[1..8,1..8] of byte = + (( 0, 0, 0, 22, 22, 0, 0, 0), + ( 0, 0, 22, 22, 22, 22, 0, 0), + ( 0, 22, 22, 0, 0, 22, 22, 0), + ( 22, 22, 0, 0, 0, 0, 22, 22), + ( 22, 22, 0, 0, 0, 0, 22, 22), + ( 0, 22, 22, 0, 0, 22, 22, 0), + ( 0, 0, 22, 22, 22, 22, 0, 0), + ( 0, 0, 0, 22, 22, 0, 0, 0)); + Rectangle : Array[1..8,1..3] of byte = + (( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23)); + + { Global Variables ? } + +Var + XCenter,X1,Y1,X2,Y2,Z,Colr,XChars,YChars,X,Y,N,Gap : Integer; + s : string; + s1 : Array[1..35] of Char; + ch : Char; + obj : Array[1..64] of Sprite; + ScreenX,ScreenY : Integer; + c, dc, SpriteX, SpriteY, CurrentPage, LastPage : Integer; + SetColor, SDir, PrevColor, PDir : Byte; + XView, YView : Integer; + XView_Change, YView_Change : Integer; + Right : Boolean; + Number_Of_Shapes : Byte; + + + { Error Handler - Returns to Text Mode & Displays Error } + +Procedure ERROR_OUT(s : string); + Begin + asm + mov ah,0 + mov al,3 + int 10h + end; + WriteLn(s); + Halt(0); +END; + + { Routine to Print a PASCAL string using Print_Str } + +Procedure Print_Text(s : string; X,Y,BColor,FColor : integer); +Var + s1 : Array[1..135] of Char; + i : byte; +Begin + For i := 1 to Length(s) DO + s1[i] := s[i]; + Print_Str(s1,Length(s),X,Y,BColor,FColor); +End; + + { Routine to Transparently Print a PASCAL string using TPrint_Str } + +Procedure TPrint_Text(s : string; X,Y,Color : integer); +Var + s1 : Array[1..135] of Char; + i : byte; +Begin + For i := 1 to Length(s) DO + s1[i] := s[i]; + TPrint_Str(s1,Length(s),X,Y,Color); +End; + + { Routines to show test patterns for a given mode } + +Procedure Demo_Res(Mode, Xmax, Ymax : integer); +Begin + + Str(mode,s); + If Set_ModeX(Mode) = 0 Then + Error_Out('Unable to SET_MODEX '+s); + Clear_VGA_Screen(0); + + XCenter := Xmax div 2; + X1 := 10; + Y1 := 10; + X2 := Xmax - 1; + Y2 := Ymax - 1; + + FOR Z := 0 TO 3 DO + Begin + Colr := 31 - Z * 2; + Draw_Line(X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr); + Draw_Line(X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr); + Draw_Line(X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr); + Draw_Line(X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr); + End; + + XChars := Xmax div 10; + YChars := Ymax div 10; + + FOR X := 0 TO XChars - 1 DO + Begin + TGPRINTC(48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X div 8) MOD 7)); + DRAW_LINE(X * 10 + 9, 0, X * 10 + 9, 3, 15); + End; + FOR Y := 0 TO YChars - 1 DO + Begin + TGPRINTC(48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y div 10) MOD 7)); + DRAW_LINE(0, Y * 10 + 9, 3, Y * 10 + 9, 15); + End; + + { Test Line Drawing } + + FOR X := 0 TO 63 DO + Begin + N := 15 + ((X * 3) div 4); + SET_DAC_REGISTER(64 + X, N, N, N); + SET_DAC_REGISTER(128 + X, 0, N, N); + DRAW_LINE(103 - X, 60, 40 + X, 123, 64 + X); + DRAW_LINE(40, 60 + X, 103, 123 - X, 128 + X); + End; + s := 'Line Test'; + PRINT_Text(s,37,130,1,0); + + { Test Block Fills } + + Y := 60; + Gap := 0; + FOR X := 0 TO 9 DO + Begin + FILL_BLOCK(120, Y, 120 + X, Y + Gap, 64 + X); + FILL_BLOCK(140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X); + FILL_BLOCK(170 - (15 - X), Y, 170, Y + Gap, 128 + X); + Y := Y + Gap + 2; + Gap := Gap + 1; + End; + s := 'Fill Test'; + Print_Text(s,110, 46, 2,0); + + { Test Pixel Write and Read } + + FOR X := 190 TO 250 DO + FOR Y := 60 TO 122 DO + SET_POINT( X, Y, X + Y + X + Y); + + s := 'Pixel Test'; + Print_Text(s,182, 130, 3,0); + + FOR X := 190 TO 250 DO + FOR Y := 60 TO 122 DO + IF READ_POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + WriteLn('READ_PIXEL Failure'); + + { Display rest of screen } + + s := ' This is a MODE X demo '; + Print_Text(s,XCenter - (Length(s) * 4), 20, 3, 1); + s := 'Screen Resolution is by '; + X := XCenter - (Length(s) * 4); + Print_Text(s,X,30,4,0); + Str(XMax,s); + Print_Text(s, X + 8 * 21, 30, 8, 0); + Str(YMax,s); + Print_Text(s, X + 8 * 28, 30, 15, 0); + + FOR X := 0 TO 15 DO + Begin + SET_DAC_REGISTER( 230 + X, 63 - X * 4, 0, 15 + X * 3); + DRAW_LINE(30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X); + End; + s := 'Press to Continue'; + For x := 1 to length(s) DO + s1[x] := s[x]; + TPrint_Str(s1, length(s), XCenter - (26 * 4), Ymax - 18, 5); + + Ch := ReadKey; + IF Ch = #27 Then + Error_Out('Abort'); + +End; + + + { Initialize Sprites for Sprite Demo } + +Procedure Init_Sprites; +Var i : byte; +Begin + For i := 1 to 64 DO + Begin + Obj[i].XPos := Random(300)+10; + Obj[i].YPos := Random(200)+20; + Obj[i].XDir := Random(10)-5; + Obj[i].YDir := Random(10)-5; + If (Obj[i].XDir = 0) AND (Obj[i].YDir = 0) Then + Begin + Obj[i].XDir := Random(5) + 1; + Obj[i].YDir := Random(5) + 1; + End; + Obj[i].Shape := Random(4)+1; + Obj[i].LastX := obj[i].XPos; + Obj[i].LastY := obj[i].YPos; + End; +End; + +Procedure Set_Sprites(number : byte); +Var i : Byte; +Begin + For i := 1 to number DO + Begin + obj[i].LastX := obj[i].XPos; + obj[i].LastY := obj[i].YPos; + obj[i].XPos := obj[i].XPos + obj[i].XDir; + obj[i].YPos := obj[i].YPos + obj[i].YDir; + If (obj[i].XPos > 335) OR (obj[i].XPos < 5 ) Then + obj[i].XDir := -(obj[i].XDir); + If (obj[i].YPos > 220) OR (obj[i].YPos < 5) Then + obj[i].YDir := -(obj[i].YDir); + End; + For i := 1 to number DO + Case obj[i].Shape of + 1 : TDraw_Bitmap(Circle_16,obj[i].XPos,obj[i].YPos,16,16); + 2 : TDraw_Bitmap(Square_16,obj[i].XPos,obj[i].YPos,16,16); + 3 : TDraw_Bitmap(Diamond,obj[i].XPos,obj[i].YPos,8,8); + 4 : TDraw_Bitmap(Rectangle,obj[i].XPos,obj[i].YPos,3,8); + End; +End; + +Procedure Remove_Sprites(p,number : byte); +Var i : byte; +Begin + For i := 1 to number DO + Copy_Bitmap(2,obj[i].LastX,obj[i].LastY,obj[i].LastX+16,obj[i].LastY+16,p,Obj[i].LastX,Obj[i].LastY); +End; + +Procedure Page_Demo; +Begin + Number_Of_Shapes := 64; + XView_Change := 1; + YView_Change := 1; + XView := 1; + YView := 1; + Right := TRUE; + ScreenX := 360; + ScreenY := 240; + PrevColor := 0; + SetColor := 3; + SDir := 1; + PDir := 1; + Str(0,s); + + IF SET_VGA_MODEX(0, ScreenX, ScreenY, 3) = 0 THEN + ERROR_OUT('Unable to SET_VGA_MODEX' + S); + + SET_ACTIVE_PAGE(0); + CLEAR_VGA_SCREEN(0); + PRINT_TEXT('This is a Test of the Following Functions:', 10, 9, 15, 0); + DRAW_LINE( 10, 18, 350, 18, 4); + Print_Text('SET_ACTIVE_PAGE', 10, 20, 1, 0); + Print_Text('SET_DISPLAY_PAGE', 10, 30, 3,0); + Print_Text('SET_DAC_REGISTER', 10, 40, 3, 0); + Print_Text('CLEAR_VGA_SCREEN', 10, 50, 13, 0); + Print_Text('TDRAW_BITMAP', 10, 60, 14, 0); + Print_Text('COPY_PAGE', 10, 70, 3, 0); + Print_Text('COPY_BITMAP', 10, 80, 13, 0); + Print_Text('GPRINTC', 10, 90, 1, 0); + Print_Text('TGPRINTC', 10, 100, 3, 0); + Print_Text('SYNC_DISPLAY', 10, 110, 3, 0); + Print_Text('SET_WINDOW', 10, 120, 14, 0); + Print_Text('VIRTUAL SCREEN SIZES', 190, 20, 1, 0); + Print_Text(' SMOOTH SCROLLING', 190, 30, 3, 0); + Print_Text(' SPRITE ANIMATION', 190, 40, 13, 0); + Print_Text(' PAGE FLIPPING', 190, 50, 3, 0); + Print_Text(' COLOR CYCLING', 190, 60, 14, 0); + + FOR X := 0 TO 60 DO + Begin + SET_DAC_REGISTER( 50 + X, 3 + X, 0, 60 - X); + SET_DAC_REGISTER( 150 + X, 3 + X, 0, 60 - X); + End; + + c := 0; + DC := 1; + FOR X := 0 TO ScreenX div 2 DO + Begin + DRAW_LINE( ScreenX div 2 - 1, ScreenY div 4, X, ScreenY - 1, c + 50); + DRAW_LINE( ScreenX div 2, ScreenY div 4, ScreenX - X - 1, ScreenY - 1, c + 50); + c := c + DC; + IF (c = 0) OR (c = 60) THEN DC := -DC; + End; + + TPrint_Text('Press to Continue', 82, 190, 15); + TPrint_Text('<+> = Fewer Shapes <-> = More Shapes', 32, 204, 12); + COPY_PAGE( 0, 1); + COPY_PAGE( 0, 2); + + Ch := #0; + CurrentPage := 1; + LastPage := 0; + Set_Sprites(Number_Of_Shapes); + For c := 1 to 4 DO + Set_Dac_Register(19+c,63-(c*10),0,0); + + While Ch <> #27 DO + Begin + Set_Active_Page(currentpage); + Set_Sprites(Number_Of_Shapes); + If Right Then + Begin + XView := XView + XView_Change; + If (XView > 38) OR (XView < 2) Then + Begin + XView_Change := -(XView_Change); + Right := FALSE; + End; + End + Else + Begin + YView := YView + YView_Change; + If (YView > 38) OR (YView < 2) Then + Begin + YView_Change := -(YView_Change); + Right := TRUE; + End; + End; + + Set_Window(currentpage,XView,YView); + Set_Display_Page(currentpage); + Set_Dac_Register(50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor); + Set_Dac_Register(50 + SetColor, SetColor, 10, 63 - SetColor); + Set_Dac_Register(150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor); + Set_Dac_Register(150 + SetColor, 63, 63, SetColor); + SetColor := SetColor + SDir; + IF (SetColor = 60) OR (SetColor = 0) THEN SDir := -SDir; + PrevColor := PrevColor + PDir; + IF (PrevColor = 60) OR (PrevColor = 0) THEN PDir := -PDir; + Remove_Sprites(lastpage,Number_Of_Shapes); + + If Keypressed Then + Begin + Ch := ReadKey; + Case Ch of + '-' : If Number_Of_Shapes > 1 Then + Begin + c := Number_Of_Shapes; + Copy_Bitmap(2,obj[c].XPos,obj[c].YPos,obj[c].XPos+16,obj[c].YPos+16, + currentpage,obj[c].XPos,obj[c].YPos); + Dec(Number_Of_Shapes); + End; + '+' : If Number_Of_Shapes < 64 Then Inc(Number_Of_Shapes); + End; + End; + lastpage := (lastpage+1) MOD 2; + currentpage := (currentpage+1) MOD 2; + End; +END; + + { MAIN ROUTINE - Run Through Demos and Exit } + +Begin + + Randomize; + Init_Sprites; + + Demo_Res(0, 320, 200); + Demo_Res(1, 320, 400); + Demo_Res(2, 360, 200); + Demo_Res(3, 360, 400); + Demo_Res(4, 320, 240); + Demo_Res(5, 320, 480); + Demo_Res(6, 360, 240); + Demo_Res(7, 360, 480); + Page_Demo; + + asm + mov ah,0 + mov al,3 + int 10h + end; + WriteLn('THIS MODE X DEMO IS FINISHED'); + +END. \ No newline at end of file diff --git a/16/modex105/DEMOS/QB45/MAKE-LIB.BAT b/16/modex105/DEMOS/QB45/MAKE-LIB.BAT new file mode 100644 index 00000000..b04876ad --- /dev/null +++ b/16/modex105/DEMOS/QB45/MAKE-LIB.BAT @@ -0,0 +1,5 @@ +ECHO ... Building MODEX.QLB for QUICKBASIC 4.5 +LIB MODEX -+MODEX,, +LIB MODEX -+UTILS,, +DEL MODEX.BAK +LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\QB45\BQLB45.LIB; diff --git a/16/modex105/DEMOS/QB45/MODEX.BI b/16/modex105/DEMOS/QB45/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/modex105/DEMOS/QB45/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/modex105/DEMOS/QB45/MODEX.LIB b/16/modex105/DEMOS/QB45/MODEX.LIB new file mode 100644 index 00000000..7baeb85e Binary files /dev/null and b/16/modex105/DEMOS/QB45/MODEX.LIB differ diff --git a/16/modex105/DEMOS/QB45/MODEX.QLB b/16/modex105/DEMOS/QB45/MODEX.QLB new file mode 100644 index 00000000..90122c13 Binary files /dev/null and b/16/modex105/DEMOS/QB45/MODEX.QLB differ diff --git a/16/modex105/DEMOS/QB45/TEST6A.BAS b/16/modex105/DEMOS/QB45/TEST6A.BAS new file mode 100644 index 00000000..b2487d57 --- /dev/null +++ b/16/modex105/DEMOS/QB45/TEST6A.BAS @@ -0,0 +1,561 @@ +'File: TEST6A.BAS +'Descp.: A Mode "X" demonstration for Quickbasic 4.5 +'Author: Matt Pritchard +'Date: 14 April, 1993 +' +DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%) +DECLARE SUB ERROR.OUT (Message$) +DECLARE FUNCTION GET.KEY% () +DECLARE SUB LOAD.SHAPES () +DECLARE SUB PAGE.DEMO () +DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%) +DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%) +DEFINT A-Z + + +TYPE ShapeType + ImgData AS STRING * 512 + xWidth AS INTEGER + yWidth AS INTEGER +END TYPE + +TYPE Sprite + Xpos AS INTEGER + Ypos AS INTEGER + XDir AS INTEGER + YDir AS INTEGER + Shape AS INTEGER +END TYPE + + +CONST MaxShapes = 32 + + REM $INCLUDE: 'UTILS.BI' + REM $INCLUDE: 'MODEX.BI' + +DIM SHARED Img(32) AS ShapeType +COMMON SHARED Img() AS ShapeType + + + CALL INIT.RANDOM + + CALL LOAD.SHAPES + + CALL DEMO.RES(Mode320x200, 320, 200) + CALL DEMO.RES(Mode320x400, 320, 400) + + CALL DEMO.RES(Mode360x200, 360, 200) + CALL DEMO.RES(Mode360x400, 360, 400) + + CALL DEMO.RES(Mode320x240, 320, 240) + CALL DEMO.RES(Mode320x480, 320, 480) + + CALL DEMO.RES(Mode360x240, 360, 240) + CALL DEMO.RES(Mode360x480, 360, 480) + + CALL PAGE.DEMO + + SET.VIDEO.MODE 3 + DOS.PRINT "THIS MODE X DEMO IS FINISHED" + END + +SUB DEMO.RES (Mode, Xmax, Ymax) + + IF SET.MODEX%(Mode) = 0 THEN + ERROR.OUT "Unable to SET_MODEX" + STR$(Mode) + END IF + + XCenter = Xmax \ 2 + + X1 = 10 + Y1 = 10 + X2 = Xmax - 1 + Y2 = Ymax - 1 + + FOR Z = 0 TO 3 + Colr = 31 - Z * 2 + DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr + DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr + DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr + DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr + NEXT Z + + XChars = Xmax \ 10 + YChars = Ymax \ 10 + + FOR X = 0 TO XChars - 1 + TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7) + DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15 + NEXT X + + FOR Y = 0 TO YChars - 1 + TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7) + DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15 + NEXT Y + + ' Draw Lines + + FOR X = 0 TO 63 + N = 15 + X * .75 + SET.DAC.REGISTER 64 + X, N, N, N + SET.DAC.REGISTER 128 + X, 0, N, N + + DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X + DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X + + NEXT X + TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE + + Y = 60: Gap = 0 + FOR X = 0 TO 9 + FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X + FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X + FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X + Y = Y + Gap + 2 + Gap = Gap + 1 + NEXT X + TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN + + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + SET.POINT X, Y, X + Y + X + Y + NEXT Y + NEXT X + + TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + ERROR.OUT "READ.PIXEL Failure" + END IF + NEXT Y + NEXT X + + + + Msg$ = " This is a MODE X demo " + PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE + Msg$ = "Screen Resolution is by " + Xp = XCenter - (LEN(Msg$) * 4) + PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK + + PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK + PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK + + FOR X = 0 TO 15 + SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3 + DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X + NEXT X + TPRINT.TEXT "Press to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW + + X = GET.KEY% + IF X = KyESC THEN ERROR.OUT "ABORT" + +END SUB + +SUB ERROR.OUT (Message$) + + SET.VIDEO.MODE 3 + DOS.PRINT Message$ + END + +END SUB + +FUNCTION GET.KEY% + + DO + X = SCAN.KEYBOARD + LOOP UNTIL X + + GET.KEY% = X + +END FUNCTION + +SUB LOAD.SHAPES + +DIM Grid(1 TO 32, 1 TO 32) + + FOR Shape = 0 TO MaxShapes - 1 + + FOR Y = 1 TO 32 + FOR X = 1 TO 32 + Grid(X, Y) = 0 + NEXT X + NEXT Y + + Style = RANDOM.INT(6) + Colour = 1 + RANDOM.INT(15) + + SELECT CASE Style + + CASE 0: ' Solid Box + + DO + xWidth = 3 + RANDOM.INT(30) + yWidth = 3 + RANDOM.INT(30) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + CASE 1: ' Hollow Box + + DO + xWidth = 5 + RANDOM.INT(28) + yWidth = 5 + RANDOM.INT(28) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1) + HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1) + + FOR Y = HollowY + 1 TO yWidth - HollowY + FOR X = HollowX + 1 TO xWidth - HollowX + Grid(X, Y) = nil + NEXT X + NEXT Y + + CASE 2: ' Solid Diamond + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + NEXT X + NEXT Y + + + CASE 3: ' Hollow Diamond + + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + sWidth = RANDOM.INT(Centre) + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + IF X + (Centre - Y) >= sWidth THEN + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + END IF + NEXT X + NEXT Y + + CASE 4: ' Ball + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + CASE 5: ' Ball + + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + sWidth = RANDOM.INT(xWidth) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + END SELECT + + Img(Shape).xWidth = xWidth + Img(Shape).yWidth = yWidth + + A$ = STRING$(xWidth * yWidth, nil) + + c = 1 + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + MID$(A$, c, 1) = CHR$(Grid(X, Y)) + c = c + 1 + NEXT X + NEXT Y + + Img(Shape).ImgData = A$ + + + NEXT Shape + +END SUB + +SUB PAGE.DEMO + +CONST MaxSprites = 64 + +DIM Obj(MaxSprites) AS Sprite +DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1) +DIM LastObjects(1) + + ScreenX = 360: ScreenY = 240 + + IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN + ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode) + END IF + + SET.ACTIVE.PAGE 0 + + CLEAR.VGA.SCREEN c.BLACK + + PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK + + DRAW.LINE 10, 18, 350, 18, c.YELLOW + PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK + PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK + PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK + PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK + + PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK + PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK + PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK + + PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK + PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK + PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK + + PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK + PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK + PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK + PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK + PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK + + + FOR X = 0 TO 60 + SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X + SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X + NEXT X + + c = 0: DC = 1 + FOR X = 0 TO ScreenX \ 2 + DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50 + DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50 + c = c + DC + IF c = 0 OR c = 60 THEN DC = -DC + NEXT X + + TPRINT.TEXT "Press to Continue", 72, 190, c.bWHITE + TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN + TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN + + TGPRINTC 43, 80, 204, c.YELLOW + TGPRINTC 45, 200, 204, c.YELLOW + + TGPRINTC 25, 40, 218, c.YELLOW + TGPRINTC 24, 200, 218, c.YELLOW + + COPY.PAGE 0, 1 + COPY.PAGE 0, 2 + + FOR X = 1 TO MaxSprites + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + + Obj(X).Shape = X MOD MaxShapes + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2) + Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2) + + LastX(X, 0) = Obj(X).Xpos + LastX(X, 1) = Obj(X).Xpos + LastY(X, 0) = Obj(X).Ypos + LastY(X, 1) = Obj(X).Ypos + NEXT X + + CurrentPage = 0 + + 'View Shift... + + ViewX = 0 + ViewY = 0 + ViewMax = 3 + ViewCnt = 0 + ViewXD = 1 + ViewYD = 1 + + SetColor = 3: SDir = 1 + PrevColor = 0: PDir = 1 + + VisObjects = MaxSprites \ 2 + LastObjects(0) = 0 + LastObjects(1) = 0 + +DRAW.LOOP: + + + SET.ACTIVE.PAGE CurrentPage + + ' Erase Old Images + + FOR X = 1 TO LastObjects(CurrentPage) + + X1 = LastX(X, CurrentPage) AND &HFFFC + Y1 = LastY(X, CurrentPage) + X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3 + Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1 + + COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1 + + NEXT X + + ' Draw new images + + FOR X = 1 TO VisObjects + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + ' Move Sprite + +REDOX: + NewX = Obj(X).Xpos + Obj(X).XDir + IF NewX < 0 OR NewX + SpriteX > ScreenX THEN + Obj(X).XDir = -Obj(X).XDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOX + END IF + END IF + Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir + +REDOY: + NewY = Obj(X).Ypos + Obj(X).YDir + IF NewY < 0 OR NewY + SpriteY > ScreenY THEN + Obj(X).YDir = -Obj(X).YDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOY + END IF + END IF + Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir + + 'Draw Sprite + + TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY + + LastX(X, CurrentPage) = Obj(X).Xpos + LastY(X, CurrentPage) = Obj(X).Ypos + + NEXT X + + LastObjects(CurrentPage) = VisObjects + + ' Pan Screen Back & Forth + + ViewCnt = ViewCnt + 1 + IF ViewCnt >= ViewMax THEN + ViewX = ViewX + ViewXD + IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD + IF ViewXD < 0 THEN + ViewY = ViewY + ViewYD + IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD + END IF + + SET.WINDOW CurrentPage, ViewX, ViewY + + ViewCnt = 0 + ELSE + SET.DISPLAY.PAGE CurrentPage + END IF + + ' Cycle Colors + + SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor + + SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor + + SetColor = SetColor + SDir + IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir + + PrevColor = PrevColor + PDir + IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir + + CurrentPage = 1 - CurrentPage + + Code = SCAN.KEYBOARD + + IF Code = False THEN GOTO DRAW.LOOP + + IF Code = KyPlus THEN + IF ViewMax < 12 THEN ViewMax = ViewMax + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyMinus THEN + IF ViewMax > 1 THEN ViewMax = ViewMax - 1 + IF ViewCnt >= ViewMax THEN ViewCnt = 0 + GOTO DRAW.LOOP + END IF + + IF Code = KyUp THEN + IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyDown THEN + IF VisObjects > 1 THEN VisObjects = VisObjects - 1 + GOTO DRAW.LOOP + END IF + + +END SUB + +SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB) + + IF LEN(Text$) = 0 THEN EXIT SUB + PRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB + + +END SUB + +SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF) + + IF LEN(Text$) = 0 THEN EXIT SUB + + TPRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF + +END SUB + diff --git a/16/modex105/DEMOS/QB45/TEST6A.EXE b/16/modex105/DEMOS/QB45/TEST6A.EXE new file mode 100644 index 00000000..e61d0387 Binary files /dev/null and b/16/modex105/DEMOS/QB45/TEST6A.EXE differ diff --git a/16/modex105/DEMOS/QB45/UASM-QB4.BAT b/16/modex105/DEMOS/QB45/UASM-QB4.BAT new file mode 100644 index 00000000..e4aa87e0 --- /dev/null +++ b/16/modex105/DEMOS/QB45/UASM-QB4.BAT @@ -0,0 +1 @@ +MASM utils, utils, utils, nul; \ No newline at end of file diff --git a/16/modex105/DEMOS/QB45/UTILS.ASM b/16/modex105/DEMOS/QB45/UTILS.ASM new file mode 100644 index 00000000..811b8f8e --- /dev/null +++ b/16/modex105/DEMOS/QB45/UTILS.ASM @@ -0,0 +1,406 @@ +;======================================================= +;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + +IFDEF FARSTRINGS + + EXTRN stringaddress:far + EXTRN stringlength:far + +ENDIF + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;================= +;DOS_PRINT (Text$) +;================= +; +; Prints Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DW ? ; Address of Text$ Descriptor +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;================== +;DOS_PRINTS (Text$) +;================== +; +; Print Text$ Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;====================== +;SET_VIDEO_MODE (Mode%) +;====================== +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;============== +;SCAN_KEYBOARD% +;============== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + int 16H ; Call Keyboard Driver + jz @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + int 16H ; Get Keycode in AX + + or AL, AL ; Low Byte Set (Ascii?) + jz @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + jmp s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;==================== +;RANDOM_INT (MaxInt%) +;==================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;=========== +;INIT_RANDOM +;=========== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + + +;==================== +;INT_SQR (X%, Round%) +;==================== +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + + +;============ +;TIMER_COUNT& +;============ +; +; Returns the current timer value as an integer/long integer +; + + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX ; use ES to get at data + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Return value in DX:AX + +TIMER_COUNT ENDP + + + END diff --git a/16/modex105/DEMOS/QB45/UTILS.BI b/16/modex105/DEMOS/QB45/UTILS.BI new file mode 100644 index 00000000..aeafeef4 --- /dev/null +++ b/16/modex105/DEMOS/QB45/UTILS.BI @@ -0,0 +1,51 @@ + + ' Misc Constants + +CONST True = -1, False = 0, nil = 0 + + ' Keyboard Codes: Extended + +CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00 +CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400 + +CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000 +CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000 + +CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100 +CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100 + +CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00 +CONST KySIns = &HC200, KySDel = &HC300 + +CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000 +CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300 +CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600 +CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900 +CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400 +CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00 +CONST KyAltY = &H1500, KyAltZ = &H2C00 + + ' Keyboard Codes: Ascii + +CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F +CONST KyPlus = 45, KyMinus = 43 + + ' Color Constants + +CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3 +CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7 +CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11 +CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15 +CONST c.BRIGHT = 8 + + ' From UTILS.ASM + +DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$) +DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$) +DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%) +DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD" +DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%) +DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM" +DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT" +DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%) + diff --git a/16/modex105/DEMOS/ROM_8X8.FNT b/16/modex105/DEMOS/ROM_8X8.FNT new file mode 100644 index 00000000..708a4f92 Binary files /dev/null and b/16/modex105/DEMOS/ROM_8X8.FNT differ diff --git a/16/modex105/DEMOS/SPACEAGE.FNT b/16/modex105/DEMOS/SPACEAGE.FNT new file mode 100644 index 00000000..029bae4e Binary files /dev/null and b/16/modex105/DEMOS/SPACEAGE.FNT differ diff --git a/16/modex105/DEMOS/SYSTEM.FNT b/16/modex105/DEMOS/SYSTEM.FNT new file mode 100644 index 00000000..9a1965eb Binary files /dev/null and b/16/modex105/DEMOS/SYSTEM.FNT differ diff --git a/16/modex105/DEMOS/TEST6.EXE b/16/modex105/DEMOS/TEST6.EXE new file mode 100644 index 00000000..5682c475 Binary files /dev/null and b/16/modex105/DEMOS/TEST6.EXE differ diff --git a/16/modex105/FONTEDIT/CHARSETS.CS b/16/modex105/FONTEDIT/CHARSETS.CS new file mode 100644 index 00000000..97fe608f Binary files /dev/null and b/16/modex105/FONTEDIT/CHARSETS.CS differ diff --git a/16/modex105/FONTEDIT/CSEDIT.DOC b/16/modex105/FONTEDIT/CSEDIT.DOC new file mode 100644 index 00000000..97ff07e0 --- /dev/null +++ b/16/modex105/FONTEDIT/CSEDIT.DOC @@ -0,0 +1,196 @@ + +CSEDIT - A Simple Font Editor by Matt Pritchard + + +CSEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X +Library for VGA Graphics. + +WHAT YOU NEED TO RUN CSEDIT: + + * A Vga Monitor + * A Microsoft Compatible Mouse + + A Mouse is most definitely required, as the keyboard is used for + nothing except entering file names. + +FILES NEEDED IN THE CURRENT DIRECTORY: + + CSEDIT.EXE - The Font Editor Program + CHARSETS.CS - The Font Editor's Internal Fonts + PALETTE.CS - The Font Editor's Palette + MOUSEIMG.CS - The Font Editor's Mouse Pointer + +SAMPLE FONT FILE THAT SHOULD BE INCLUDED: + + SYSTEM.FNT - The Font used by CSEDIT.EXE + INVERSE.FNT - An Inverted version of SYSTEM.FNT + SPACEAGE.FNT - A Futuristic, Tech style font + ROM_8X8.FNT - The Lower 128 characters from the VGA BIOS Rom + +WHAT IT EDITS: + + 8 by 8 character fonts, 128 characters at a time. 2 fonts at a time. + +HOW IT WORKS/FEATURES: + + CSEDIT allows the user to edit 2 different font groups at a time, + which may be loaded and saved separately. + + A enlarged character grid allows the user to edit individual pixels + on a selected character. + + The Following operations can be performed on a single character or + simultaneously on a selected block of characters. + + * Shift the selected character(s) in any direction + with or without clipping at the edges. + * Vertically Flip the selected character(s) + * Horizontally Flip the selected character(s) + * Rotate the selected character(s) 90 Degrees Clockwise + * Rotate the selected character(s) 90 Degrees Counterclockwise + * Clear the selected character(s) + * Invert the selected character(s) + * XOR the selected character(s) with other character(s) + * AND the selected character(s) with other character(s) + * OR the selected character(s) with other character(s) + * Copy the selected character(s) to another position or font. + + An UNDO feature allows the reversal of the most recent operation. + +DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN: + + Character Grid: (RED) Box in Upper Left corner of screen. This is + where you edit an individual character. The Left Button sets the + pixel the mouse pointer is on, while the Right Button clears that + pixel. + + Scroll Buttons: The Four Scroll Buttons are labeled with directional + arrows, and arranged in a diamond pattern. Left Clicking on a + directional button will scroll the currently selected character + in that direction, with the pixels on the edge rolling off and + appearing on the other size. Right Clicking will prevent the + pixels from rolling to the other side. + + Vertical Flip Button: + Horizontal Flip Button: Clicking these buttons will flip the pattern + of the currently selected character(s) around the indicated axis. + i.e. the top row will be swapped with the bottom row, etc. or the + left row column will be swapped with right column, etc. + depending upon which button you push. + + Invert Button: Clicking this button causes all pixels in the selected + character(s) to flip flop between on and off. + + Clear Button: Clicking this button erases the selected characters + + Rotate Buttons: Clicking these buttons will rotate the pattern in the + selected character(s) 90 degrees in the indicated direction. + + XOR Button: Clicking this button will let you XOR the currently + selected character(s) with other character(s) in either font. + The Button will turn RED, indicating that it is waiting for + you to click on the desired character (or upper left corner + of the desired block of characters) in either the Red or Green + Character Set Displays. Clicking anywhere else will abort this + process without doing anything. If you click on (any of) the + selected character(s) the operation is aborted. If a block is + selected and the character you click on is in a position where + it can't represent the upper left corner of a block of the same + size, then the operation is not performed. + + AND Button & OR Button: These buttons work just like the XOR Button + except that the Binary operation performed is either an AND or OR + depending upon which button you have selected. + + COPY Button: This button lets you copy a character or selected block + of characters to another area in the current font or the other + font. After clicking, the button turns RED and works much like + the XOR Button. Clicking on a valid position in either font + window will copy the selected character(s) to that location. + + MODE Button: Clicking this button toggles the editor between BLOCK + mode and CHARACTER mode. The current mode is displayed on a plate + at the top of the screen, just to the right of the enlarged + character grid. In character mode the plate will read "CHAR" and + the currently selected character is displayed just to the right + of the plate. In Block mode the plate will read "BLOCK" and the + enlarged character grid is disabled. + + UNDO Button: Clicking this Button will UNDO or reverse the effects of + the most recent operation. + + QUIT Button: Clicking this button will return you to DOS. Any loaded + fonts are not saved, and no confirmation is given. + + + GREEN FONT AREA: This area displays one of the current fonts which + can be edited. The characters are display in order from #0 to #127 + from the upper left, going right, then down. The Font Box is 32 + characters wide and 4 characters Tall. When the editor is in + character mode, just point at and Left Click on the character you + wish to edit and a Cyan box will appear around that character. + + * If you Right Click on a character, the last current character, + which will still appear in the enlarged character grid, will be + copied onto the character you pointed at, replacing it. This is + a shortcut for copying characters: You can hold the right button + down an fill in a large area with a single character pattern. + When the editor is in Block Mode, you select an area by clicking + on any corner of the desired block. Then drag the mouse to the + opposite corner while holding down the left button. A Cyan Box + will stretch to surround the selected block of characters. + + GREEN FONT FILE NAME BOX: This Text Box is used to enter the name + of a font file to load or the name to save the current Green font + as. Just click on the Box, and it will change color and a + flashing cursor will appear. Now you type in a filename or edit + the existing filename. Press or click outside the text + box to end editing. + + GREEN FONT LOAD BUTTON: Clicking this button will load the font file + that is named in the Green File name box. If no name is given or + no such file exists, then nothing will be loaded. + + GREEN FONT SAVE BUTTON: Clicking this button will save the current + font in the Green Font Area under the name given in the File Name + Box. If a Valid name is not provided, nothing will be saved. + + RED FONT AREA: This is just the same as the GREEN FONT AREA; providing + you with the ability to copy and edit between multiple fonts. + + RED FONT FILE NAME BOX: This works just like the GREEN FONT FILE + NAME BOX. + + RED FONT LOAD BUTTON: This works just like the GREEN FONT LOAD BUTTON. + + RED FONT SAVE BUTTON: This works just like the GREEN FONT SAVE BUTTON. + + Message Bar: At the very bottom of the screen, this Bar will display + information and messages for various functions. + + +FONT FILE FORMAT: + + BINARY Image, in order of character. The format is identical to that + used by the VGA ROM. The Files will be exactly 1024 (128 * 8) bytes + long. + + CHARACTER: 8 Bytes + + FONT: Array (0 to 127) of CHARACTER + + +COMMENTS, QUESTIONS, BUG REPORTS, etc: + + Send the to the Author: Matt Pritchard + + Through the 80xxx Fidonet Echo or + + Matt Pritchard + P.O. Box 140264 + Irving, TX 75014 + +CREDITS: + + This Font Editor was written in QuickBASIC 4.5 + diff --git a/16/modex105/FONTEDIT/CSEDIT.EXE b/16/modex105/FONTEDIT/CSEDIT.EXE new file mode 100644 index 00000000..58b07325 Binary files /dev/null and b/16/modex105/FONTEDIT/CSEDIT.EXE differ diff --git a/16/modex105/FONTEDIT/INVERSE.FNT b/16/modex105/FONTEDIT/INVERSE.FNT new file mode 100644 index 00000000..5901c517 Binary files /dev/null and b/16/modex105/FONTEDIT/INVERSE.FNT differ diff --git a/16/modex105/FONTEDIT/MOUSEIMG.CS b/16/modex105/FONTEDIT/MOUSEIMG.CS new file mode 100644 index 00000000..101e2084 Binary files /dev/null and b/16/modex105/FONTEDIT/MOUSEIMG.CS differ diff --git a/16/modex105/FONTEDIT/PALETTE.CS b/16/modex105/FONTEDIT/PALETTE.CS new file mode 100644 index 00000000..09c5549e Binary files /dev/null and b/16/modex105/FONTEDIT/PALETTE.CS differ diff --git a/16/modex105/FONTEDIT/ROM_8X8.FNT b/16/modex105/FONTEDIT/ROM_8X8.FNT new file mode 100644 index 00000000..708a4f92 Binary files /dev/null and b/16/modex105/FONTEDIT/ROM_8X8.FNT differ diff --git a/16/modex105/FONTEDIT/SPACEAGE.FNT b/16/modex105/FONTEDIT/SPACEAGE.FNT new file mode 100644 index 00000000..029bae4e Binary files /dev/null and b/16/modex105/FONTEDIT/SPACEAGE.FNT differ diff --git a/16/modex105/FONTEDIT/SYSTEM.FNT b/16/modex105/FONTEDIT/SYSTEM.FNT new file mode 100644 index 00000000..9a1965eb Binary files /dev/null and b/16/modex105/FONTEDIT/SYSTEM.FNT differ diff --git a/16/modex105/MODE-X.TXT b/16/modex105/MODE-X.TXT new file mode 100644 index 00000000..4e18d962 --- /dev/null +++ b/16/modex105/MODE-X.TXT @@ -0,0 +1,44 @@ +The following is a FAQ (Frequently Asked Question) summary of +information and assembly routines for Mode "X" Graphics. + +An overview of Mode "X" for the VGA Adaptor: + +1) Mode "X" is a 256 color graphics mode that is available on *ANY* VGA +card with the minimum of 256K video RAM. It is capable of providing +higher resoultions than the only "Official" 256 color mode, mode 13h. +(In quickbasic that is mode 13) + +2) Mode "X" comes in 8 different flavors: 320 or 360 pixels +horizontally, and 200, 240, 400, and 480 pixels vertically. + +3) Since mode X is not supported by the VGA BIOS, there is no built in +support for it. A program must provide its own routines for *ALL* +operations in Mode "X", including setting up the video mode. + +4) Unlike Mode 13h, which has one display page, Mode "X" allows from 1 +to 4 video pages, depending upon the resoultion selected. The reason +that Mode 13h has but one page is that it activates a VGA hardware +feature known as CHAIN4, which prevents access to all but 64K of VGA's +video RAM. CHAIN4 is what provides mode 13h's linear addres space. + +5) Unlike Mode 13h, where each 256 color (1-byte) pixel has a unique +address in the E000: segement, in Mode X there are Four (4) Pixels +at each address in E000: segment. The VGA's control registers allow you +to control which of the 4 pixels is currently available at an address. + +6) It is possible to use the VGA's control registers to operate on 2 or +more of the Pixels at the same address at the same time. The CPU can +write one color value, and set up to 4 pixels with that value at the +same time. + +7) Video RAM that is not being used for the current screen display can +be used to store images and patterns. These images and patterns can be +copied to other parts of the Video RAM 4 bytes (32 bits) at a time, +which is much faster than the 8 bits (1 byte) at time that is possible +over the ISA BUS. (16 Bit BUS operations can produce erroneous results) + +If anything is unclear, inadequate, or you just plain want to know more +or have other specific questions, please send me a message. + + +-Matt Pritchard diff --git a/16/modex105/MODEX.ASM b/16/modex105/MODEX.ASM new file mode 100644 index 00000000..2985fd80 --- /dev/null +++ b/16/modex105/MODEX.ASM @@ -0,0 +1,3295 @@ +;======================================================== +; MODEX.ASM - A Complete Mode X Library +; +; Version 1.04 Release, 3 May 1993, By Matt Pritchard +; With considerable input from Michael Abrash +; +; The following information is donated to the public domain in +; the hopes that save other programmers much frustration. +; +; If you do use this code in a product, it would be nice if +; you include a line like "Mode X routines by Matt Pritchard" +; in the credits. +; +; ========================================================= +; +; All of this code is designed to be assembled with MASM 5.10a +; but TASM 3.0 could be used as well. +; +; The routines contained are designed for use in a MEDIUM model +; program. All Routines are FAR, and is assumed that a DGROUP +; data segment exists and that DS will point to it on entry. +; +; For all routines, the AX, BX, CX, DX, ES and FLAGS registers +; will not be preserved, while the DS, BP, SI and DI registers +; will be preserved. +; +; Unless specifically noted, All Parameters are assumed to be +; "PASSED BY VALUE". That is, the actual value is placed on +; the stack. When a reference is passed it is assumed to be +; a near pointer to a variable in the DGROUP segment. +; +; Routines that return a single 16-Bit integer value will +; return that value in the AX register. +; +; This code will *NOT* run on an 8086/8088 because 80286+ +; specific instructions are used. If you have an 8088/86 +; and VGA, you can buy an 80386-40 motherboard for about +; $160 and move into the 90's. +; +; This code is reasonably optimized: Most drawing loops have +; been unrolled once and memory references are minimized by +; keeping stuff in registers when possible. +; +; Error Trapping varies by Routine. No Clipping is performed +; so the caller should verify that all coordinates are valid. +; +; Several Macros are used to simplify common 2 or 3 instruction +; sequences. Several Single letter Text Constants also +; simplify common assembler expressions like "WORD PTR". +; +; ------------------ Mode X Variations ------------------ +; +; Mode # Screen Size Max Pages Aspect Ratio (X:Y) +; +; 0 320 x 200 4 Pages 1.2:1 +; 1 320 x 400 2 Pages 2.4:1 +; 2 360 x 200 3 Pages 1.35:1 +; 3 360 x 400 1 Page 2.7:1 +; 4 320 x 240 3 Pages 1:1 +; 5 320 x 480 1 Page 2:1 +; 6 360 x 240 3 Pages 1.125:1 +; 7 360 x 480 1 Page 2.25:1 +; +; -------------------- The Legal Stuff ------------------ +; +; No warranty, either written or implied, is made as to +; the accuracy and usability of this code product. Use +; at your own risk. Batteries not included. Pepperoni +; and extra cheese available for an additional charge. +; +; ----------------------- The Author -------------------- +; +; Matt Pritchard is a paid programmer who'd rather be +; writing games. He can be reached at: P.O. Box 140264, +; Irving, TX 75014 USA. Michael Abrash is a living +; god, who now works for Bill Gates (Microsoft). +; +; -------------------- Revision History ----------------- +; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI +; SET_MODEX now saves SI +; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and +; READ_DAC_REGISTERS. Expanded CLR Macro +; to handle multiple registers +; + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ===== MACROS ===== + + ; Macro to OUT a 16 bit value to an I/O port + +OUT_16 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AX not setup + MOV AX, Value ; then Get Data Value + ENDIF + OUT DX, AX ; Set I/O Register(s) +ENDM + + ; Macro to OUT a 8 bit value to an I/O Port + +OUT_8 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AL not Setup + MOV AL, Value ; then Get Data Value + ENDIF + OUT DX, AL ; Set I/O Register +ENDM + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + PUSH R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + POP R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear Registers to 0 + +CLR MACRO Register, R2, R3, R4, R5, R6 + IFNB + XOR Register, Register ; Set Register = 0 + CLR R2, R3, R4, R5, R6 + ENDIF +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + DEC Register ; Counter-- + JNZ Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + DEC Register ; Counter-- + JZ Destination ; Jump if 0 +ENDM + + + ; ===== General Constants ===== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + ; ===== VGA Register Values ===== + + VGA_Segment EQU 0A000h ; Vga Memory Segment + + ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller + GC_Index EQU 03CEh ; VGA Graphics Controller + SC_Index EQU 03C4h ; VGA Sequencer Controller + SC_Data EQU 03C5h ; VGA Sequencer Data Port + CRTC_Index EQU 03D4h ; VGA CRT Controller + CRTC_Data EQU 03D5h ; VGA CRT Controller Data + MISC_OUTPUT EQU 03C2h ; VGA Misc Register + INPUT_1 EQU 03DAh ; Input Status #1 Register + + DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register + DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register + PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W + + PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg + MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg + READ_MAP EQU 004h ; GC Index: Read Map Register + START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi + START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo + + MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1 + MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1 + ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes + + CHAIN4_OFF EQU 00604h ; Chain 4 mode Off + ASYNC_RESET EQU 00100h ; (A)synchronous Reset + SEQU_RESTART EQU 00300h ; Sequencer Restart + + LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches + LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU + + VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit + PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane # + ALL_PLANES EQU 0Fh ; All Bit Planes Selected + CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data + + GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set + ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer + ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer + + ; Constants Specific for these routines + + NUM_MODES EQU 8 ; # of Mode X Variations + + ; Specific Mode Data Table format... + +Mode_Data_Table STRUC + M_MiscR DB ? ; Value of MISC_OUTPUT register + M_Pages DB ? ; Maximum Possible # of pages + M_XSize DW ? ; X Size Displayed on screen + M_YSize DW ? ; Y Size Displayed on screen + M_XMax DW ? ; Maximum Possible X Size + M_YMax DW ? ; Maximum Possible Y Size + M_CRTC DW ? ; Table of CRTC register values +Mode_Data_Table ENDS + + ; ===== DGROUP STORAGE NEEDED (42 BYTES) ===== + + .DATA? + +SCREEN_WIDTH DW 0 ; Width of a line in Bytes +SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels + +LAST_PAGE DW 0 ; # of Display Pages +PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page + +PAGE_SIZE DW 0 ; Size of Page in Addr Bytes + +DISPLAY_PAGE DW 0 ; Page # currently displayed +ACTIVE_PAGE DW 0 ; Page # currently active + +CURRENT_PAGE DW 0 ; Offset of current Page +CURRENT_SEGMENT DW 0 ; Segment of VGA memory + +CURRENT_XOFFSET DW 0 ; Current Display X Offset +CURRENT_YOFFSET DW 0 ; Current Display Y Offset + +CURRENT_MOFFSET DW 0 ; Current Start Offset + +MAX_XOFFSET DW 0 ; Current Display X Offset +MAX_YOFFSET DW 0 ; Current Display Y Offset + +CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127 +CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255 + + .CODE + + ; ===== DATA TABLES ===== + + ; Data Tables, Put in Code Segment for Easy Access + ; (Like when all the other Segment Registers are in + ; use!!) and reduced DGROUP requirements... + + ; Bit Mask Tables for Left/Right/Character Masks + +Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H + +Right_Clip_Mask DB 01H, 03H, 07H, 0FH + + ; Bit Patterns for converting character fonts + +Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH + DB 01H,09H,05H,0DH,03H,0BH,07H,0FH + + ; CRTC Register Values for Various Configurations + +MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes + DW 04009H ; Cell Height (1 Scan Line) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 400/480 Line Mode + +MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes + DW 04109H ; Cell Height (2 Scan Lines) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 200/240 Line Mode + +MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels + DW 05F00H ; Horz total + DW 04F01H ; Horz Displayed + DW 05002H ; Start Horz Blanking + DW 08203H ; End Horz Blanking + DW 05404H ; Start H Sync + DW 08005H ; End H Sync + DW nil ; End of CRTC Data for 320 Horz pixels + +MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels + DW 06B00H ; Horz total + DW 05901H ; Horz Displayed + DW 05A02H ; Start Horz Blanking + DW 08E03H ; End Horz Blanking + DW 05E04H ; Start H Sync + DW 08A05H ; End H Sync + DW nil ; End of CRTC Data for 360 Horz pixels + +MODE_200_Tall: +MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes + DW 0BF06H ; Vertical Total + DW 01F07H ; Overflow + DW 09C10H ; V Sync Start + DW 08E11H ; V Sync End/Prot Cr0 Cr7 + DW 08F12H ; Vertical Displayed + DW 09615H ; V Blank Start + DW 0B916H ; V Blank End + DW nil ; End of CRTC Data for 200/400 Lines + +MODE_240_Tall: +MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes + DW 00D06H ; Vertical Total + DW 03E07H ; Overflow + DW 0EA10H ; V Sync Start + DW 08C11H ; V Sync End/Prot Cr0 Cr7 + DW 0DF12H ; Vertical Displayed + DW 0E715H ; V Blank Start + DW 00616H ; V Blank End + DW nil ; End of CRTC Data for 240/480 Lines + + ; Table of Display Mode Tables + +MODE_TABLE: + DW o MODE_320x200, o MODE_320x400 + DW o MODE_360x200, o MODE_360x400 + DW o MODE_320x240, o MODE_320x480 + DW o MODE_360x240, o MODE_360x480 + + ; Table of Display Mode Components + +MODE_320x200: ; Data for 320 by 200 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 4 ; Maximum of 4 Pages + DW 320, 200 ; Displayed Pixels (X,Y) + DW 1302, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_320x400: ; Data for 320 by 400 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 2 ; Maximum of 2 Pages + DW 320, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_400_Tall + DW o MODE_Single_Line, nil + +MODE_360x240: ; Data for 360 by 240 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 240 ; Displayed Pixels X,Y + DW 1092, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_240_Tall + DW o MODE_Double_Line , nil + +MODE_360x480: ; Data for 360 by 480 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 360, 480 ; Displayed Pixels X,Y + DW 544, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_480_Tall + DW o MODE_Single_Line , nil + +MODE_320x240: ; Data for 320 by 240 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 320, 240 ; Displayed Pixels X,Y + DW 1088, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_240_Tall + DW o MODE_Double_Line, nil + +MODE_320x480: ; Data for 320 by 480 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 320, 480 ; Displayed Pixels X,Y + DW 540, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_WIDE, o MODE_480_Tall + DW o MODE_Single_Line, nil + +MODE_360x200: ; Data for 360 by 200 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 200 ; Displayed Pixels (X,Y) + DW 1302, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_360x400: ; Data for 360 by 400 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 1 ; Maximum of 1 Pages + DW 360, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_400_Tall + DW o MODE_Single_Line, nil + + + ; ===== MODE X SETUP ROUTINES ===== + +;====================================================== +;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%) +;====================================================== +; +; Sets Up the specified version of Mode X. Allows for +; the setup of multiple video pages, and a virtual +; screen which can be larger than the displayed screen +; (which can then be scrolled a pixel at a time) +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; +; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio +; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio +; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio +; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio +; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio +; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio +; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio +; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio +; +; MaxXpos = The Desired Virtual Screen Width +; MaxYpos = The Desired Virtual Screen Height +; Pages = The Desired # of Video Pages +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SVM_STACK STRUC + SVM_Table DW ? ; Offset of Mode Info Table + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Pages DW ? ; # of Screen Pages desired + SVM_Ysize DW ? ; Vertical Screen Size Desired + SVM_Xsize DW ? ; Horizontal Screen Size Desired + SVM_Mode DW ? ; Display Resolution Desired +SVM_STACK ENDS + + PUBLIC SET_VGA_MODEX + +SET_VGA_MODEX PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 2 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + ; Check Legality of Mode Request.... + + MOV BX, [BP].SVM_Mode ; Get Requested Mode # + CMP BX, NUM_MODES ; Is it 0..7? + JAE @SVM_BadModeSetup ; If Not, Error out + + SHL BX, 1 ; Scale BX + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + MOV [BP].SVM_Table, SI ; Save ptr for later use + + ; Check # of Requested Display Pages + + MOV CX, [BP].SVM_Pages ; Get # of Requested Pages + CLR CH ; Set Hi Word = 0! + CMP CL, CS:[SI].M_Pages ; Check # Pages for mode + JA @SVM_BadModeSetup ; Report Error if too Many Pages + JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages + + ; Check Validity of X Size + + AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0 + + MOV AX, [BP].SVM_XSize ; Get Logical Screen Width + CMP AX, CS:[SI].M_XSize ; Check against Displayed X + JB @SVM_BadModeSetup ; Report Error if too small + CMP AX, CS:[SI].M_XMax ; Check against Max X + JA @SVM_BadModeSetup ; Report Error if too big + + ; Check Validity of Y Size + + MOV BX, [BP].SVM_YSize ; Get Logical Screen Height + CMP BX, CS:[SI].M_YSize ; Check against Displayed Y + JB @SVM_BadModeSetup ; Report Error if too small + CMP BX, CS:[SI].M_YMax ; Check against Max Y + JA @SVM_BadModeSetup ; Report Error if too big + + ; Enough memory to Fit it all? + + SHR AX, 2 ; # of Bytes:Line = XSize/4 + MUL CX ; AX = Bytes/Line * Pages + MUL BX ; DX:AX = Total VGA mem needed + JNO @SVM_Continue ; Exit if Total Size > 256K + + DEC DX ; Was it Exactly 256K??? + OR DX, AX ; (DX = 1, AX = 0000) + JZ @SVM_Continue ; if so, it's valid... + +@SVM_BadModeSetup: + + CLR AX ; Return Value = False + JMP @SVM_Exit ; Normal Exit + +@SVM_Continue: + + MOV AX, 13H ; Start with Mode 13H + INT 10H ; Let BIOS Set Mode + + OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode + OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset + OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size + OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ... + + OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register + INC DX ; Point to Data + IN AL, DX ; Get Value, Bit 7 = Protect + AND AL, 7FH ; Mask out Write Protect + OUT DX, AL ; And send it back + + MOV DX, CRTC_INDEX ; Vga Crtc Registers + ADD SI, M_CRTC ; SI -> CRTC Parameter Data + + ; Load Tables of CRTC Parameters from List of Tables + +@SVM_Setup_Table: + + MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl + ADD SI, 2 ; Point to next Ptr Entry + OR DI, DI ; A nil Ptr means that we have + JZ @SVM_Set_Data ; finished CRTC programming + +@SVM_Setup_CRTC: + MOV AX, CS:[DI] ; Get CRTC Data from Table + ADD DI, 2 ; Advance Pointer + OR AX, AX ; At End of Data Table? + JZ @SVM_Setup_Table ; If so, Exit & get next Table + + OUT DX, AX ; Reprogram VGA CRTC reg + JMP s @SVM_Setup_CRTC ; Process Next Table Entry + + ; Initialize Page & Scroll info, DI = 0 + +@SVM_Set_Data: + MOV DISPLAY_PAGE, DI ; Display Page = 0 + MOV ACTIVE_PAGE, DI ; Active Page = 0 + MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0 + MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0 + MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0 + MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0 + + MOV AX, VGA_SEGMENT ; Segment for VGA memory + MOV CURRENT_SEGMENT, AX ; Save for Future LES's + + ; Set Logical Screen Width, X Scroll and Our Data + + MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info + MOV AX, [BP].SVM_Xsize ; Get Display Width + + MOV CX, AX ; CX = Logical Width + SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value + MOV MAX_XOFFSET, CX ; Set Maximum X Scroll + + SHR AX, 2 ; Bytes = Pixels / 4 + MOV SCREEN_WIDTH, AX ; Save Width in Pixels + + SHR AX, 1 ; Offset Value = Bytes / 2 + MOV AH, 13h ; CRTC Offset Register Index + XCHG AL, AH ; Switch format for OUT + OUT DX, AX ; Set VGA CRTC Offset Reg + + ; Setup Data table, Y Scroll, Misc for Other Routines + + MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height + + MOV CX, AX ; CX = Logical Height + SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value + MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll + + MOV SCREEN_HEIGHT, AX ; Save Height in Pixels + MUL SCREEN_WIDTH ; AX = Page Size in Bytes, + MOV PAGE_SIZE, AX ; Save Page Size + + MOV CX, [BP].SVM_Pages ; Get # of Pages + MOV LAST_PAGE, CX ; Save # of Pages + + CLR BX ; Page # = 0 + MOV DX, BX ; Page 0 Offset = 0 + +@SVM_Set_Pages: + + MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset + ADD BX, 2 ; Page#++ + ADD DX, AX ; Compute Addr of Next Page + LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set + + ; Clear VGA Memory + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; -> Start of VGA memory + + CLR AX ; AX = 0 + CLD ; Block Xfer Forwards + MOV CX, 8000H ; 32K * 4 * 2 = 256K + REP STOSW ; Clear dat memory! + + ; Setup Font Pointers + + MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_LOW, BP ; Save Char Set Offset + MOV CHARSET_LOW+2, ES ; Save Char Set Segment + + MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_HI, BP ; Save Char Set Offset + MOV CHARSET_HI+2, ES ; Save Char Set Segment + + MOV AX, True ; Return Success Code + +@SVM_EXIT: + ADD SP, 2 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit & Clean Up Stack + +SET_VGA_MODEX ENDP + + +;================== +;SET_MODEX% (Mode%) +;================== +; +; Quickie Mode Set - Sets Up Mode X to Default Configuration +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; (See SET_VGA_MODEX for list) +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SM_STACK STRUC + DW ?,? ; BP, SI + DD ? ; Caller + SM_Mode DW ? ; Desired Screen Resolution +SM_STACK ENDS + + PUBLIC SET_MODEX + +SET_MODEX PROC FAR + + PUSHx BP, SI ; Preserve Important registers + MOV BP, SP ; Set up Stack Frame + + CLR AX ; Assume Failure + MOV BX, [BP].SM_Mode ; Get Desired Mode # + CMP BX, NUM_MODES ; Is it a Valid Mode #? + JAE @SMX_Exit ; If Not, don't Bother + + PUSH BX ; Push Mode Parameter + + SHL BX, 1 ; Scale BX to word Index + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + + PUSH CS:[SI].M_XSize ; Push Default X Size + PUSH CS:[SI].M_Ysize ; Push Default Y size + MOV AL, CS:[SI].M_Pages ; Get Default # of Pages + CLR AH ; Hi Byte = 0 + PUSH AX ; Push # Pages + + CALL f SET_VGA_MODEX ; Set up Mode X! + +@SMX_Exit: + POPx SI, BP ; Restore Registers + RET 2 ; Exit & Clean Up Stack + +SET_MODEX ENDP + + + ; ===== BASIC GRAPHICS PRIMITIVES ===== + +;============================ +;CLEAR_VGA_SCREEN (ColorNum%) +;============================ +; +; Clears the active display page +; +; ENTRY: ColorNum = Color Value to fill the page with +; +; EXIT: No meaningful values returned +; + +CVS_STACK STRUC + DW ?,? ; DI, BP + DD ? ; Caller + CVS_COLOR DB ?,? ; Color to Set Screen to +CVS_STACK ENDS + + PUBLIC CLEAR_VGA_SCREEN + +CLEAR_VGA_SCREEN PROC FAR + + PUSHx BP, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AL, [BP].CVS_COLOR ; Get Color + MOV AH, AL ; Copy for Word Write + CLD ; Block fill Forwards + + MOV CX, PAGE_SIZE ; Get Size of Page + SHR CX, 1 ; Divide by 2 for Words + REP STOSW ; Block Fill VGA memory + + POPx DI, BP ; Restore Saved Registers + RET 2 ; Exit & Clean Up Stack + +CLEAR_VGA_SCREEN ENDP + + +;=================================== +;SET_POINT (Xpos%, Ypos%, ColorNum%) +;=================================== +; +; Plots a single Pixel on the active display page +; +; ENTRY: Xpos = X position to plot pixel at +; Ypos = Y position to plot pixel at +; ColorNum = Color to plot pixel with +; +; EXIT: No meaningful values returned +; + +SP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + SETP_Color DB ?,? ; Color of Point to Plot + SETP_Ypos DW ? ; Y pos of Point to Plot + SETP_Xpos DW ? ; X pos of Point to Plot +SP_STACK ENDS + + PUBLIC SET_POINT + +SET_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].SETP_Xpos ; Get Xpos + MOV CX, BX ; Copy to extract Plane # from + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register + AND CL, PLANE_BITS ; Get Plane Bits + SHL AH, CL ; Get Plane Select Value + OUT_16 SC_Index, AX ; Select Plane + + MOV AL,[BP].SETP_Color ; Get Pixel Color + MOV ES:[DI+BX], AL ; Draw Pixel + + POPx DI, BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_POINT ENDP + + +;========================== +;READ_POINT% (Xpos%, Ypos%) +;========================== +; +; Read the color of a pixel from the Active Display Page +; +; ENTRY: Xpos = X position of pixel to read +; Ypos = Y position of pixel to read +; +; EXIT: AX = Color of Pixel at (Xpos, Ypos) +; + +RP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + RP_Ypos DW ? ; Y pos of Point to Read + RP_Xpos DW ? ; X pos of Point to Read +RP_STACK ENDS + + PUBLIC READ_POINT + +READ_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].RP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].RP_Xpos ; Get Xpos + MOV CX, BX + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AL, READ_MAP ; GC Read Mask Register + MOV AH, CL ; Get Xpos + AND AH, PLANE_BITS ; & mask out Plane # + OUT_16 GC_INDEX, AX ; Select Plane to read in + + CLR AH ; Clear Return Value Hi byte + MOV AL, ES:[DI+BX] ; Get Color of Pixel + + POPx DI, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +READ_POINT ENDP + + +;====================================================== +;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;====================================================== +; +; Fills a rectangular block on the active display Page +; +; ENTRY: Xpos1 = Left X position of area to fill +; Ypos1 = Top Y position of area to fill +; Xpos2 = Right X position of area to fill +; Ypos2 = Bottom Y position of area to fill +; ColorNum = Color to fill area with +; +; EXIT: No meaningful values returned +; + +FB_STACK STRUC + DW ?x4 ; DS, DI, SI, BP + DD ? ; Caller + FB_Color DB ?,? ; Fill Color + FB_Ypos2 DW ? ; Y pos of Lower Right Pixel + FB_Xpos2 DW ? ; X pos of Lower Right Pixel + FB_Ypos1 DW ? ; Y pos of Upper Left Pixel + FB_Xpos1 DW ? ; X pos of Upper Left Pixel +FB_STACK ENDS + + PUBLIC FILL_BLOCK + +FILL_BLOCK PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + + ; Validate Pixel Coordinates + ; If necessary, Swap so X1 <= X2, Y1 <= Y2 + + MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2? + MOV BX, [BP].FB_Ypos2 ; BX = Y2 + CMP AX, BX + JLE @FB_NOSWAP1 + + MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1 + XCHG AX, BX ; on stack for future use + +@FB_NOSWAP1: + SUB BX, AX ; Get Y width + INC BX ; Add 1 to avoid 0 value + MOV [BP].FB_Ypos2, BX ; Save in Ypos2 + + MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line + ADD DI, AX ; DI = Start of Line Y1 + + MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2 + MOV BX, [BP].FB_Xpos2 ; + CMP AX, BX + JLE @FB_NOSWAP2 ; Skip Ahead if Ok + + MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2 + XCHG AX, BX ; on stack for future use + + ; All our Input Values are in order, Now determine + ; How many full "bands" 4 pixels wide (aligned) there + ; are, and if there are partial bands (<4 pixels) on + ; the left and right edges. + +@FB_NOSWAP2: + MOV DX, AX ; DX = X1 (Pixel Position) + SHR DX, 2 ; DX/4 = Bytes into Line + ADD DI, DX ; DI = Addr of Upper-Left Corner + + MOV CX, BX ; CX = X2 (Pixel Position) + SHR CX, 2 ; CX/4 = Bytes into Line + + CMP DX, CX ; Start and end in same band? + JNE @FB_NORMAL ; if not, check for l & r edges + JMP @FB_ONE_BAND_ONLY ; if so, then special processing + +@FB_NORMAL: + SUB CX, DX ; CX = # bands -1 + MOV SI, AX ; SI = PLANE#(X1) + AND SI, PLANE_BITS ; if Left edge is aligned then + JZ @FB_L_PLANE_FLUSH ; no special processing.. + + ; Draw "Left Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask + + MOV SI, DI ; SI = Copy of Start Addr (UL) + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_LEFT_LOOP: + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn + +@FB_LEFT_CONT: + + INC DI ; Point to Middle (or Right) Block + DEC CX ; Reset CX instead of JMP @FB_RIGHT + +@FB_L_PLANE_FLUSH: + INC CX ; Add in Left band to middle block + + ; DI = Addr of 1st middle Pixel (band) to fill + ; CX = # of Bands to fill -1 + +@FB_RIGHT: + MOV SI, [BP].FB_Xpos2 ; Get Xpos2 + AND SI, PLANE_BITS ; Get Plane values + CMP SI, 0003 ; Plane = 3? + JE @FB_R_EDGE_FLUSH ; Hey, add to middle + + ; Draw "Right Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask + + MOV SI, DI ; Get Addr of Left Edge + ADD SI, CX ; Add Width-1 (Bands) + DEC SI ; To point to top of Right Edge + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_RIGHT_LOOP: + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn + +@FB_RIGHT_CONT: + + DEC CX ; Minus 1 for Middle bands + JZ @FB_EXIT ; Uh.. no Middle bands... + +@FB_R_EDGE_FLUSH: + + ; DI = Addr of Upper Left block to fill + ; CX = # of Bands to fill in (width) + + OUT_8 SC_Data, ALL_PLANES ; Write to All Planes + + MOV DX, SCREEN_WIDTH ; DX = DI Increment + SUB DX, CX ; = Screen_Width-# Planes Filled + + MOV BX, CX ; BX = Quick Refill for CX + MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill + MOV AL, [BP].FB_Color ; Get Fill Color + +@FB_MIDDLE_LOOP: + REP STOSB ; Fill in entire line + + MOV CX, BX ; Recharge CX (Line Width) + ADD DI, DX ; Point to start of Next Line + LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn + + JMP s @FB_EXIT ; Outa here + +@FB_ONE_BAND_ONLY: + MOV SI, AX ; Get Left Clip Mask, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV SI, BX ; Get Right Clip Mask, Save X2 + AND SI, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_ONE_LOOP: + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn + + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn + +@FB_EXIT: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +FILL_BLOCK ENDP + + +;===================================================== +;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;===================================================== +; +; Draws a Line on the active display page +; +; ENTRY: Xpos1 = X position of first point on line +; Ypos1 = Y position of first point on line +; Xpos2 = X position of last point on line +; Ypos2 = Y position of last point on line +; ColorNum = Color to draw line with +; +; EXIT: No meaningful values returned +; + +DL_STACK STRUC + DW ?x3 ; DI, SI, BP + DD ? ; Caller + DL_ColorF DB ?,? ; Line Draw Color + DL_Ypos2 DW ? ; Y pos of last point + DL_Xpos2 DW ? ; X pos of last point + DL_Ypos1 DW ? ; Y pos of first point + DL_Xpos1 DW ? ; X pos of first point +DL_STACK ENDS + + PUBLIC DRAW_LINE + +DRAW_LINE PROC FAR + + PUSHx BP, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + MOV CH, [BP].DL_ColorF ; Save Line Color in CH + + ; Check Line Type + + MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2? + MOV DI, [BP].DL_Xpos2 ; DX = X2 + CMP SI, DI ; Is X1 < X2 + JE @DL_VLINE ; If X1=X2, Draw Vertical Line + JL @DL_NOSWAP1 ; If X1 < X2, don't swap + + XCHG SI, DI ; X2 IS > X1, SO SWAP THEM + +@DL_NOSWAP1: + + ; SI = X1, DI = X2 + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2? + CMP AX, [BP].DL_Ypos2 ; Y1 = Y2? + JE @DL_HORZ ; If so, Draw a Horizontal Line + + JMP @DL_BREZHAM ; Diagonal line... go do it... + + ; This Code draws a Horizontal Line in Mode X where: + ; SI = X1, DI = X2, and AX = Y1/Y2 + +@DL_HORZ: + + MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width + MOV DX, AX ; CX = Line offset into Page + + MOV AX, SI ; Get Left edge, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV CX, DI ; Get Right edge, Save X2 + AND DI, PLANE_BITS ; Mask out Row # + MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte + + SHR AX, 2 ; Get X1 Byte # (=X1/4) + SHR CX, 2 ; Get X2 Byte # (=X2/4) + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, DX ; Point to Start of Line + ADD DI, AX ; Point to Pixel X1 + + SUB CX, AX ; CX = # Of Bands (-1) to set + JNZ @DL_LONGLN ; jump if longer than one segment + + AND BL, BH ; otherwise, merge clip masks + +@DL_LONGLN: + + OUT_8 SC_Data, BL ; Set the Left Clip Mask + + MOV AL, [BP].DL_ColorF ; Get Line Color + MOV BL, AL ; BL = Copy of Line Color + STOSB ; Set Left (1-4) Pixels + + JCXZ @DL_EXIT ; Done if only one Line Segment + + DEC CX ; CX = # of Middle Segments + JZ @DL_XRSEG ; If no middle segments.... + + ; Draw Middle Segments + + OUT_8 DX, ALL_PLANES ; Write to ALL Planes + + MOV AL, BL ; Get Color from BL + REP STOSB ; Draw Middle (4 Pixel) Segments + +@DL_XRSEG: + OUT_8 DX, BH ; Select Planes for Right Clip Mask + MOV AL, BL ; Get Color Value + STOSB ; Draw Right (1-4) Pixels + + JMP s @DL_EXIT ; We Are Done... + + + ; This Code Draws A Vertical Line. On entry: + ; CH = Line Color, SI & DI = X1 + +@DL_VLINE: + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 + MOV SI, [BP].DL_Ypos2 ; SI = Y2 + CMP AX, SI ; Is Y1 < Y2? + JLE @DL_NOSWAP2 ; if so, Don't Swap them + + XCHG AX, SI ; Ok, NOW Y1 < Y2 + +@DL_NOSWAP2: + + SUB SI, AX ; SI = Line Height (Y2-Y1+1) + INC SI + + ; AX = Y1, DI = X1, Get offset into Page into AX + + MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width + MOV DX, DI ; Copy Xpos into DX + SHR DI, 2 ; DI = Xpos/4 + ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1 + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, AX ; Point to Pixel X1, Y1 + + ;Select Plane + + MOV CL, DL ; CL = Save X1 + AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #) + MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1 + SHL AH, CL ; Change to Correct Plane # + OUT_16 SC_Index, AX ; Select Plane + + MOV AL, CH ; Get Saved Color + MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By + +@DL_VLoop: + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPjz SI, @DL_EXIT ; Lines--, Exit if done + + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPx SI, @DL_VLoop ; Lines--, Loop until Done + +@DL_EXIT: + + JMP @DL_EXIT2 ; Done! + + ; This code Draws a diagonal line in Mode X + +@DL_BREZHAM: + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].DL_Ypos1 ; get Y1 value + MOV BX, [BP].DL_Ypos2 ; get Y2 value + MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos + + CMP BX, AX ; Y2-Y1 is? + JNC @DL_DeltaYOK ; if Y2>=Y1 then goto... + + XCHG BX, AX ; Swap em... + MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos + +@DL_DeltaYOK: + MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1 + + ADD DI, AX ; DI -> Start of Line Y1 on Page + MOV AX, CX ; AX = Xpos (X1) + SHR AX, 2 ; /4 = Byte Offset into Line + ADD DI, AX ; DI = Starting pos (X1,Y1) + + MOV AL, 11h ; Staring Mask + AND CL, PLANE_BITS ; Get Plane # + SHL AL, CL ; and shift into place + MOV AH, [BP].DL_ColorF ; Color in Hi Bytes + + PUSH AX ; Save Mask,Color... + + MOV AH, AL ; Plane # in AH + MOV AL, MAP_MASK ; Select Plane Register + OUT_16 SC_Index, AX ; Select initial plane + + MOV AX, [BP].DL_Xpos1 ; get X1 value + MOV BX, [BP].DL_Ypos1 ; get Y1 value + MOV CX, [BP].DL_Xpos2 ; get X2 value + MOV DX, [BP].DL_Ypos2 ; get Y2 value + + MOV BP, SCREEN_WIDTH ; Use BP for Line width to + ; to avoid extra memory access + + SUB DX, BX ; figure Delta_Y + JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1 + + ADD BX, DX ; put Y2 into Y1 + NEG DX ; abs(Delta_Y) + XCHG AX, CX ; and exchange X1 and X2 + +@DL_DeltaYOK2: + MOV BX, 08000H ; seed for fraction accumulator + + SUB CX, AX ; figure Delta_X + JC @DL_DrawLeft ; if negative, go left + + JMP @DL_DrawRight ; Draw Line that slopes right + +@DL_DrawLeft: + + NEG CX ; abs(Delta_X) + + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepLeft ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the left in Mode X + +@DL_ShallowLeft: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down... + +@DL_SLLLoop: + MOV ES:[DI], AH ; set first pixel, plane data set up + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLLL2nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL2nc: + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator, + JNC @DL_SLLL3nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL3nc: ; Now move left a pixel... + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLLLoop ; loop until done + +@DL_SLLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a steep line to the left in Mode X + +@DL_SteepLeft: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe left + +@DL_STLLoop: + + MOV ES:[DI], AH ; set first pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc2 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc3 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc3: + ADD DI, BP ; advance to next line. + JMP s @DL_STLLoop ; Loop until done + +@DL_STLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a line that goes to the Right... + +@DL_DrawRight: + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepRight ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the Right in Mode X + +@DL_ShallowRight: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down... + +@DL_SLRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR2nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR2nc: ; Now move right a pixel... + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR3nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR3nc: + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLRLoop ; loop till done + +@DL_SLRExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a Steep line to the Right in Mode X + +@DL_SteepRight: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right + +@STRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc2 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc3 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc3: + ADD DI, BP ; advance to next line. + JMP s @STRLoop ; loop till done + +@DL_EXIT2: + POPx DI, SI, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +DRAW_LINE ENDP + + + ; ===== DAC COLOR REGISTER ROUTINES ===== + +;================================================= +;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%) +;================================================= +; +; Sets a single (RGB) Vga Palette Register +; +; ENTRY: Register = The DAC # to modify (0-255) +; Red = The new Red Intensity (0-63) +; Green = The new Green Intensity (0-63) +; Blue = The new Blue Intensity (0-63) +; +; EXIT: No meaningful values returned +; + +SDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDR_Blue DB ?,? ; Blue Data Value + SDR_Green DB ?,? ; Green Data Value + SDR_Red DB ?,? ; Red Data Value + SDR_Register DB ?,? ; Palette Register # +SDR_STACK ENDS + + PUBLIC SET_DAC_REGISTER + +SET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to modify + + OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + OUT_8 DX, [BP].SDR_Red ; Set Red Intensity + OUT_8 DX, [BP].SDR_Green ; Set Green Intensity + OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +SET_DAC_REGISTER ENDP + +;==================================================== +;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%) +;==================================================== +; +; Reads the RGB Values of a single Vga Palette Register +; +; ENTRY: Register = The DAC # to read (0-255) +; Red = Offset to Red Variable in DS +; Green = Offset to Green Variable in DS +; Blue = Offset to Blue Variable in DS +; +; EXIT: The values of the integer variables Red, +; Green, and Blue are set to the values +; taken from the specified DAC register. +; + +GDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + GDR_Blue DW ? ; Addr of Blue Data Value in DS + GDR_Green DW ? ; Addr of Green Data Value in DS + GDR_Red DW ? ; Addr of Red Data Value in DS + GDR_Register DB ?,? ; Palette Register # +GDR_STACK ENDS + + PUBLIC GET_DAC_REGISTER + +GET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to read in + + OUT_8 DAC_READ_ADDR, [BP].GDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + CLR AX ; Clear AX + + IN AL, DX ; Read Red Value + MOV BX, [BP].GDR_Red ; Get Address of Red% + MOV [BX], AX ; *Red% = AX + + IN AL, DX ; Read Green Value + MOV BX, [BP].GDR_Green ; Get Address of Green% + MOV [BX], AX ; *Green% = AX + + IN AL, DX ; Read Blue Value + MOV BX, [BP].GDR_Blue ; Get Address of Blue% + MOV [BX], AX ; *Blue% = AX + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +GET_DAC_REGISTER ENDP + + +;=========================================================== +;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%) +;=========================================================== +; +; Sets a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to Block of palette data +; StartReg = First Register # in range to set (0-255) +; EndReg = Last Register # in Range to set (0-255) +; Sync = Wait for Vertical Retrace Flag (Boolean) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +LDR_STACK STRUC + DW ?x3 ; BP, DS, SI + DD ? ; Caller + LDR_Sync DW ? ; Vertical Sync Flag + LDR_EndReg DB ?,? ; Last Register # + LDR_StartReg DB ?,? ; First Register # + LDR_PalData DD ? ; Far Ptr to Palette Data +LDR_STACK ENDS + + PUBLIC LOAD_DAC_REGISTERS + +LOAD_DAC_REGISTERS PROC FAR + + PUSHx BP, DS, SI ; Save Registers + mov BP, SP ; Set up Stack Frame + + mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag + or AX, AX ; is Sync Flag = 0? + jz @LDR_Load ; if so, skip call + + call f SYNC_DISPLAY ; wait for vsync + + ; Determine register #'s, size to copy, etc + +@LDR_Load: + + lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data + mov DX, DAC_WRITE_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].LDR_StartReg ; Get Start Register + mov BL, [BP].LDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block OUTs forward + out DX, AL ; set up correct register # + + ; Load a block of DAC Registers + + mov DX, PEL_DATA_REG ; Dac Data Register + + rep outsb ; block set DAC registers + + POPx SI, DS, BP ; Restore Registers + ret 10 ; Exit & Clean Up Stack + +LOAD_DAC_REGISTERS ENDP + + +;==================================================== +;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%) +;==================================================== +; +; Reads a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to block to store palette data +; StartReg = First Register # in range to read (0-255) +; EndReg = Last Register # in Range to read (0-255) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +RDR_STACK STRUC + DW ?x3 ; BP, ES, DI + DD ? ; Caller + RDR_EndReg DB ?,? ; Last Register # + RDR_StartReg DB ?,? ; First Register # + RDR_PalData DD ? ; Far Ptr to Palette Data +RDR_STACK ENDS + + PUBLIC READ_DAC_REGISTERS + +READ_DAC_REGISTERS PROC FAR + + PUSHx BP, ES, DI ; Save Registers + mov BP, SP ; Set up Stack Frame + + ; Determine register #'s, size to copy, etc + + les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer + mov DX, DAC_READ_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].RDR_StartReg ; Get Start Register + mov BL, [BP].RDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block INs forward + + ; Read a block of DAC Registers + + out DX, AL ; set up correct register # + mov DX, PEL_DATA_REG ; Dac Data Register + + rep insb ; block read DAC registers + + POPx DI, ES, BP ; Restore Registers + ret 8 ; Exit & Clean Up Stack + +READ_DAC_REGISTERS ENDP + + + ; ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +;========================= +;SET_ACTIVE_PAGE (PageNo%) +;========================= +; +; Sets the active display Page to be used for future drawing +; +; ENTRY: PageNo = Display Page to make active +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SAP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SAP_Page DW ? ; Page # for Drawing +SAP_STACK ENDS + + PUBLIC SET_ACTIVE_PAGE + +SET_ACTIVE_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SAP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SAP_Exit ; IF Not, Do Nothing + + MOV ACTIVE_PAGE, BX ; Set Active Page # + + SHL BX, 1 ; Scale Page # to Word + MOV AX, PAGE_ADDR[BX] ; Get offset to Page + + MOV CURRENT_PAGE, AX ; And set for future LES's + +@SAP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_ACTIVE_PAGE ENDP + + +;================ +;GET_ACTIVE_PAGE% +;================ +; +; Returns the Video Page # currently used for Drawing +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page used for Drawing +; + + PUBLIC GET_ACTIVE_PAGE + +GET_ACTIVE_PAGE PROC FAR + + MOV AX, ACTIVE_PAGE ; Get Active Page # + RET ; Exit and Clean up Stack + +GET_ACTIVE_PAGE ENDP + + +;=============================== +;SET_DISPLAY_PAGE (DisplayPage%) +;=============================== +; +; Sets the currently visible display page. +; When called this routine syncronizes the display +; to the vertical blank. +; +; ENTRY: PageNo = Display Page to show on the screen +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SDP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDP_Page DW ? ; Page # to Display... +SDP_STACK ENDS + + PUBLIC SET_DISPLAY_PAGE + +SET_DISPLAY_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SDP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SDP_Exit ; IF Not, Do Nothing + + MOV DISPLAY_PAGE, BX ; Set Display Page # + + SHL BX, 1 ; Scale Page # to Word + MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page + ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling + + ; Wait if we are currently in a Vertical Retrace + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @DP_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new page + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, CL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, CH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @DP_WAIT1 ; If Not, wait for it + + ; Now Set Display Starting Address + + +@SDP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_DISPLAY_PAGE ENDP + + +;================= +;GET_DISPLAY_PAGE% +;================= +; +; Returns the Video Page # currently displayed +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page being displayed +; + + PUBLIC GET_DISPLAY_PAGE + +GET_DISPLAY_PAGE PROC FAR + + MOV AX, DISPLAY_PAGE ; Get Display Page # + RET ; Exit & Clean Up Stack + +GET_DISPLAY_PAGE ENDP + + +;======================================= +;SET_WINDOW (DisplayPage%, Xpos%, Ypos%) +;======================================= +; +; Since a Logical Screen can be larger than the Physical +; Screen, Scrolling is possible. This routine sets the +; Upper Left Corner of the Screen to the specified Pixel. +; Also Sets the Display page to simplify combined page +; flipping and scrolling. When called this routine +; syncronizes the display to the vertical blank. +; +; ENTRY: DisplayPage = Display Page to show on the screen +; Xpos = # of pixels to shift screen right +; Ypos = # of lines to shift screen down +; +; EXIT: No meaningful values returned +; + +SW_STACK STRUC + DW ? ; BP + DD ? ; Caller + SW_Ypos DW ? ; Y pos of UL Screen Corner + SW_Xpos DW ? ; X pos of UL Screen Corner + SW_Page DW ? ; (new) Display Page +SW_STACK ENDS + + PUBLIC SET_WINDOW + +SET_WINDOW PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + ; Check if our Scroll Offsets are Valid + + MOV BX, [BP].SW_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SW_Exit ; IF Not, Do Nothing + + MOV AX, [BP].SW_Ypos ; Get Desired Y Offset + CMP AX, MAX_YOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + MOV CX, [BP].SW_Xpos ; Get Desired X Offset + CMP CX, MAX_XOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + ; Compute proper Display start address to use + + MUL SCREEN_WIDTH ; AX = YOffset * Line Width + SHR CX, 2 ; CX / 4 = Bytes into Line + ADD AX, CX ; AX = Offset of Upper Left Pixel + + MOV CURRENT_MOFFSET, AX ; Save Offset Info + + MOV DISPLAY_PAGE, BX ; Set Current Page # + SHL BX, 1 ; Scale Page # to Word + ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page + MOV BX, AX ; BX = Desired Display Start + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait if we are currently in a Vertical Retrace + +@SW_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SW_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new window + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, BL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, BH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@SW_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SW_WAIT1 ; If Not, wait for it + + ; Now Set the Horizontal Pixel Pan values + + OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register + + MOV AX, [BP].SW_Xpos ; Get Desired X Offset + AND AL, 03 ; Get # of Pixels to Pan (0-3) + SHL AL, 1 ; Shift for 256 Color Mode + OUT DX, AL ; Fine tune the display! + +@SW_Exit: + POP BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_WINDOW ENDP + + +;============= +;GET_X_OFFSET% +;============= +; +; Returns the X coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Horizontal Scroll Offset +; + + PUBLIC GET_X_OFFSET + +GET_X_OFFSET PROC FAR + + MOV AX, CURRENT_XOFFSET ; Get current horz offset + RET ; Exit & Clean Up Stack + +GET_X_OFFSET ENDP + + +;============= +;GET_Y_OFFSET% +;============= +; +; Returns the Y coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Vertical Scroll Offset +; + + PUBLIC GET_Y_OFFSET + +GET_Y_OFFSET PROC FAR + + MOV AX, CURRENT_YOFFSET ; Get current vertical offset + RET ; Exit & Clean Up Stack + +GET_Y_OFFSET ENDP + + +;============ +;SYNC_DISPLAY +;============ +; +; Pauses the computer until the next Vertical Retrace starts +; +; ENTRY: No Parameters are passed +; +; EXIT: No meaningful values returned +; + + PUBLIC SYNC_DISPLAY + +SYNC_DISPLAY PROC FAR + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait for any current retrace to end + +@SD_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SD_WAIT0 ; If Not, wait for it + + ; Wait for the start of the next vertical retrace + +@SD_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SD_WAIT1 ; If Not, wait for it + + RET ; Exit & Clean Up Stack + +SYNC_DISPLAY ENDP + + + ; ===== TEXT DISPLAY ROUTINES ===== + +;================================================== +;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================== +; +; Draws an ASCII Text Character using the currently selected +; 8x8 font on the active display page. It would be a simple +; exercise to make this routine process variable height fonts. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +GPC_STACK STRUC + GPC_Width DW ? ; Screen Width-1 + GPC_Lines DB ?,? ; Scan lines to Decode + GPC_T_SETS DW ? ; Saved Charset Segment + GPC_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + GPC_ColorB DB ?,? ; Background Color + GPC_ColorF DB ?,? ; Text Color + GPC_Ypos DW ? ; Y Position to Print at + GPC_Xpos DW ? ; X position to Print at + GPC_Char DB ?,? ; Character to Print +GPC_STACK ENDS + + PUBLIC GPRINTC + +GPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].GPC_Width, BX ; Save for later use + + MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].GPC_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].GPC_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @GPC_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @GPC_Set_Char ; Go Setup Character Ptr + +@GPC_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@GPC_Set_Char: + MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].GPC_Lines, AL ; Save on Stack + + MOV DS, [BP].GPC_T_SETS ; Point to character set + +@GPC_DECODE_CHAR_BYTE: + + MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].GPC_T_SETO, SI ; And save new Pointer... + + CLR AX ; Clear AX + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_LEFT1BITS: + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_LEFT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@GPC_NO_LEFT0BITS: + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE1BITS: + XOR AL, ALL_PLANES ; Invert mask for Background + JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE0BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @GPC_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT1BITS: + + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT0BITS: + DEC DI ; Adjust for Next Line Advance + +@GPC_NEXT_LINE: + ADD DI, [BP].GPC_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].GPC_Lines ; Count Down Lines + JZ @GPC_EXIT ; Ok... Done! + + JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey! + +@GPC_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +GPRINTC ENDP + + +;========================================== +;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%) +;========================================== +; +; Transparently draws an ASCII Text Character using the +; currently selected 8x8 font on the active display page. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; +; EXIT: No meaningful values returned +; + +TGP_STACK STRUC + TGP_Width DW ? ; Screen Width-1 + TGP_Lines DB ?,? ; Scan lines to Decode + TGP_T_SETS DW ? ; Saved Charset Segment + TGP_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TGP_ColorF DB ?,? ; Text Color + TGP_Ypos DW ? ; Y Position to Print at + TGP_Xpos DW ? ; X position to Print at + TGP_Char DB ?,? ; Character to Print +TGP_STACK ENDS + + PUBLIC TGPRINTC + +TGPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].TGP_Width, BX ; Save for later use + + MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].TGP_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].TGP_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @TGP_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @TGP_Set_Char ; Go Setup Character Ptr + +@TGP_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@TGP_Set_Char: + MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].TGP_Lines, AL ; Save on Stack + + MOV DS, [BP].TGP_T_SETS ; Point to character set + +@TGP_DECODE_CHAR_BYTE: + + MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].TGP_T_SETO, SI ; And save new Pointer... + + MOV AH, [BP].TGP_ColorF ; Get Foreground Color + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@TGP_NO_LEFT1BITS: + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_MIDDLE1BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @TGP_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_RIGHT1BITS: + + DEC DI ; Adjust for Next Line Advance + +@TGP_NEXT_LINE: + ADD DI, [BP].TGP_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].TGP_Lines ; Count Down Lines + JZ @TGP_EXIT ; Ok... Done! + + JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey! + +@TGP_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit and Clean up Stack + +TGPRINTC ENDP + + +;=============================================================== +;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;=============================================================== +; +; Routine to quickly Print a null terminated ASCII string on the +; active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +PS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + PS_ColorB DW ? ; Background Color + PS_ColorF DW ? ; Text Color + PS_Ypos DW ? ; Y Position to Print at + PS_Xpos DW ? ; X position to Print at + PS_Len DW ? ; Maximum Length of string to print + PS_Text DW ?,? ; Far Ptr to Text String +PS_STACK ENDS + + PUBLIC PRINT_STR + +PRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@PS_Print_It: + + MOV CX, [BP].PS_Len ; Get Remaining text Length + JCXZ @PS_Exit ; Exit when out of text + + LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @PS_Exit ; Exit if null character + + DEC [BP].PS_Len ; Remaining Text length-- + INC [BP].PS_Text ; Point to Next text char + + ; Set up Call to GPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].PS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].PS_Xpos, BX ; Save for next time through + + MOV BX, [BP].PS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].PS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + MOV BX, [BP].PS_ColorB ; Get Background Color + PUSH BX ; Set ColorB Parameter + + CALL f GPRINTC ; Print Character! + JMP s @PS_Print_It ; Process next character + +@PS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 14 ; Exit and Clean up Stack + +PRINT_STR ENDP + + +;================================================================ +;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================================ +; +; Routine to quickly transparently Print a null terminated ASCII +; string on the active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; +; EXIT: No meaningful values returned +; + +TPS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TPS_ColorF DW ? ; Text Color + TPS_Ypos DW ? ; Y Position to Print at + TPS_Xpos DW ? ; X position to Print at + TPS_Len DW ? ; Maximum Length of string to print + TPS_Text DW ?,? ; Far Ptr to Text String +TPS_STACK ENDS + + PUBLIC TPRINT_STR + +TPRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@TPS_Print_It: + + MOV CX, [BP].TPS_Len ; Get Remaining text Length + JCXZ @TPS_Exit ; Exit when out of text + + LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @TPS_Exit ; Exit if null character + + DEC [BP].TPS_Len ; Remaining Text length-- + INC [BP].TPS_Text ; Point to Next text char + + ; Set up Call to TGPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].TPS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].TPS_Xpos, BX ; Save for next time through + + MOV BX, [BP].TPS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].TPS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + CALL f TGPRINTC ; Print Character! + JMP s @TPS_Print_It ; Process next character + +@TPS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TPRINT_STR ENDP + + +;=========================================== +;SET_DISPLAY_FONT(SEG FontData, FontNumber%) +;=========================================== +; +; Allows the user to specify their own font data for +; wither the lower or upper 128 characters. +; +; ENTRY: FontData = Far Pointer to Font Bitmaps +; FontNumber = Which half of set this is +; = 0, Lower 128 characters +; = 1, Upper 128 characters +; +; EXIT: No meaningful values returned +; + +SDF_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDF_Which DW ? ; Hi Table/Low Table Flag + SDF_Font DD ? ; Far Ptr to Font Table +SDF_STACK ENDS + + PUBLIC SET_DISPLAY_FONT + +SET_DISPLAY_FONT PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, [BP].SDF_Font ; Get Far Ptr to Font + + MOV SI, o CHARSET_LOW ; Assume Lower 128 chars + TEST [BP].SDF_Which, 1 ; Font #1 selected? + JZ @SDF_Set_Font ; If not, skip ahead + + MOV SI, o CHARSET_HI ; Ah, really it's 128-255 + +@SDF_Set_Font: + MOV [SI], DI ; Set Font Pointer Offset + MOV [SI+2], ES ; Set Font Pointer Segment + + POP BP ; Restore Registers + RET 6 ; We are Done.. Outa here + +SET_DISPLAY_FONT ENDP + + + ; ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +;====================================================== +;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;====================================================== +; +; Draws a variable sized Graphics Bitmap such as a +; picture or an Icon on the current Display Page in +; Mode X. The Bitmap is stored in a linear byte array +; corresponding to (0,0) (1,0), (2,0) .. (Width, Height) +; This is the same linear manner as mode 13h graphics. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +DB_STACK STRUC + DB_LineO DW ? ; Offset to Next Line + DB_PixCount DW ? ; (Minimum) # of Pixels/Line + DB_Start DW ? ; Addr of Upper Left Pixel + DB_PixSkew DW ? ; # of bytes to Adjust EOL + DB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DB_Height DW ? ; Height of Bitmap in Pixels + DB_Width DW ? ; Width of Bitmap in Pixels + DB_Ypos DW ? ; Y position to Draw Bitmap at + DB_Xpos DW ? ; X position to Draw Bitmap at + DB_Image DD ? ; Far Pointer to Graphics Bitmap +DB_STACK ENDS + + PUBLIC DRAW_BITMAP + +DRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].DB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].DB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].DB_LineO, AX ; Save Line Width offset + MOV [BP].DB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].DB_PixSkew, DX ; Also End of Line Skew + MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@DB_COPY_PLANE: + + LDS SI, [BP].DB_Image ; DS:SI-> Source Image + MOV DX, [BP].DB_Height ; # of Lines to Copy + MOV DI, [BP].DB_Start ; ES:DI-> Dest pos + +@DB_COPY_LINE: + MOV CX, [BP].DB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @DB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@DB_COPY_LOOP: + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @DB_COPY_LOOP ; if so, do another block + +@DB_COPY_REMAINDER: + JCXZ @DB_NEXT_LINE ; Any Pixels left on line + +@DB_COPY2: + MOVSB ; Copy Bitmap Pixel + ADD SI,3 ; Skip to Next Byte in same plane + LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done + +@DB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].DB_SkewFlag ; Get Skew Count + JZ @DB_NEXT2 ; if no partial pixels + + MOVSB ; Copy Bitmap Pixel + DEC DI ; Back up to align + DEC SI ; Back up to align + +@DB_NEXT2: + ADD SI, [BP].DB_PixSkew ; Adjust Skew + ADD DI, [BP].DB_LineO ; Set to Next Display Line + LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more + + ; Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @DB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].DB_Start, 0 ; Screen Addr =+Carry + INC w [BP].DB_Image ; Start @ Next Byte + + SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP s @DB_COPY_PLANE ; Go Copy the Next Plane + +@DB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +DRAW_BITMAP ENDP + + +;======================================================= +;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;======================================================= +; +; Transparently Draws a variable sized Graphics Bitmap +; such as a picture or an Icon on the current Display Page +; in Mode X. Pixels with a value of 0 are not drawn, +; leaving the previous "background" contents intact. +; +; The Bitmap format is the same as for the DRAW_BITMAP function. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +TB_STACK STRUC + TB_LineO DW ? ; Offset to Next Line + TB_PixCount DW ? ; (Minimum) # of Pixels/Line + TB_Start DW ? ; Addr of Upper Left Pixel + TB_PixSkew DW ? ; # of bytes to Adjust EOL + TB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TB_Height DW ? ; Height of Bitmap in Pixels + TB_Width DW ? ; Width of Bitmap in Pixels + TB_Ypos DW ? ; Y position to Draw Bitmap at + TB_Xpos DW ? ; X position to Draw Bitmap at + TB_Image DD ? ; Far Pointer to Graphics Bitmap +TB_STACK ENDS + + PUBLIC TDRAW_BITMAP + +TDRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].TB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].TB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].TB_LineO, AX ; Save Line Width offset + MOV [BP].TB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].TB_PixSkew, DX ; Also End of Line Skew + MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@TB_COPY_PLANE: + + LDS SI, [BP].TB_Image ; DS:SI-> Source Image + MOV DX, [BP].TB_Height ; # of Lines to Copy + MOV DI, [BP].TB_Start ; ES:DI-> Dest pos + + ; Here AH is set with the value to be considered + ; "Transparent". It can be changed! + + MOV AH, 0 ; Value to Detect 0 + +@TB_COPY_LINE: + MOV CX, [BP].TB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @TB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@TB_COPY_LOOP: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_01 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_01: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_02 ; Skip ahead if so + MOV ES:[DI+1], AL ; Copy Pixel to VGA screen + +@TB_SKIP_02: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_03 ; Skip ahead if so + MOV ES:[DI+2], AL ; Copy Pixel to VGA screen + +@TB_SKIP_03: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_04 ; Skip ahead if so + MOV ES:[DI+3], AL ; Copy Pixel to VGA screen + +@TB_SKIP_04: + ADD DI, 4 ; Adjust Pixel Write Location + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @TB_COPY_LOOP ; if so, do another block + +@TB_COPY_REMAINDER: + JCXZ @TB_NEXT_LINE ; Any Pixels left on line + +@TB_COPY2: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_05 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_05: + INC DI ; Advance Dest Addr + LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done + +@TB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].TB_SkewFlag ; Get Skew Count + JZ @TB_NEXT2 ; if no partial pixels + + LODSB ; Get Pixel Value in AL + DEC SI ; Backup to Align + CMP AL, AH ; It is "Transparent"? + JE @TB_NEXT2 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_NEXT2: + ADD SI, [BP].TB_PixSkew ; Adjust Skew + ADD DI, [BP].TB_LineO ; Set to Next Display Line + LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More + + ;Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @TB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].TB_Start, 0 ; Screen Addr =+Carry + INC w [BP].TB_Image ; Start @ Next Byte + + SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP @TB_COPY_PLANE ; Go Copy the next Plane + +@TB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TDRAW_BITMAP ENDP + + + ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +;================================== +;COPY_PAGE (SourcePage%, DestPage%) +;================================== +; +; Duplicate on display page onto another +; +; ENTRY: SourcePage = Display Page # to Duplicate +; DestPage = Display Page # to hold copy +; +; EXIT: No meaningful values returned +; + +CP_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CP_DestP DW ? ; Page to hold copied image + CP_SourceP DW ? ; Page to Make copy from +CP_STACK ENDS + + PUBLIC COPY_PAGE + +COPY_PAGE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Block Xfer Forwards + + ; Make sure Page #'s are valid + + MOV AX, [BP].CP_SourceP ; Get Source Page # + CMP AX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + MOV BX, [BP].CP_DestP ; Get Destination Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + CMP AX, BX ; Pages #'s the same? + JE @CP_Exit ; if so, abort + + ; Setup DS:SI and ES:DI to Video Pages + + SHL BX, 1 ; Scale index to Word + MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page + + MOV BX, AX ; Index to Source page + SHL BX, 1 ; Scale index to Word + MOV SI, PAGE_ADDR[BX] ; Offset to Source Page + + MOV CX, PAGE_SIZE ; Get size of Page + MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment + MOV ES, AX ; ES:DI -> Dest Page + MOV DS, AX ; DS:SI -> Source Page + + ; Setup VGA registers for Mem to Mem copy + + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes + + ; Note.. Do *NOT* use MOVSW or MOVSD - they will + ; Screw with the latches which are 8 bits x 4 + + REP MOVSB ; Copy entire Page! + + ; Reset VGA for normal memory access + + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off + +@CP_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +COPY_PAGE ENDP + + +;========================================================================== +;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%) +;========================================================================== +; +; Copies a Bitmap Image from one Display Page to Another +; This Routine is Limited to copying Images with the same +; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4) +; Copying an Image to the Same Page is supported, but results +; may be defined when the when the rectangular areas +; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) - +; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap... +; No Paramter checking to done to insure that +; X2 >= X1 and Y2 >= Y1. Be Careful... +; +; ENTRY: SourcePage = Display Page # with Source Image +; X1 = Upper Left Xpos of Source Image +; Y1 = Upper Left Ypos of Source Image +; X2 = Lower Right Xpos of Source Image +; Y2 = Lower Right Ypos of Source Image +; DestPage = Display Page # to copy Image to +; DestX1 = Xpos to Copy UL Corner of Image to +; DestY1 = Ypos to Copy UL Corner of Image to +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +CB_STACK STRUC + CB_Height DW ? ; Height of Image in Lines + CB_Width DW ? ; Width of Image in "bands" + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CB_DestY1 DW ? ; Destination Ypos + CB_DestX1 DW ? ; Destination Xpos + CB_DestP DW ? ; Page to Copy Bitmap To + CB_Y2 DW ? ; LR Ypos of Image + CB_X2 DW ? ; LR Xpos of Image + CB_Y1 DW ? ; UL Ypos of Image + CB_X1 DW ? ; UL Xpos of Image + CB_SourceP DW ? ; Page containing Source Bitmap +CB_STACK ENDS + + PUBLIC COPY_BITMAP + +COPY_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 4 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + ; Prep Registers (and keep jumps short!) + + MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram + CLD ; Block Xfer Forwards + + ; Make sure Parameters are valid + + MOV BX, [BP].CB_SourceP ; Get Source Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV CX, [BP].CB_DestP ; Get Destination Page # + CMP CX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV AX, [BP].CB_X1 ; Get Source X1 + XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1 + AND AX, PLANE_BITS ; Check Plane Bits + JNZ @CB_Abort ; They should cancel out + + ; Setup for Copy processing + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + + ; Compute Info About Images, Setup ES:SI & ES:DI + + MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines + SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1 + INC AX ; (add 1 since were not 0 based) + MOV [BP].CB_Height, AX ; Save on Stack for later use + + MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels + MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1 + SHR AX, 2 ; Get X2 Band (X2 / 4) + SHR DX, 2 ; Get X1 Band (X1 / 4) + SUB AX, DX ; AX = # of Bands - 1 + INC AX ; AX = # of Bands + MOV [BP].CB_Width, AX ; Save on Stack for later use + + SHL BX, 1 ; Scale Source Page to Word + MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page + MOV AX, [BP].CB_Y1 ; Get Source Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD SI, AX ; SI = Offset to Line Y1 + MOV AX, [BP].CB_X1 ; Get Source X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD SI, AX ; SI = Byte Offset to (X1,Y1) + + MOV BX, CX ; Dest Page Index to BX + SHL BX, 1 ; Scale Source Page to Word + MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page + MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD DI, AX ; DI = Offset to Line Y1 + MOV AX, [BP].CB_DestX1 ; Get Dest X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1) + + MOV CX, [BP].CB_Width ; CX = Width of Image (Bands) + DEC CX ; CX = 1? + JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band + + MOV BX, [BP].CB_X1 ; Get Source X1 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?) + JZ @CB_Check_Right ; if so, check right alignment + JNZ @CB_Left_Band ; not aligned? well.. + +@CB_Abort: + CLR AX ; Return False (Failure) + JMP @CB_Exit ; and Finish Up + + ; Copy when Left & Right Clip Masks overlap... + +@CB_Only_One_Band: + MOV BX, [BP].CB_X1 ; Get Left Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask + MOV BX, [BP].CB_X2 ; Get Right Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_One_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_One_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_One_Loop ; Loop until Finished + +@CB_One_Done: + JMP @CB_Finish ; Outa Here! + + ; Copy Left Edge of Bitmap + +@CB_Left_Band: + + OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_Left_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Left_Loop ; Loop until Finished + +@CB_Left_Done: + INC DI ; Move Dest Over 1 band + INC SI ; Move Source Over 1 band + DEC [BP].CB_Width ; Band Width-- + + ; Determine if Right Edge of Bitmap needs special copy + +@CB_Check_Right: + MOV BX, [BP].CB_X2 ; Get Source X2 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?) + CMP BL, 03h ; Plane = 3? + JE @CB_Copy_Middle ; Copy the Middle then! + + ; Copy Right Edge of Bitmap + +@CB_Right_Band: + + OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask + + DEC [BP].CB_Width ; Band Width-- + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + MOV BX, [BP].CB_Width ; BX = Offset to Right Edge + +@CB_Right_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Right_Loop ; Loop until Finished + +@CB_Right_Done: + + ; Copy the Main Block of the Bitmap + +@CB_Copy_Middle: + + MOV CX, [BP].CB_Width ; Get Width Remaining + JCXZ @CB_Finish ; Exit if Done + + OUT_8 SC_Data, ALL_PLANES ; Copy all Planes + + MOV DX, SCREEN_WIDTH ; Get Width of Screen minus + SUB DX, CX ; Image width (for Adjustment) + MOV AX, [BP].CB_Height ; AX = # of Lines to Copy + MOV BX, CX ; BX = Quick REP reload count + MOV CX, ES ; Move VGA Segment + MOV DS, CX ; Into DS + + ; Actual Copy Loop. REP MOVSB does the work + +@CB_Middle_Copy: + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + LOOPjz AX, @CB_Finish ; Exit Loop if Finished + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done + +@CB_Finish: + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on + +@CB_Exit: + ADD SP, 04 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 16 ; Exit and Clean up Stack + +COPY_BITMAP ENDP + + END ; End of Code Segment diff --git a/16/modex105/MODEX.BI b/16/modex105/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/modex105/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/modex105/MODEX.H b/16/modex105/MODEX.H new file mode 100644 index 00000000..7de25a63 --- /dev/null +++ b/16/modex105/MODEX.H @@ -0,0 +1,76 @@ + +#ifndef __MODEX_H +#define __MODEX_H + + /* ===== SCREEN RESOLUTIONS ===== */ + +#define Mode_320x200 0 +#define Mode_320x400 1 +#define Mode_360x200 2 +#define Mode_360x400 3 +#define Mode_320x240 4 +#define Mode_320x480 5 +#define Mode_360x240 6 +#define Mode_360x480 7 + + /* ===== MODE X SETUP ROUTINES ===== */ + +int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages); +int far pascal set_modex (int Mode); + + /* ===== BASIC GRAPHICS PRIMITIVES ===== */ + +void far pascal clear_vga_screen (int Color); +void far pascal set_point (int Xpos, int Ypos, int Color); +int far pascal read_point (int Xpos, int Ypos); +void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); +void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); + + /* ===== DAC COLOR REGISTER ROUTINES ===== */ + +void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue); +void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue); +void far pascal load_dac_registers (char far *PalData, int StartReg, + int EndReg, int VSync); +void far pascal readd_dac_registers (char far *PalData, int StartReg, + int EndReg); + + /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */ + +void far pascal set_active_page (int PageNo); +int far pascal get_active_page (void); +void far pascal set_display_page (int PageNo); +int far pascal get_display_page (void); +void far pascal set_window (int DisplayPage, int XOffset, int YOffset); +int far pascal get_x_offset (void); +int far pascal get_y_offset (void); +void far pascal sync_display (void); + + /* ===== TEXT DISPLAY ROUTINES ===== */ + +void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF, + int ColorB); +void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF); +void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF, int ColorB); +void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF); +void far pascal set_display_font (char far *FontData, int FontNumber); + + /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */ + +void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); +void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); + + /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */ + +void far pascal copy_page (int SourcePage, int DestPage); +void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2, + int DestPage, int DestX1, int DestY1); + + +#endif diff --git a/16/modex105/PACKING.LST b/16/modex105/PACKING.LST new file mode 100644 index 00000000..88f817ca --- /dev/null +++ b/16/modex105/PACKING.LST @@ -0,0 +1,87 @@ + +PACKING LIST FOR MODEX104 + +DIRECTORY: \ - The Mode X Library versoon 1.04 + +ASM BAT 26 05-14-93 6:00p - Batch File to Assemble MODEX.ASM +MODE-X TXT 2135 05-14-93 6:00p - File Describing MODE X Routines +MODEX ASM 117039 05-14-93 6:00p - Assembly source to Mode X Library +MODEX BI 3238 05-14-93 6:00p - Include File for BASIC/PDS +MODEX H 2943 05-14-93 6:00p - Include File for C/C++ +MODEX OBJ 5208 05-14-93 6:00p - The Mode X Library +README DOC 3259 05-14-93 6:00p - Information on this Product +PACKING LST 4767 05-14-93 6:00p - This File + +DIRECTORY: \DEMOS - Mode X Demos + +CHARDEMO EXE 13066 05-14-93 6:00p - Demo of Multiple Fonts & Color Cycling +TEST6 EXE 19990 05-14-93 6:00p - Main Mode X Demo +ROM_8X8 FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE +SPACEAGE FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE +SYSTEM FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE + +DIRECTORY: \DEMOS\BASIC7 - Demo Sources for Microsoft BASIC 7.1 (PDS) + +MAKE-LIB BAT 166 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB +MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library +MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QBX +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File +MODEX QLB 11141 05-14-93 6:00p - Mode X & Utility Quick Library +TEST6 BAS 12733 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE) +UASM-BC7 BAT 43 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QBX +UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source +UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes +UTILS OBJ 681 05-14-93 6:00p - Basic Utilities - Object File +CHARDEMO BAS 3431 05-14-93 6:00p - Source to CHARDEMO.EXE + +DIRECTORY: \DEMOS\C - Demo Sources for Borland C/C++ + +C_UTILS ASM 8782 05-14-93 6:00p - C Utilities - Assembler source +C_UTILS H 2623 05-14-93 6:00p - C Utilities - C Includes +C_UTILS OBJ 648 05-14-93 6:00p - C Utilities - Object File +MODEX H 2943 05-14-93 6:00p - Mode X Library C Incldues +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library +UTLS-ASM BAT 36 05-14-93 6:00p - Batch File to Make C_UTILS.OBJ +X-DEMO C 15085 05-14-93 6:00p - Source to Main Demo (TEST6) in C +X-DEMO EXE 41090 05-14-93 6:00p - C Version of Main Demo +X-DEMO PRJ 5188 05-14-93 6:00p - Borland C Project file + +DIRECTORY: \DEMOS\PASCAL - Demo Sources for Turbo Pascal + +TEST5 PAS 15873 05-14-93 6:00p - Source for a TP Version of TEST6.EXE + +DIRECTORY: \DEMOS\QB45 - Demo Sources for Microsoft QuickBASIC 4.5 + +MAKE-LIB BAT 164 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB +MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library +MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QB45 +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File +MODEX QLB 9739 05-14-93 6:00p - Mode X & Utility Quick Library/QB45 +TEST6A BAS 12743 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE) +TEST6A EXE 40544 05-14-93 6:00p - QB45 Version of Main Demo +UASM-QB4 BAT 30 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QB45 +UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source +UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes +UTILS OBJ 628 05-14-93 6:00p - Basic Utilities - Object File + +DIRECTORY: \FONTEDIT - Font Editor + +CSEDIT EXE 39242 05-14-93 6:00p - Font Editor Program +CSEDIT DOC 8629 05-14-93 6:00p - Font Editor Documentation +CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor +MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor +PALETTE CS 768 05-14-93 6:00p - Palette for Editor +INVERSE FNT 1024 05-14-93 6:00p - Sample Font +ROM_8X8 FNT 1024 05-14-93 6:00p - Sample Font +SPACEAGE FNT 1024 05-14-93 6:00p - Sample Font +SYSTEM FNT 1024 05-14-93 6:00p - Sample Font + +DIRECTORY: \PALEDIT - Palette Editor + +PALEDIT EXE 31954 05-14-93 6:00p - Palette Editor Program +PALEDIT DOC 6688 05-14-93 6:00p - Palette Editor Documentation +CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor +MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor +GAMECOLR PAL 768 05-14-93 6:00p - Sample Palette +PRIME PAL 768 05-14-93 6:00p - Sample Palette +RGB PAL 768 05-14-93 6:00p - Sample Palette diff --git a/16/modex105/PALEDIT/CHARSETS.CS b/16/modex105/PALEDIT/CHARSETS.CS new file mode 100644 index 00000000..97fe608f Binary files /dev/null and b/16/modex105/PALEDIT/CHARSETS.CS differ diff --git a/16/modex105/PALEDIT/GAMECOLR.PAL b/16/modex105/PALEDIT/GAMECOLR.PAL new file mode 100644 index 00000000..621b1e5e Binary files /dev/null and b/16/modex105/PALEDIT/GAMECOLR.PAL differ diff --git a/16/modex105/PALEDIT/MOUSEIMG.CS b/16/modex105/PALEDIT/MOUSEIMG.CS new file mode 100644 index 00000000..101e2084 Binary files /dev/null and b/16/modex105/PALEDIT/MOUSEIMG.CS differ diff --git a/16/modex105/PALEDIT/PALEDIT.DOC b/16/modex105/PALEDIT/PALEDIT.DOC new file mode 100644 index 00000000..61d0b2ee --- /dev/null +++ b/16/modex105/PALEDIT/PALEDIT.DOC @@ -0,0 +1,166 @@ + +PALEDIT - A Simple VGA 256 Color Palette Editor + + +PALEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X +Library for VGA Graphics. + +WHAT YOU NEED TO RUN PALEDIT: + + * A Vga Monitor + * A Microsoft Compatible Mouse + + A Mouse is most definitely required, as the keyboard is used for + nothing except entering file names. + +FILES NEEDED IN THE CURRENT DIRECTORY: + + PALEDIT.EXE - The Palette Editor Program + CHARSETS.CS - The Palette Editor's Internal Fonts + MOUSEIMG.CS - The Palette Editor's Mouse Pointer + +SAMPLE PALETTE FILE THAT SHOULD BE INCLUDED: + + RGB.PAL - A Simple Palette with Reds, Greens, and Blues + PRIME.PAL - A Simple Palette + GAMECOLR.PAL - A Bright Palette from a Game of mine. + +WHAT IT EDITS: + + The VGA DAC Registers, all 256 of them. + +HOW IT WORKS/FEATURES: + + PALEDIT allows the user to see the entire VGA Palette of 256 colors + and select and modify the RED, GREEN, and BLUE values of any individual + color (DAC) register. The entire group of 256 colors can be saved to + a disk file for later retrieval. + + Individual "SLIDERS" show the current RED, GREEN, and BLUE color + components of the current color and allow them to be changed. + + The Following operations can be performed. + + * Raise, Lower, and set the RED, GREEN, or BLUE components. + * Copy the current RGB values to another Color (DAC) Register + * Brighten the selected color + * Darken and selected color + * Reset the selected color to its original state + * Blend an entire range of colors, creating a smooth + Transition from one color to another + * Optionally Lock out the first 16 colors to prevent + Accidental Modification + +DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN: + + COLOR SLIDERS: In the upper left of the screen there are + Three Rectangular Boxes: One for each primary color: + RED, GREEN, and BLUE. Each Box has an arrow at each + end, and a scale bar in the middle, connecting the two + arrows. The scale bar is much like a thermometer, + indicating how much of that color is in the selected + color. To the right of each Box, the name of the color + is indicated, along with the content color in the form + of a number from 0 to 63; where 0 means none of that + color goes into making the selected color, and 63 means + that the selected color is saturated with that color. + + Clicking the mouse on the slider's left arrow box will + decrease the amount of that primary color in the selected + color. Holding the mouse button down will reduce the + color value all the way to 0. + + Clicking the mouse on the slider's right arrow box will + increase the amount of that primary color in the selected + color. Holding the mouse button down will increase the + color value all the way to 63. + + Clicking the mouse on the scale bar will set the amount + of that primary color to the value the represents that + position on the slider. + + LOCK Button: Clicking the button toggles the lockout of the + first 16 colors. When they are locked out, they can not + be modified, and when selected the word "LOCKED" will + appear below the color # on the Color Information Display. + + LOAD Button: Clicking this button will load the Palette file + that is named in the Palette File name box. If no name is + given or no such file exists, then nothing will be loaded. + + SAVE Button: Clicking this button will save the current Palette + in a file using the name given in the Palette File Name Box. + If a Valid name is not provided, nothing will be saved. + + QUIT Button: Clicking this button will return you to DOS. + Nothing is saved, and no confirmation is given. + + + Color Information Display: This Box is on the left side of the + Screen, below the Color Sliders. It shows the number of the + currently selected color (from 0 to 255) and indicates if + that color is locked. To the right of this box is a big + square showing the current color. + + LIGHTER Button: Clicking this button will make the selected + color brighter. + + DARKER Button: Clicking this button will make the selected + color darker. + + RESET Button: Clicking this button will restore the selected + color to the value it had when it was first selected. + + BLEND Button: Clicking this button will let you Blend a range + of colors together. One end of the range of colors is the + currently selected color. After Clicking the BLEND button. + You must click on the color at the other end of the range + in the Palette Display Box. All of the colors in between + those two colors will be changed to represent a gradual + transition from the color at one end to the color at the + other end. + + PALETTE FILE NAME BOX: This Text Box is used to enter the name + of a Palette file to load or the name to save the current + Palette as. Just click on the Box, and it will change color + and a flashing cursor will appear. Now you type in a filename + or edit the existing filename. Press or click + outside the text box to end editing. + + PALETTE DISPLAY BOX: This Box shows all 256 colors in an array + of 32 by 8 color blocks. The Currently Selected Color will + have a Box around it. Clicking on a color with the Left + Mouse button will make that color the new currently selected + color. Clicking on a color with the Right Mouse Button will + copy the color value from the old selected color to it, before + it is made the new selected color. + + Message Bar: At the very bottom of the screen, this Bar will display + information and messages for various functions. + +PALETTE FILE FORMAT: + + BINARY image, in order of VGA DAC (Color) Number. 3 Bytes Per + Color, 256 Colors. 768 Bytes total. The Files will be exactly + 768 bytes in size. + + COLOR: + RED: 1 BYTE + GREEN: 1 BYTE + BLUE: 1 BYTE + + PALETTE: Array (0 to 255) of COLOR + +COMMENTS, QUESTIONS, BUG REPORTS, etc: + + Send the to the Author: Matt Pritchard + + Through the 80xxx Fidonet Echo or + + Matt Pritchard + P.O. Box 140264 + Irving, TX 75014 + +CREDITS: + + This Palette Editor was written in QuickBASIC 4.5 diff --git a/16/modex105/PALEDIT/PALEDIT.EXE b/16/modex105/PALEDIT/PALEDIT.EXE new file mode 100644 index 00000000..f69e172d Binary files /dev/null and b/16/modex105/PALEDIT/PALEDIT.EXE differ diff --git a/16/modex105/PALEDIT/PRIME.PAL b/16/modex105/PALEDIT/PRIME.PAL new file mode 100644 index 00000000..310ca6e7 Binary files /dev/null and b/16/modex105/PALEDIT/PRIME.PAL differ diff --git a/16/modex105/PALEDIT/RGB.PAL b/16/modex105/PALEDIT/RGB.PAL new file mode 100644 index 00000000..bc03425d Binary files /dev/null and b/16/modex105/PALEDIT/RGB.PAL differ diff --git a/16/modex105/README.DOC b/16/modex105/README.DOC new file mode 100644 index 00000000..63a9053f --- /dev/null +++ b/16/modex105/README.DOC @@ -0,0 +1,76 @@ + +========================================================================= + þ þ þþþþþ þþþþ þþþþþ þ þ þ þþþþþ þ þ + þþ þþ þ þ þ þ þ þ þ þþ þ þ þ þ + þ þ þ þ þ þ þ þþþþ þ þ þ þ þ þþþþþ + þ þ þ þ þ þ þ þ þ þ þ þ þ + þ þ þþþþþ þþþþ þþþþþ þ þ þþþþþ þþ þþþþþ þ +========================================================================= + MODE X 1.04 +========================================================================= + Library & Editors by Matt Pritchard: Release 1.04 on 14 Mar 93 +========================================================================= + +MODEX104 is a library of high performance assembler routines for setting, +accessing, and manipulating the Undocumented 256 Color Modes available in +all VGA adaptors. + +MODEX104 includes the following elements: + + MODE X Library - A library of MODE X routines written in assembly. + + FONT EDITOR - An editor for creating and modifying fonts for use by + The MODE X Library. + + PALETTE EDITOR - An editor for creating and modifying palettes for + use in VGA 256 Color modes. + + MODE X Demos - Programs that show off the various features of the + MODE X Library + + MODE X Demo Source - The Full source code for the MODE X Demos for + the following Languages: Microsoft QuickBASIC 4.5, + Microsoft BASIC 7.1 PDS, Borland C/C++ 3.1, + and Borland Turbo Pascal. + +THE LEGAL STUFF: + + The Mode X Library has been placed into the Public Domain by the + Author (Matt Pritchard). The Font Editor and Palette Editor are also + placed into the Public Domain by the Author (Matt Pritchard). The + Source Code to the above editors is not in the Public Domain. + + The Mode X Demos and the Mode X Demo Sources have been placed into the + Public domain by the Author (Matt Pritchard). + + The Mode X Library may be used freely in any non commerical product. + It would be nice if the author was credited for the contribution, + but it is not necessary. No $$$ involved. + + The Mode X Library may be used freely in a commercial product, *IF* + the author (Matt Pritchard) is credited for the contribution. That's + it. No $$$ involved. + + The Mode X Library should not be re-sold or modified and re-sold. + No fee in excess of $5 should be charged for duplication of this + Library. + +CONTRIBUTORS: The following people have contributed to this effort. + + Michael Abrash - He told us all how to do it in the first place. + Scott Wyatt - He ported the Main Demo code to Turbo Pascal. + +THE AUTHOR: + + The author of MODEX104 is Matt Pritchard. + All Questions and correspondance can be directed to: + + "Matt Pritchard" on Fido Net ECHO Conference: 80xxx + + or mailed to: Matt Pritchard + P.O. Box 140264 + Irving, TX 75014-0264 + + Questions, Inquiries, Comments, Donations, etc are quite welcome. + +