_GRAPHICS PROGRAMMING COLUMN_ by Michael Abrash [LISTING ONE] /* Demonstrates non-antialiased drawing in 256 color mode. Tested with Borland C++ 2.0 in C mode in the small model. */ #include #include #include "polygon.h" /* Draws the polygon described by the point list PointList in color Color with all vertices offset by (X,Y) */ #define DRAW_POLYGON(PointList,Color,X,Y) \ Polygon.Length = sizeof(PointList)/sizeof(struct Point); \ Polygon.PointPtr = PointList; \ FillConvexPolygon(&Polygon, Color, X, Y); void main(void); extern int FillConvexPolygon(struct PointListHeader *, int, int, int); /* Palette RGB settings to load the first four palette locations with black, pure blue, pure green, and pure red */ static char Palette[4*3] = {0, 0, 0, 0, 0, 63, 0, 63, 0, 63, 0, 0}; void main() { struct PointListHeader Polygon; static struct Point Face0[] = {{198,138},{211,89},{169,44},{144,89}}; static struct Point Face1[] = {{153,150},{198,138},{144,89},{105,113}}; static struct Point Face2[] = {{169,44},{133,73},{105,113},{144,89}}; union REGS regset; struct SREGS sregs; /* Set the display to VGA mode 13h, 320x200 256-color mode */ regset.x.ax = 0x0013; int86(0x10, ®set, ®set); /* Set color 0 to black, color 1 to pure blue, color 2 to pure green, and color 3 to pure red */ regset.x.ax = 0x1012; /* load palette block BIOS function */ regset.x.bx = 0; /* start with palette register 0 */ regset.x.cx = 4; /* set four palette registers */ regset.x.dx = (unsigned int) Palette; segread(&sregs); sregs.es = sregs.ds; /* point ES:DX to Palette */ int86x(0x10, ®set, ®set, &sregs); /* Draw the cube */ DRAW_POLYGON(Face0, 3, 0, 0); DRAW_POLYGON(Face1, 2, 0, 0); DRAW_POLYGON(Face2, 1, 0, 0); getch(); /* wait for a keypress */ /* Return to text mode and exit */ regset.x.ax = 0x0003; /* AL = 3 selects 80x25 text mode */ int86(0x10, ®set, ®set); } [LISTING TWO] /* Demonstrates unweighted antialiased drawing in 256 color mode. Tested with Borland C++ 2.0 in C mode in the small model. */ #include #include #include #include #include "polygon.h" /* Draws the polygon described by the point list PointList in color Color, with all vertices offset by (X,Y), to ScanLineBuffer, at double horizontal and vertical resolution */ #define DRAW_POLYGON_DOUBLE_RES(PointList,Color,x,y) \ Polygon.Length = sizeof(PointList)/sizeof(struct Point); \ Polygon.PointPtr = PointTemp; \ /* Double all vertical & horizontal coordinates */ \ for (k=0; k> 2) & 0x03) == Component) ? 1 : 0) + ((((Value >> 4) & 0x03) == Component) ? 1 : 0) + ((((Value >> 6) & 0x03) == Component) ? 1 : 0); /* Look up brightness of the specified color component in a megapixel of this value */ return GammaTable[i]; } [LISTING THREE] /* Draws pixels from the list of horizontal lines passed in; drawing takes place only for scan lines between ScanBandStart and ScanBandEnd, inclusive; drawing goes to ScanLineBuffer, with the scan line at ScanBandStart mapping to the first scan line in ScanLineBuffer. Intended for use in unweighted antialiasing, whereby a polygon is scanned out into a buffer at a multiple of the screen's resolution, and then the scanned-out info in the buffer is grouped into megapixels that are mapped to the closest approximation the screen supports and drawn. Tested with Borland C++ 2.0 in C mode in the small model */ #include #include #include "polygon.h" extern unsigned char *ScanLineBuffer; /* drawing goes here */ extern int ScanBandStart, ScanBandEnd; /* limits of band to draw */ extern int ScanBandWidth; /* # of pixels across scan band */ void DrawBandedList(struct HLineList * HLineListPtr, int Color) { struct HLine *HLinePtr; int Length, Width, YStart = HLineListPtr->YStart; unsigned char *BufferPtr; /* Done if fully off the bottom or top of the band */ if (YStart > ScanBandEnd) return; Length = HLineListPtr->Length; if ((YStart + Length) <= ScanBandStart) return; /* Point to the XStart/XEnd descriptor for the first (top) horizontal line */ HLinePtr = HLineListPtr->HLinePtr; /* Confine drawing to the specified band */ if (YStart < ScanBandStart) { /* Skip ahead to the start of the band */ Length -= ScanBandStart - YStart; HLinePtr += ScanBandStart - YStart; YStart = ScanBandStart; } if (Length > (ScanBandEnd - YStart + 1)) Length = ScanBandEnd - YStart + 1; /* Point to the start of the first scan line on which to draw */ BufferPtr = ScanLineBuffer + (YStart - ScanBandStart) * ScanBandWidth; /* Draw each horizontal line within the band in turn, starting with the top one and advancing one line each time */ while (Length-- > 0) { /* Draw the whole horizontal line if it has a positive width */ if ((Width = HLinePtr->XEnd - HLinePtr->XStart + 1) > 0) memset(BufferPtr + HLinePtr->XStart, Color, Width); HLinePtr++; /* point to next scan line X info */ BufferPtr += ScanBandWidth; /* point to next scan line start */ } } [LISTING FOUR] /* The changes required to convert the function FillConvexPolygon, from Listing 1 in the Feb, 1991, column, into FillCnvxPolyDrvr. FillConvexPolygon was hardwired to call DrawHorizontalLineList to draw to the display; FillCnvxPolyDrvr is more flexible because it draws via the driver passed in as the DrawListFunc parameter */ /****** Delete this line ******/ extern void DrawHorizontalLineList(struct HLineList *, int); /****** Change this... ******/ int FillConvexPolygon(struct PointListHeader * VertexList, int Color, int XOffset, int YOffset) /****** ...to this ******/ int FillCnvxPolyDrvr(struct PointListHeader * VertexList, int Color, int XOffset, int YOffset, void (*DrawListFunc)()) /****** Change this... ******/ DrawHorizontalLineList(&WorkingHLineList, Color); /****** ...to this ******/ (*DrawListFunc)(&WorkingHLineList, Color); [LISTING FIVE] ; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs. ; **************************************************************** ; * Revised 6/19/91 to select correct clock; fixes vertical roll * ; * problems on fixed-frequency (IBM 851X-type) monitors. * ; **************************************************************** ; C near-callable as: void Set320x240Mode(void); ; Tested with TASM 2.0. ; Modified from public-domain mode set code by John Bridges. SC_INDEX equ 03c4h ;Sequence Controller Index CRTC_INDEX equ 03d4h ;CRT Controller Index MISC_OUTPUT equ 03c2h ;Miscellaneous Output register SCREEN_SEG equ 0a000h ;segment of display memory in mode X .model small .data ; Index/data pairs for CRT Controller registers that differ between ; mode 13h and mode X. CRTParms label word dw 00d06h ;vertical total dw 03e07h ;overflow (bit 8 of vertical counts) dw 04109h ;cell height (2 to double-scan) dw 0ea10h ;v sync start dw 0ac11h ;v sync end and protect cr0-cr7 dw 0df12h ;vertical displayed dw 00014h ;turn off dword mode dw 0e715h ;v blank start dw 00616h ;v blank end dw 0e317h ;turn on byte mode CRT_PARM_LENGTH equ (($-CRTParms)/2) .code public _Set320x240Mode _Set320x240Mode proc near push bp ;preserve caller's stack frame push si ;preserve C register vars push di ; (don't count on BIOS preserving anything) mov ax,13h ;let the BIOS set standard 256-color int 10h ; mode (320x200 linear) mov dx,SC_INDEX mov ax,0604h out dx,ax ;disable chain4 mode mov ax,0100h out dx,ax ;synchronous reset while setting Misc Output ; for safety, even though clock unchanged mov dx,MISC_OUTPUT mov al,0e3h out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate mov dx,SC_INDEX mov ax,0300h out dx,ax ;undo reset (restart sequencer) mov dx,CRTC_INDEX ;reprogram the CRT Controller mov al,11h ;VSync End reg contains register write out dx,al ; protect bit inc dx ;CRT Controller Data register in al,dx ;get current VSync End register setting and al,7fh ;remove write protect on various out dx,al ; CRTC registers dec dx ;CRT Controller Index cld mov si,offset CRTParms ;point to CRT parameter table mov cx,CRT_PARM_LENGTH ;# of table entries SetCRTParmsLoop: lodsw ;get the next CRT Index/Data pair out dx,ax ;set the next CRT Index/Data pair loop SetCRTParmsLoop mov dx,SC_INDEX mov ax,0f02h out dx,ax ;enable writes to all four planes mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels mov es,ax ; at a time sub di,di ;point ES:DI to display memory sub ax,ax ;clear to zero-value pixels mov cx,8000h ;# of words in display memory rep stosw ;clear all of display memory pop di ;restore C register vars pop si pop bp ;restore caller's stack frame ret _Set320x240Mode endp end