Previous | Table of Contents | Next

LISTING 33.1 L33-1.ASM

    ; Program to demonstrate use of the DAC registers by selecting a
    ; smoothly contiguous set of 256 colors, then filling the screen
    ; with concentric diamonds in all 256 colors so that they blend
    ; into one another to form a continuum of color.
    ;
           .model     small
           .stack     200h
           .data

    ; Table used to set all 256 DAC entries.
    ;
    ; Table format:
    ;      Byte 0: DAC register 0 red value
    ;      Byte 1: DAC register 0 green value
    ;      Byte 2: DAC register 0 blue value
    ;      Byte 3: DAC register 1 red value
    ;      Byte 4: DAC register 1 green value
    ;      Byte 5: DAC register 1 blue value
    ;      :
    ;      Byte 765: DAC register 255 red value
    ;      Byte 766: DAC register 255 green value
    ;      Byte 767: DAC register 255 blue value

    ColorTable label byte

    ; The first 64 entries are increasingly dim pure green.
    X=0
           REPT 64
           db    0,63-X,0
    X=X+1
           ENDM

    ; The next 64 entries are increasingly strong pure blue.
    X=0
           REPT 64
           db   0,0,X
    X=X+1
           ENDM

    ; The next 64 entries fade through violet to red.
    X=0
           REPT 64
           db   X,0,63-X
    X=X+1
           ENDM

    ; The last 64 entries are increasingly dim pure red.
    X=0
           REPT 64
           db   63-X,0,0
    X=X+1
    ENDM

           .code
    Start:
           mov  ax,0013h               ;AH=0 selects set mode function,
                                       ; AL=13h selects 320x200 256-color
           int  10h                    ; mode

                                       ;load the DAC registers with the
                                       ; color settings
           mov  ax,@data               ;point ES to the default
           mov  es,ax                  ; data segment
           mov  dx,offset ColorTable
                                       ;point ES:DX to the start of the
                                       ; block of RGB three-byte values
                                       ; to load into the DAC registers
           mov  ax,1012h               ;AH=10h selects set color function,
                                       ; AL=12h selects set block of DAC
                                       ; registers subfunction
           sub  bx,bx                  ;load the block of registers
                                       ; starting at DAC register #0
           mov  cx,100h                ;set all 256 registers
           int  10h                    ;load the DAC registers

                                       ;now fill the screen with
                                       ; concentric diamonds in all 256
                                       ; color attributes
           mov  ax,0a000h              ;point DS to the display memory
           mov  ds,ax                  ; segment
                                       ;
                                       ;draw diagonal lines in the upper-
                                       ; left quarter of the screen
           mov  al,2                   ;start with color attribute #2
           mov  ah,-1                  ;cycle down through the colors
           mov  bx,320                 ;draw top to bottom (distance from
                                       ; one line to the next)
           mov  dx,160                 ;width of rectangle
           mov  si,100                 ;height of rectangle
           sub  di,di                  ;start at (0,0)
           mov  bp,1                   ;draw left to right (distance from
                                       ; one column to the next)
           call FillBlock              ;draw it
                                       ;
                                       ;draw diagonal lines in the upper-
                                       ; right quarter of the screen
           mov  al,2                   ;start with color attribute #2
           mov  ah,-1                  ;cycle down through the colors
           mov  bx,320                 ;draw top to bottom (distance from
                                       ; one line to the next)
           mov  dx,160                 ;width of rectangle
           mov  si,100                 ;height of rectangle
           mov  di,319                 ;start at (319,0)
           mov  bp,-1                  ;draw right to left (distance from
                                       ; one column to the next)
    callFillBlock;draw it

                                       ;draw diagonal lines in the lower-
                                       ; left quarter of the screen
           mov  al,2                   ;start with color attribute #2
           mov  ah,-1                  ;cycle down through the colors
           mov  bx,-320                ;draw bottom to top (distance from
                                       ; one line to the next)
           mov  dx,160                 ;width of rectangle
           mov  si,100                 ;height of rectangle
           mov  di,199*320             ;start at (0,199)
           mov  bp,1                   ;draw left to right (distance from
                                       ; one column to the next)
    callFillBlock;draw it
                                       ;
                                       ;draw diagonal lines in the lower-
                                       ; right quarter of the screen
           mov  al,2                   ;start with color attribute #2
           mov  ah,-1                  ;cycle down through the colors
           mov  bx,-320                ;draw bottom to top (distance from
                                       ; one line to the next)
           mov  dx,160                 ;width of rectangle
           mov  si,100                 ;height of rectangle
           mov  di,199*320+319     ;start at (319,199)
           mov  bp,-1                  ;draw right to left (distance from
                                       ; one column to the next)
    callFillBlock;draw it

           mov  ah,1                   ;wait for a key
    int21h;

           mov  ax,0003h               ;return to text mode
    int10h;

           mov  ah,4ch                 ;done--return to DOS
    int21h

    ; Fills the specified rectangular area of the screen with diagonal lines.
    ;
    ; Input:
    ;      AL = initial attribute with which to draw
    ;      AH = amount by which to advance the attribute from
    ;            one pixel to the next
    ;      BX = distance to advance from one pixel to the next
    ;      DX = width of rectangle to fill
    ;      SI = height of rectangle to fill
    ;      DS:DN = screen address of first pixel to draw
    ;      BP = offset from the start of one column to the start of
    ;            the next

    FillBlock:
    FillHorzLoop:
           push di                     ;preserve pointer to top of column
           push ax                     ;preserve initial attribute
           mov  cx,si                  ;column height
    FillVertLoop:
           mov  [di],al                ;set the pixel
           add  di,bx                  ;point to the next row in the column
           add  al,ah                  ;advance the attribute
           loop FillVertLoop           ;
           pop  ax                     ;restore initial attribute
           add  al,ah                  ;advance to the next attribute to
                                       ; start the next column
           pop  di                     ;retrieve pointer to top of column
           add  di,bp                  ;point to next column
           dec  dx                     ;have we done all columns?
           jnz  FillHorzLoop           ;no, do the next column
           ret;

            endStart

Note the jagged lines at the corners of the screen when you run Listing 33.1. This shows how coarse the 320×200 resolution of mode 13H actually is. Now look at how smoothly the colors blend together in the rest of the screen. This is an excellent example of how careful color selection can boost perceived resolution, as for example when drawing antialiased lines, as discussed in Chapter 42.

Finally, note that the border of the screen turns green when Listing 33.1 is run. Listing 33.1 reprograms DAC register 0 to green, and the border attribute (in the Overscan register) happens to be 0, so the border comes out green even though we haven’t touched the Overscan register. Normally, attribute 0 is black, causing the border to vanish, but the border is an 8-bit attribute that has to pass through the DAC just like any other pixel value, and it’s just as subject to DAC color translation as the pixels controlled by display memory. However, the border color is not affected by the palette RAM or by the Color Select register.

In this chapter, we traced the surprisingly complex path by which the VGA turns a pixel value into RGB analog signals headed for the monitor. In the next chapter and Chapter A on the companion CD-ROM, we’ll look at some more code that plays with VGA color. We’ll explore in more detail the process of reading and writing the palette RAM and DAC registers, and we’ll observe color paging and cycling in action.

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash