Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!bloom-beacon!mit-eddie!uw-beaver!cornell!rochester!pt.cs.cmu.edu!andrew.cmu.edu!ks26+ From: ks26+@andrew.cmu.edu (Kenneth Sykes) Newsgroups: comp.graphics Subject: Re: VGA Programming Message-ID: Date: 2 Feb 89 18:50:51 GMT Organization: Mellon College of Science, Carnegie Mellon, Pittsburgh, PA, Carnegie Mellon, Pittsburgh, PA Lines: 151 VGA programming --------------- A. Palette programming The VGA has two palettes: the EGA palette and the VGA palette. The VGA palette is a 256 entry table of r,g,b values. the r,g,b values range from 0 to 63, giving 18-bit color. Each of the r,g,b values are stored in a byte, so an r,g,b triple is 3 bytes and the palette is 768 bytes long. The EGA palette is a 16 entry palette, where each entry is a byte ranging from 0 to 63. The byte is organized as follows: 7 6 5 4 3 2 1 0 x x r' g' b' r g b r' is the MSB (Most significant bit) and r is the LSB. Similarly for g and b. On a VGA, the low order 6 bits are used as an index into the VGA palette. For instance bright red is 00100100b which corresponds to entry 36 in the VGA palette. Use the following BIOS calls to set the EGA palette (all call INT 10h): to set an individual entry: AX = 1000h BL = palette index (0-15) BH = value to set overscan register (background): AX = 1001h BH = value to set palette all registers and overscan: AX = 1002h ES:DX = pointer to 17 byte table (0-15 are palette, 16 is overscan) Note: the associated read commands are the same except add 7 to AL. For instance, to read overscan: AX = 1008h (value returned in BH). Use the following BIOS calls to set the VGA palette (all call INT 10h): to set an individual entry: AX = 1010h BX = index DH = red CH = green CL = blue to set a block of registers: AX = 1012h ES:DX = pointer to table (r,g,b,r,g,b,...) BX = starting index CX = length of table (#entries NOT #bytes) Note: the associated read commands are the same except add 5 to AL. The overscan color is defined to be entry 0 in the VGA palette. One other useful function is conversion to Gray Scale: AX = 101Bh BX = starting index CX = # colors to convert For each palette entry, a weighted sum of the components is computed and the result is placed back into the palette. If r,g,b are components of a given palette entry, then this function does the following: i = 0.3 * r + 0.59 * g + 0.11 * b; r = g = b = i; Note: this function does NOT preserve the original value. B. Video Memory organization The 320x200x256 color mode is a 64000 byte array starting at A000:0. Each pixel can range from 0 to 255 and corresponds to an index into the VGA palette [To answer someone's question concerning gray scales: If you need gray scales, you can stuff the first 64 palette entries with gray scale values (palette[i].r = i, etc.) and then treat the pixels as gray scale values from 0 to 63.]. That's all there is to it - one byte per pixel. It's much easier to program than the EGA. (Use AX = 0013h to get this mode) The 16 color modes are organized the same as the EGA, and are register compatible with the EGA. There are 4 bit planes, and a mask register (among other things). The bit plane is accessable starting at A000:0. The following is a C example for setting pixels: don't worry about this unless you have version 3 | /* EGADEMO.C -- Compile with Microsoft C Version 3 with /Ze parameter to enable "far" keyword. Programmed by Charles Petzold. */ #include #define MAXROWS 350 #define MAXCOLS 640 #define COLBYTES MAXCOLS/8 #define GRAFOUT(index,value) { outp(0x3CE,index) ; outp(0x3CF,value) ; } #define SWAP(a,b,temp) { temp = a ; a = b ; b = temp ; } main() { setvideomode(0x12) ; randomrect(0) ; /* Draw colored rectangles */ setvideomode(0x12) ; randomrect(0x18) ; /* Rectangles with XORing */ setvideomode(3) ; } setvideomode(mode) /* Sets video mode */ int mode ; { union REGS regs ; regs.x.ax = mode ; int86(0x10, ®s, ®s) ; } randomrect(fnct) /* Draws 100 rectangles */ int fnct ; { unsigned int i, r1, c1, r2, c2, temp ; GRAFOUT(3, fnct) ; /* Function Register */ for (i = 0 ; i < 100 ; i++) { r1 = rand() % MAXROWS ; r2 = rand() % MAXROWS ; c1 = rand() % MAXCOLS ; c2 = rand() % MAXCOLS ; if (r1 > r2) SWAP (r1, r2, temp) ; if (c1 > c2) SWAP (c1, c2, temp) ; rect(r1, c1, r2, c2, rand()%16); } } rect(r1, c1, r2, c2, color) /* r1 <= r2 and c1 <= c2 */ unsigned int r1, c1, r2, c2, color ; { char far *addr = (char far *) (0xA0000000L + COLBYTES*r1 + (c1>>3)) ; int numrows = r2 - r1 ; /* Number of rows */ int numcols = (c2 >> 3) - (c1 >> 3) - 1 ; /* Number of columns */ char lmask = 0xFF >> (c1 & 7) ; /* Mask for left */ char rmask = ~(0xFF >> (c2 & 7)) ; /* Mask for right */ register row, col ; if (numcols < 0) { /* Adjustment for small rows */ lmask &= rmask ; rmask = numcols = 0 ; } GRAFOUT(0, color) ; /* Set/Reset Register */ GRAFOUT(1, 0x0F) ; /* Enable Set/Reset Register */ for (row = 0 ; row < numrows ; row++) { GRAFOUT(8, lmask) ; /* Bit Mask Register */ *(addr++) &= 1 ; /* Left side */ GRAFOUT(8, 0xFF) ; for (col = 0 ; col < numcols ; col++) *(addr++) &= 1 ; /* Middle part */ GRAFOUT(8, rmask) ; *(addr++) &= 1 ; /* Right side */ addr += COLBYTES - 2 - numcols ; /* Next row */ } GRAFOUT(0, 0) ; /* Set/Reset to normal */ GRAFOUT(1, 0) ; /* S/R Enable to normal */ GRAFOUT(8, 0xFF) ; /* Bit mask to normal */ } This should have everything needed to get started. E-mail me if there are any questions. --Ken Sykes