CS-220, Sec.90, Week 12-A
R. Eckert


Although the int 10h services can be used to access the video system, they
have the disadvantage of being very slow. If our application requires
optimum performance, as, for example, in doing animation, we need to be
able to access the video system directly.

On a PC, the video system is memory mapped. In text mode, the start
address of the video RAM is 0B8000h. Each pair of bytes controls what is
displayed in one character cell on the screen in row major fashion. In
other words, in an 80-column mode, the first row of character cells is
controlled by the bytes at offsets 0-159 in the video RAM. The second row
by the bytes at offsets 160-319, etc. For any given character cell the
first byte of the pair that controls the character cell should contain the
ASCII code of the character to be displayed and the second the display
attribute (which determines the foreground/background color of the
character--see previous notes).

In order to display a character with a given display attribute at a
specified position (row and column) on the screen, we need to determine
the offset into the video RAM of the two bytes that control that character
cell from the row and column, then write the ASCII code to the first byte
and the display attribute to the second byte. For the PC, row-0 and
column-0 are at the upper lefthand corner of the screen. In other words,
column numbers increase from left to right and row numbers from top to
bottom. In general, the offset of the pair of bytes controlling the
character cell at row y and column x is given by the following:

           offset = (80*y + x)*2

We now want to write some pseudo-code for a procedure that will output a
character to a specified row and column on the screen. Input parameters to
the procdure will be:

           BL = ASCII code of character to be displayed
           BH = display attribute
           DH = row number (0-24)
           DL = column number (0-79)

The pseudcode is:

     Save registers
     Set accumulator to 80
     Multiply by DH
     Add DL
     Multiply by 2 (shift)
     Store in an index register (e.g., SI)
     Set a segment register (e.g., ES) to point to Video Ram (0B800h)
     Load ES:[SI] with BX    ;This displays the character!
     Restore registers
     Return to calling procedure


Suppose we want to display a line composed of repetitions of some
character (e.g., asterisks) on the screen. We are given the column and row
of each of the line's endpoints -- (x1,y1) and (x2,y2).

One way of representing a line is the "point-slope" method. This says that
the slope (delta_y/delta_x) of any part of the line has to be the same as
the slope computed from the endpoints. In other words, any point (x,y)
will be on the line if:

           y - y1   y2-y1
           ------ = -----
           x - x1   x2-x1

If we solve this for y, we get:

           y = y1 + (x - x1)*(y2 - y1)/(x2 - x1)

Therefore we could begin at x = x1, take unit increments in x (step in x),
compute the corresponding value of y and plot the character at that point.
(The plotting of the character would be done by the routine whose pseudo-
code is given above.) This is the "brute force" method for plotting a line.
The number of points to plot is x2-x1+1. (Here we assume that x1<x2. If
that is not the case the endpoints can be swapped.) The "brute force"
algorithm to plot a line between (x1,y1) and (x2,y2) is thus:

           num_points = x2 - x1 + 1
           x <-- x1
           repeat num_points times
              y <-- y1 + (x-x1)*(y2-y1)/(x2-x1)
              call character-plotting procedure
              x <-- x + 1

There are two problems with this algorithm:

1. It "blows up" for vertical lines (x1=x2).

2. The line will have gaps if the absolute value of the slope is greater
than 1.

Both problems can be solved if we step in the x direction only if the
slope is less than 1; otherwise step in the y direction. For stepping in
the y direction, the "point-slope" equation given above would need to be
solved for x, and each time through the loop, y would be incremented by 1.
The number of iterations (num_points) would be y2-y1+1 (again assuming
that y2>y1).


In VGA Mode 13h, the PC's screen is divided into 320 columns and 200 rows 
of pixels (dots). Each pixel can be set to one of 256 colors chosen from 
2^18 possible colors (combinations of red, green, and blue). This video
mode works as follows:

   One byte of Mode 13h VRAM controls one pixel.
   Mode 13h VRAM begins at address 0A000:0000h (row major ordered).
   To set pixel at (x,y) to a given color:
      Set a segment register (e.g., ES) to start of video RAM, 0A000h
      Compute offset of the byte controlling the pixel (320 * y + x)
      Load offset into a pointer register (e.g., SI)
      Set the pixel by loading that location with a color (byte)--
         mov ES:[SI], color.

Mode 13h color control is indirect through a 256 X 18 Color Lookup Table.
The color written to the VRAM is a byte-size index into this table.
Entries in table: 6 bits for Red, 6 for Green, 6 for Blue.
To change an entry in the VGA CLUT, use the video interrupt (10h):
   AH = 10h, AL = 10H, BX = CLUT position to be changed (0-255)
   DH, CH, CL = {Red, Green, Blue intensity: 0-63 each}.

Some Default Color Lookup Table colors: 0 ==> black, 1 ==> dark blue,
2 ==> dark green, 3 ==> dark cyan, 4 ==> dark red, 5 ==> dark magenta, 
6 ==> brown, 7 ==> grey, etc. In other words, if you load any of these 
values into a byte of the VRAM, the pixel controlled by that location will 
change to the corresponing color.