home *** CD-ROM | disk | FTP | other *** search
- _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 <conio.h>
- #include <dos.h>
- #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 <conio.h>
- #include <dos.h>
- #include <stdlib.h>
- #include <string.h>
- #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<sizeof(PointList)/sizeof(struct Point); k++) { \
- PointTemp[k].X = PointList[k].X * 2; \
- PointTemp[k].Y = PointList[k].Y * 2; \
- } \
- FillCnvxPolyDrvr(&Polygon, Color, x, y, DrawBandedList);
-
- #define SCREEN_WIDTH 320
- #define SCREEN_HEIGHT 200
- #define SCREEN_SEGMENT 0xA000
- #define SCAN_BAND_WIDTH (SCREEN_WIDTH*2) /* # of double-res pixels
- across scan band */
- #define BUFFER_SIZE (SCREEN_WIDTH*2*2) /* enough space for one scan
- line scanned out at double
- resolution horz and vert */
- void main(void);
- void DrawPixel(int, int, char);
- int ColorComponent(int, int);
- extern int FillCnvxPolyDrvr(struct PointListHeader *, int, int, int,
- void (*)());
- extern void DrawBandedList(struct HLineList *, int);
-
- /* Pointer to buffer in which double-res scanned data will reside */
- unsigned char *ScanLineBuffer;
- int ScanBandStart, ScanBandEnd; /* top & bottom of each double-res
- band we'll draw to ScanLineBuffer */
- int ScanBandWidth = SCAN_BAND_WIDTH; /* # pixels across scan band */
- static char Palette[256*3];
-
- void main()
- {
- int i, j, k;
- struct PointListHeader Polygon;
- struct Point PointTemp[4];
- 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}};
- unsigned char Megapixel;
- union REGS regset;
- struct SREGS sregs;
-
- if ((ScanLineBuffer = malloc(BUFFER_SIZE)) == NULL) {
- printf("Couldn't get memory\n");
- exit(0);
- }
-
- /* Set the display to VGA mode 13h, 320x200 256-color mode */
- regset.x.ax = 0x0013; int86(0x10, ®set, ®set);
-
- /* Stack the palette for the desired megapixel effect, with each
- 2-bit field representing 1 of 4 double-res pixels in one of four
- colors */
- for (i=0; i<256; i++) {
- Palette[i*3] = ColorComponent(i, 3); /* red component */
- Palette[i*3+1] = ColorComponent(i, 2); /* green component */
- Palette[i*3+2] = ColorComponent(i, 1); /* blue component */
- }
- regset.x.ax = 0x1012; /* load palette block BIOS function */
- regset.x.bx = 0; /* start with palette register 0 */
- regset.x.cx = 256; /* set all 256 palette registers */
- regset.x.dx = (unsigned int) Palette;
- segread(&sregs);
- sregs.es = sregs.ds; /* point ES:DX to Palette */
- int86x(0x10, ®set, ®set, &sregs);
-
- /* Scan out the polygons at double resolution one screen scan line
- at a time (two double-res scan lines at a time) */
- for (i=0; i<SCREEN_HEIGHT; i++) {
- /* Set the band dimensions for this pass */
- ScanBandEnd = (ScanBandStart = i*2) + 1;
- /* Clear the drawing buffer */
- memset(ScanLineBuffer, 0, BUFFER_SIZE);
- /* Draw the current band of the cube to the scan line buffer */
- DRAW_POLYGON_DOUBLE_RES(Face0, 3, 0, 0);
- DRAW_POLYGON_DOUBLE_RES(Face1, 2, 0, 0);
- DRAW_POLYGON_DOUBLE_RES(Face2, 1, 0, 0);
-
- /* Coalesce the double-res pixels into normal screen pixels
- and draw them */
- for (j=0; j<SCREEN_WIDTH; j++) {
- Megapixel = (ScanLineBuffer[j*2] << 6) +
- (ScanLineBuffer[j*2+1] << 4) +
- (ScanLineBuffer[j*2+SCAN_BAND_WIDTH] << 2) +
- (ScanLineBuffer[j*2+SCAN_BAND_WIDTH+1]);
- DrawPixel(j, i, Megapixel);
- }
- }
-
- 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);
- }
-
- /* Draws a pixel of color Color at (X,Y) in mode 13h */
- void DrawPixel(int X, int Y, char Color)
- {
- char far *ScreenPtr;
-
- ScreenPtr = (char far *)MK_FP(SCREEN_SEGMENT, Y*SCREEN_WIDTH+X);
- *ScreenPtr = Color;
- }
-
- /* Returns the gamma-corrected value representing the number of
- double-res pixels containing the specified color component in a
- megapixel with the specified value */
- int ColorComponent(int Value, int Component)
- {
- /* Palette settings for 0%, 25%, 50%, 75%, and 100% brightness,
- assuming a gamma value of 2.3 */
- static int GammaTable[] = {0, 34, 47, 56, 63};
- int i;
-
- /* Add up the number of double-res pixels of the specified color
- in a megapixel of this value */
- i = (((Value & 0x03) == Component) ? 1 : 0) +
- ((((Value >> 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 <string.h>
- #include <dos.h>
- #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