EarthWeb   
   datamation.com Brought to you by EarthWeb

HomeSubscribeSearchFAQSitemapContact Us
     

   

  Search Tips
  Advanced Search
   
  

  
Go to ITKnowledge Enterprise

Zen of Graphics Programming, 2nd Edition Zen of Graphics Programming, 2nd Edition
by Michael Abrash
Coriolis, The Coriolis Group
ISBN: 1883577896   Pub Date: 04/01/96

Search this book:
 
Previous Table of Contents Next


Actually, though, the correspondence of pixel values to color is absolutely arbitrary, depending solely on how the color-mapping portion of the EGA containing the palette registers is programmed. If you cared to have color 0 be bright red and color 1 be black, that could easily be arranged, as could a mapping in which all 16 colors were yellow. What’s more, these mappings affect text-mode characters as readily as they do graphics-mode pixels, so you could map text attribute 0 to white and text attribute 15 to black to produce a black on white display, if you wished.

Each of the 16 palette registers stores the mapping of one of the 16 possible 4-bit pixel values from memory to one of 64 possible 6-bit pixel values to be sent to the monitor as video data, as shown in Figure 7.2. A 4-bit pixel value of 0 causes the 6-bit value stored in palette register 0 to be sent to the display as the color of that pixel, a pixel value of 1 causes the contents of palette register 1 to be sent to the display, and so on. Since there are only four input bits, it stands to reason that only 16 colors are available at any one time; since there are six output bits, however, those 16 colors can be mapped to any of 64 colors. The mapping for each of the 16 pixel values is controlled by the lower six bits of the corresponding palette register, as shown in Figure 7.3. Secondary red, green, and blue are less-intense versions of red, green, and blue, although their exact effects vary from monitor to monitor. The best way to figure out what the 64 colors look like on your monitor is to see them, and that’s just what the program in Listing 7.3, which we’ll discuss shortly, lets you do.


Figure 7.2  Color Translation via the Palette Registers


Figure 7.3  Bit Organization within a Palette Register

How does one go about setting the palette registers? Well, it’s certainly possible to set the palette registers directly by addressing them at registers 0 through 0FH of the Attribute Controller. However, setting the palette registers is a bit tricky—bit 5 of the Attribute Controller Index register must be 0 while the palette registers are written to, and glitches can occur if the updating doesn’t take place during the blanking interval—and besides, it turns out that there’s no need at all to go straight to the hardware on this one. Conveniently, the EGA BIOS provides us with video function 10H, which supports setting either any one palette register or all 16 palette registers (and the overscan register as well) with a single video interrupt.

Video function 10H is invoked by performing an INT 10H with AH set to 10H. If AL is 0 (subfunction 0), then BL contains the number of the palette register to set, and BH contains the value to set that register to. If AL is 1 (subfunction 1), then BH contains the value to set the overscan (border) color to. Finally, if AL is 2 (subfunction 2), then ES:DX points to a 17-byte array containing the values to set palette registers 0-15 and the overscan register to. (For completeness, although it’s unrelated to the palette registers, there is one more subfunction of video function 10H. If AL = 3 (subfunction 3), bit 0 of BL is set to 1 to cause bit 7 of text attributes to select blinking, or set to 0 to cause bit 7 of text attributes to select high-intensity reverse video).

Listing 7.3 uses video function 10H, subfunction 2 to step through all 64 possible colors. This is accomplished by putting up 16 color bars, one for each of the 16 possible 4-bit pixel values, then changing the mapping provided by the palette registers to select a different group of 16 colors from the set of 64 each time a key is pressed. Initially, colors 0-15 are displayed, then 1-16, then 2-17, and so on up to color 3FH wrapping around to colors 0-14, and finally back to colors 0-15. (By the way, at mode set time the 16 palette registers are not set to colors 0-15, but rather to 0H, 1H, 2H, 3H, 4H, 5H, 14H, 7H, 38H, 39H, 3AH, 3BH, 3CH, 3DH, 3EH, and 3FH, respectively. Bits 6, 5, and 4—secondary red, green, and blue—are all set to 1 in palette registers 8-15 in order to produce high-intensity colors. Palette register 6 is set to 14H to produce brown, rather than the yellow that the expected value of 6H would produce.)

