home *** CD-ROM | disk | FTP | other *** search
- _GRAPHICS PROGRAMMING COLUMN_
- by Michael Abrash
-
-
- [LISTING ONE]
-
- /* Utility to force an ET4000-based VGA into 16- or 8-bit operation even if
- a monochrome adapter is in the system. (Note that only 16-bit memory access,
- not 16-bit I/O, is enabled; the I/O state is not altered.) The monochrome
- adapter won't work properly while SETBUS 16 is in effect. Tested with
- Borland C++ 3.0. Courtesy of Charles Marslett of STB. Commented and
- reformatted by Michael Abrash. */
-
- /*****************************************************************************
- * This utility isn't known to cause problems, but use it at your own risk, as
- * the monochrome and VGA adapters will both respond to accesses to monochrome
- * display memory while SETBUS 16 is in effect, resulting in bus contention.
- ****************************************************************************/
- #include <dos.h>
- #include <stdio.h>
- #include <string.h>
-
- void main(int argc, char *argv[])
- {
- int crtc, val;
- union REGS regset;
-
- if (inp(0x3CC) & 0x01) /* decide where to address the CRT */
- crtc = 0x3D4; /* Controller by reading the I/O */
- else /* Address Select bit of the */
- crtc = 0x3B4; /* Miscellaneous Output register */
-
- outportb(0x3BF, 0x03); /* key sequence to enable access to */
- outportb(crtc+4, 0xA0); /* ET4000-specific registers */
- outportb(crtc, 0x36); /* get the current setting of the Video */
- val = inp(crtc+1); /* System Configuration 1 register */
-
- /* Decide whether 16- or 8-bit access desired, and configure accordingly */
- if (argc == 2) {
- if (strcmp(argv[1], "16") == 0) {
- outportb(crtc+1, val | 0x40); /* 16-bit memory access */
- goto ModeSet;
- } else if (strcmp(argv[1], "8") == 0) {
- outportb(crtc+1, val & 0xBF); /* 8-bit memory access */
- ModeSet:
- regset.x.ax = 0x0003;
- int86(0x10, ®set, ®set); /* do a text mode mode set */
- exit(0);
- }
- }
- fprintf(stderr, "Usage: SETBUS 16\n");
- fprintf(stderr, " or SETBUS 8\n");
- exit(1);
- }
-
-
-
- [LISTING TWO]
-
- /* Function to tell the BIOS to set up properly sized characters for 25 rows of
- 16 pixel high text in 640x400 graphics mode. Call immediately after mode set.
- Based on a contribution by Bill Lindley. */
-
- #include <dos.h>
-
- void Set640x400()
- {
- union REGS regs;
-
- regs.h.ah = 0x11; /* character generator function */
- regs.h.al = 0x24; /* use ROM 8x16 character set for graphics */
- regs.h.bl = 2; /* 25 rows */
- int86(0x10, ®s, ®s); /* invoke the BIOS video interrupt
- to set up the text */
- }
-
-
-
- [LISTING THREE]
-
-
- /* Draws the 8x8 monochrome icon pointed to by IconPtr at coordinates (X,Y) in
- the DestWidth-wide bitmap starting at DestSeg:0, using the transparent
- replace raster op and color Color. Destination bitmap must be an
- 8-bit-per-pixel bitmap. 1-bits in the pattern are converted to drawing color
- and drawn, and 0-bits are skipped over, preserving destination (that is, are
- transparent). Tested with Borland C++ 3.0; when USE_C is 0, uses
- BC++ dependent inline assembly. */
-
- #define USE_C 0 /* set to 1 to compile C code, 0 to compile assembler */
- #if !USE_C
- #pragma inline /* tell the compiler there's inline ASM code */
- #else
- #include <dos.h>
- #endif
-
- void DrawReplaceXpar(unsigned int X, unsigned int Y,
- unsigned int DestSeg, unsigned int DestWidth,
- unsigned int Color, unsigned char *IconPtr)
- {
- #if USE_C
- unsigned char far *ScreenPtr, Temp;
- int i,j;
-
- /* Point to the first destination pixel */
- ScreenPtr = MK_FP(DestSeg, Y*DestWidth+X);
- for (i=0; i<8; i++) { /* do the 8 icon rows */
- Temp = *IconPtr++; /* get the next icon row */
- for (j=0; j<8; j++) { /* do the 8 pixels per icon row */
- if (Temp & 0x80) /* draw this pixel if the */
- *ScreenPtr = Color; /* corresponding icon bit is 1 */
- ScreenPtr++; /* point to the next destination pixel */
- Temp <<= 1; /* shift the next icon bit into place */
- }
- /* Point to the start of the next row */
- ScreenPtr += DestWidth - 8;
- }
- #else
- asm cld /* make LODSB increment SI */
- asm mov es,DestSeg /* point ES to the bitmap */
- asm mov ax,Y
- asm mov bx,DestWidth
- asm mul bx /* DestWidth*Y+X = offset of first */
- asm add ax,X /* dest pixel */
- asm mov di,ax /* point ES:DI to the first dest pixel */
- asm mov si,IconPtr /* point DS:SI to the first icon byte */
- asm mov dx,8 /* we'll do 8 rows */
- asm mov ah,byte ptr Color /* color we'll draw with */
- asm sub bx,8 /* offset from end of one dest row to start of next */
- RowLoop:
- asm lodsb /* get the next icon row */
- asm mov cx,8 /* we'll do 8 pixels on each row */
- PixelLoop:
- asm shl al,1 /* shift the next icon bit into CF */
- asm jnc NoDraw /* bit is 0, so don't draw */
- asm mov es:[di],ah /* bit is 1, so draw this pixel */
- NoDraw:
- asm inc di /* point to the next destination pixel */
- asm loop PixelLoop /* do the next pixel */
- asm add di,bx /* point to the start of the next dest row */
- asm dec dx /* count down rows */
- asm jnz RowLoop /* do the next row */
- #endif
- }
-
-
- [LISTING FOUR]
-
- /* Compiled bitblit code for drawing the 8x8 monochrome icon pointed to by
- IconPtr at coordinates (X,Y) in the DestWidth-wide bitmap starting at
- DestSeg:0, using the transparent replace raster op and color Color.
- CompileReplaceXpar() generates code to perform desired bitblit, and
- ExecuteCompiled() executes that code to perform bitblit. Generally faster than
- a standard approach when drawing the same icon many times, because this way
- color expansion, transparency, and reading the source are only performed once,
- at expansion time, rather than every time an icon is drawn. Destination bitmap
- must be an 8-bit-per-pixel bitmap. 1-bits in pattern are converted to drawing
- color and drawn, and 0-bits are skipped over, preserving destination (that is,
- are transparent). Tested with Borland C++ 3.0; uses BC++ dependent inline
- assembly. */
-
- #pragma inline /* tell the compiler there's inline ASM code */
-
- /* Generates far-callable code to bitblit the specified icon, and stores code
- in BufferToCompileInto. Code is simply a series of MOV [DI+xxxx],AL
- instructions, where xxxx is the offset from upper left corner of icon of
- each pixel to be drawn. */
- void CompileReplaceXpar(unsigned int DestWidth,
- unsigned char *IconPtr, unsigned char *BufferToCompileInto)
- {
- unsigned int i, j, PixelOffset = 0;
- unsigned char Temp;
-
- for (i=0; i<8; i++) { /* do the 8 icon rows */
- Temp = *IconPtr++; /* get the next icon row */
- for (j=0; j<8; j++) { /* do the 8 pixels per icon row */
- if (Temp & 0x80) { /* generate the code to draw this pixel if the
- corresponding icon bit is 1. Code is the hex bytes
- for the instruction MOV [DI+PixelOffset],AL */
- *BufferToCompileInto++ = 0x88; /* MOV opcode */
- *BufferToCompileInto++ = 0x85; /* mod-reg-rm byte */
- *((unsigned int *)BufferToCompileInto)++ = PixelOffset;
- /* addressing displacement */
- }
- PixelOffset++; /* point to the next destination pixel */
- Temp <<= 1; /* shift the next icon bit into place */
- }
- /* Point to the start of the next row in the destination */
- PixelOffset += DestWidth - 8;
- }
- /* Put a RET at the end to return to the calling code, and done */
- *BufferToCompileInto = 0xCB; /* RETF instruction = 0xCB */
- }
- void ExecuteCompiled(unsigned int X, unsigned int Y,
- unsigned int DestSeg, unsigned int DestWidth, unsigned int Color,
- unsigned char far *BufferToExecute)
- {
- asm push ds /* preserve the default data segment */
- asm mov ds,DestSeg /* point ES to the bitmap */
- asm mov ax,Y
- asm mul word ptr DestWidth /* DestWidth*Y+X = offset of */
- asm add ax,X /* first dest pixel */
- asm mov di,ax /* point ES:DI to the first dest pixel */
- asm mov al,Color /* color with which to draw */
- asm call dword ptr BufferToExecute
- /* perform a far call to execute the
- compiled bitblit code, and done */
- asm pop ds /* restore the default data segment */
- }
-
-
-
- [LISTING FIVE]
-
- /* Sample program to tile screen with an 8x8 monochrome icon.
- Tested with Borland C++ 3.0. */
-
- #include <dos.h>
- #include <conio.h>
-
- #define USE_COMPILED_BITBLITS 1 /* set to 1 and link to Listing 4 to use
- compiled biblits, set to 0 and link to
- Listing 3 to use conventional bitblits */
- #define SCREEN_WIDTH 320
- #define SCREEN_HEIGHT 200
- #define SCREEN_SEGMENT 0xa000
-
- #if USE_COMPILED_BITBLITS
- extern void CompileReplaceXpar(unsigned int, unsigned char *, unsigned char *);
- extern void ExecuteCompiled(unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned char far *);
- #else
- extern void DrawReplaceXpar(unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int, unsigned char *);
- #endif
-
- static unsigned char TestIcon[8] =
- {0x88, 0x44, 0x22, 0x11, 0x11, 0x22, 0x44, 0x88};
- #if USE_COMPILED_BITBLITS
- /* Storage for the compiled icon-drawing code; must be large enough for the
- largest possible code size, because no error checking is performed */
- static unsigned char CompiledBuffer[1000];
- #endif
-
- void main()
- {
- unsigned int x, y;
- union REGS regset;
- #if USE_COMPILED_BITBLITS
- unsigned char far *CompiledBufferPtr;
- #endif
- regset.x.ax = 0x0013; /* AL = 0x13 selects 320x200 */
- int86(0x10, ®set, ®set); /* 256-color graphics mode */
- #if USE_COMPILED_BITBLITS
- /* Generate the code for drawing the icon with the transparent
- replace raster op, and store the code in CompiledBuffer */
- CompileReplaceXpar(SCREEN_WIDTH, TestIcon, CompiledBuffer);
- CompiledBufferPtr = MK_FP(_DS, CompiledBuffer);
- #endif
- /* Tile TestIcon over the entire screen */
- for (y=0; y<SCREEN_HEIGHT; y += 8) {
- for (x=0; x<SCREEN_WIDTH; x += 8) {
- #if USE_COMPILED_BITBLITS
- /* Draw the icon by executing the code in CompiledBuffer */
- ExecuteCompiled(x, y, SCREEN_SEGMENT, SCREEN_WIDTH, 14,
- CompiledBufferPtr);
- #else
- /* Draw the icon with the transparent replace raster op, color
- expanding it and handling transparency on the fly */
- DrawReplaceXpar(x, y, SCREEN_SEGMENT, SCREEN_WIDTH, 14,TestIcon);
- #endif
- }
- }
- getch(); /* wait for a key press */
- regset.x.ax = 0x0003; /* AL = 3 selects 80x25 text mode */
- int86(0x10, ®set, ®set); /* return to text mode */
- exit(1); /* done */
- }
-
-
-