[comp.graphics] VGA Programming..

ks26+@andrew.cmu.edu (Kenneth Sykes) (02/03/89)

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 <dos.h>
#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, &regs, &regs) ;
    }

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

martin@csd4.csd.uwm.edu (Martin A Miller) (10/12/90)

Greetings,

Well, I think I've exhausted all the "direct" approaches to solving
my problem, so I'll try the "brute force" method.

I recently found a couple of no-frills GIF viewers on the "grape"
archive site in the file "gifsrc.arc".  They were written by Jim
Griebel and for my EGA needs I was able to hack one of them a bit to
write a plain ASCII file with the actual numerical values for each
pixel (0=black, 1=blue,..., 15=white) of the GIF. These programs
are written in Turbo Pascal 4.0.

The programs work for EGA only, so of course, now I have been 
asked to do the same thing with VGA.  Not having any background
in programming VGA graphics, I have found out that VGA is quite a 
different animal...(than EGA).  I've sent msgs to "grape" asking
for info; they don't have any..I've got Richard Wilton's book
"Programmer's Guide to PC & PS/2 Video Systems" and I can't make
heads or tails out it..

The purpose of this post, then, is twofold: 

Jim Griebel, if you're reading this, please contact me, or if anyone 
has any info on VGA programming ie., which registers take what values,
etc.. please email.


thank you..

-mm


Martin A. Miller
Programmer/Consultant
Social Science Research Facility
University of Wisconsin-Milwaukee
Phone: (414) 229-5314
Internet: martin@csd4.csd.uwm.edu
Bitnet  : martin%csd4.csd.uwm.edu@INTERBIT
UUCP    : uunet!martin@csd4.csd.uwm.edu