When you run Listing 7.3, you’ll see that the whole screen changes color as each new color set is selected. This occurs because most of the pixels on the screen have a value of 0, selecting the background color stored in palette register 0, and we’re reprogramming palette register 0 right along with the other 15 palette registers.

It’s important to understand that in Listing 7.3 the contents of display memory are never changed after initialization. The only change is the mapping from the 4-bit pixel data coming out of display memory to the 6-bit data going to the monitor. For this reason, it’s technically inaccurate to speak of bits in display memory as representing colors; more accurately, they represent attributes in the range 0-15, which are mapped to colors 0-3FH by the palette registers.

LISTING 7.3 L7-3.ASM

; Program to illustrate the color mapping capabilities of the
; EGA's palette registers.
;
VGA_SEGMENT    equ   0a000h
SC_INDEX       equ   3c4h         ;Sequence Controller Index register
MAP_MASK       equ   2            ;Map Mask register index in SC
BAR_HEIGHT     equ   14           ;height of each bar
TOP_BAR        equ   BAR_HEIGHT*6 ;start the bars down a bit to
                                  ; leave room for text
;
stack  segment para  stack 'STACK'
       db      512 dup (?)
stack  ends
;
Data   segment word 'DATA'
KeyMsg db   'Press any key to see the next color set. '
       db   'There are 64 color sets in all.'
       db   0dh, 0ah, 0ah, 0ah, 0ah
       db   13 dup (' '), 'Attribute'
       db   38 dup (' '), 'Color$'
;
; Used to label the attributes of the color bars.
;
AttributeNumbers       label    byte
x=      0
        rept           16
if x lt 10
        db             '0', x+'0', 'h', 0ah, 8, 8, 8
else
        db             '0', x+'A'-10, 'h', 0ah, 8, 8, 8
endif
x=      x+1
        endm
        db             '$'
;
; Used to label the colors of the color bars. (Color values are
; filled in on the fly.)
;
ColorNumbers           label   byte
        rept           16
        db             '000h', 0ah, 8, 8, 8, 8
        endm
COLOR_ENTRY_LENGTH     equ     ($-ColorNumbers)/16
        db             '$'
;
CurrentColor    db     ?
;
; Space for the array of 16 colors we'll pass to the BIOS, plus
; an overscan setting of black.
;
ColorTable     db      16 dup (?), 0
Data    ends
;
Code    segment
        assume cs:Code, ds:Data
Start   proc   near
        cld
        mov    ax,Data
        mov    ds,ax
;
; Go to hi-res graphics mode.
;
        mov    ax,10h         ;AH = 0 means mode set, AL =
                               10h selects
                              ; hi-res graphics mode
        int    10h            ;BIOS video interrupt
;
; Put up relevant text.
;
        mov    ah,9                   ;DOS print string function
        mov    dx,offset KeyMsg
        int    21h
