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