;
; Put up the color bars, one in each of the 16 possible pixel values
; (which we'll call attributes).
;
        mov    cx,16                  ;we'll put up 16 color bars
        sub    al,al                  ;start with attribute 0
BarLoop:
        push   ax
        push   cx
        call   BarUp
        pop    cx
        pop    ax
        inc    ax                ;select the next attribute
        loop   BarLoop
;
; Put up the attribute labels.
;
        mov    ah,2              ;video interrupt set cursor position
                                  function
        sub    bh,bh             ;page 0
        mov    dh,TOP_BAR/14     ;counting in character rows, match to
                                 ; top of first bar, counting in
                                 ; scan lines
        mov    dl,16             ;just to left of bars
        int    10h
        mov    ah,9              ;DOS print string function
        mov    dx,offset AttributeNumbers
        int    21h
;
; Loop through the color set, one new setting per keypress.
;
        mov    [CurrentColor],0  ;start with color zero
ColorLoop:
;
; Set the palette registers to the current color set, consisting
; of the current color mapped to attribute 0, current color + 1
; mapped to attribute 1, and so on.
;
        mov    al,[CurrentColor]
        mov    bx,offset ColorTable
        mov    cx,16           ;we have 16 colors to set
PaletteSetLoop:
        and    al,3fh          ;limit to 6-bit color values
        mov    [bx],al         ;build the 16-color table used for setting
        inc    bx              ; the palette registers
        inc    ax
        loop   PaletteSetLoop
        mov    ah,10h          ;video interrupt palette function
        mov    al,2            ;subfunction to set all 16 palette registers
                               ; and overscan at once
        mov    dx,offset ColorTable
        push   ds
        pop    es              ;ES:DX points to the color table
        int    10h             ;invoke the video interrupt to set the
                                palette
;
; Put up the color numbers, so we can see how attributes map
; to color values, and so we can see how each color # looks
; (at least on this particular screen).
;
        call   ColorNumbersUp
;
; Wait for a keypress, so they can see this color set.
;
WaitKey:
        mov    ah,8            ;DOS input without echo function
        int    21h
;
; Advance to the next color set.
;
        mov    al,[CurrentColor]
        inc    ax
        mov    [CurrentColor],al
        cmp    al,64
        jbe    ColorLoop
;
; Restore text mode.
;
        mov    ax,3
        int    10h
;
; Done.
;
Done:
        mov    ah,4ch          ;DOS terminate function
   int   21h
;
; Puts up a bar consisting of the specified attribute (pixel value),
; at a vertical position corresponding to the attribute.
;
; Input: AL = attribute
;
BarUp   proc   near
        mov    dx,SC_INDEX
        mov    ah,al
        mov    al,MAP_MASK
        out    dx,al
        inc    dx
        mov    al,ah
        out    dx,al           ;set the Map Mask register to produce
                               ; the desired color
        mov    ah,BAR_HEIGHT
        mul    ah              ;row of top of bar
        add    ax,TOP_BAR      ;start a few lines down to leave room for
                               ; text
        mov    dx,80           ;rows are 80 bytes long
        mul    dx              ;offset in bytes of start of scan line bar
                               ; starts on
        add    ax,20           ;offset in bytes of upper left corner of bar
        mov    di,ax
        mov    ax,VGA_SEGMENT
        mov    es,ax           ;ES:DI points to offset of upper left
                               ; corner of bar
        mov    dx,BAR_HEIGHT
        mov    al,0ffh
BarLineLoop:
        mov    cx,40           ;make the bars 40 wide
        rep    stosb           ;do one scan line of the bar
        add    di,40           ;point to the start of the next scan line
                               ; of the bar
        dec    dx
        jnz    BarLineLoop
        ret
BarUp   endp
;
; Converts AL to a hex digit in the range 0-F.
;
BinToHexDigit   proc   near
        cmp    al,9
        ja     IsHex
        add    al,'0'
        ret
IsHex:
        add    al,'A'-10
        ret
BinToHexDigit   endp
;
; Displays the color values generated by the color bars given the
; current palette register settings off to the right of the color
; bars.
;
ColorNumbersUp   proc   near
        mov    ah,2            ;video interrupt set cursor position
                                function
        sub    bh,bh           ;page 0
        mov    dh,TOP_BAR/14   ;counting in character rows, match to
                               ; top of first bar, counting in
                               ; scan lines
        mov    dl,20+40+1 ;just to right of bars
        int    10h
        mov    al,[CurrentColor]  ;start with the current color
        mov    bx,offset ColorNumbers+1
                               ;build color number text string on the fly
        mov    cx,16           ;we've got 16 colors to do
ColorNumberLoop:
        push   ax              ;save the color #
        and    al,3fh          ;limit to 6-bit color values
        shr    al,1
        shr    al,1
        shr    al,1
        shr    al,1            ;isolate the high nibble of the color #
        call   BinToHexDigit   ;convert the high color # nibble
        mov    [bx],al         ; and put it into the text
        pop    ax              ;get back the color #
        push   ax              ;save the color #
        and    al,0fh          ;isolate the low color # nibble
        call   BinToHexDigit   ;convert the low nibble of the
                               ; color # to ASCII
        mov    [bx+1],al   ; and put it into the text
        add    bx,COLOR_ENTRY_LENGTH     ;point to the next entry
        pop    ax              ;get back the color #
        inc    ax              ;next color #
        loop   ColorNumberLoop
        mov    ah,9            ;DOS print string function
        mov    dx,offset ColorNumbers
        int    21h             ;put up the attribute numbers
        ret
ColorNumbersUp endp
;
Start   endp
Code    ends
        end    Start


Previous Table of Contents Next

homesubscribesearchfaqsitemapcontactus
Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.