11.2 VGA Mode 13h Graphics

11.2.1 Overview

Mode 13h is a standard VGA graphics mode. While it may seem somewhat limited in resolution and colors when compared to SVGA modes, it is supported on nearly every computer available today. There are 320 pixels over and 200 pixels down the screen, each of which may have one of 256 colors. Mode 13h is unique from other higher-resolution, but only 16-color, VGA graphics modes because the memory for the video screen is arranged linearly, where one byte corresponds to one pixel on the screen. As a result, Mode 13h is very easy to program in since it's not necessary to deal with bit planes.

The first step to making a Mode 13h program is to call a BIOS interrupt to enter it. Do this by:

        mov     ax, 0013h
        int     10h

To return back to text at the end of the program, use:

        mov     ax, 0003h
        int     10h

Once in Mode 13h, each pixel can be set to any color from a palette of 256 colors. There are two methods to do this by--using BIOS interrupts or direct writes. Direct writes are the best choice here due to the simplicity of Mode 13h (the bit planes used in other VGA modes can make BIOS interrupts the best choice). Since each pixel directly corresponds to one byte, just set the byte to the color (0 - 255). Use the following formula to determine the address and move a byte into it:

The following code fragment illustrates how to set a pixel:

; Before drawing graphics
        mov     ax, 0A000h      ; Set ES to graphics screen segment
        mov     es, ax
                |
            (set X and Y and DL to the color)
                |
        mul     di, [Y], 320    ; Multiply Y by 320 and store in DI
        add     di, [X]         ; Add the X coordinate
        mov     [es:di], dl     ; Set the pixel to the color specified
                                ;  by DL

This method can be much faster than BIOS, because for most things, only a few MUL instructions should be needed and the majority of pixels can be set by moving relative to the original address. For example, to move left or right, simply subtract or add 1 from the address, and to move up and down, subtract or add 320, respectively. Use this method along with string operations to set entire ranges, draw straight horizontal and vertical lines, and draw boxes. For more information about string operations, refer to Section 4.6.

11.2.2 Using Extra Segments

One of the most aggravating thing about creating animated images is the flicker and delays seen by the user while the image is being drawn. Because of Mode 13h's memory scheme and usage, it is possible to draw the graphics on another segment in memory instead of the graphics screen, and when an individual frame is finished being created, to copy that segment directly onto the VGA screen memory. The easiest and fastest way to do this is to use string operations.

To create a blank segment in the program that graphics instructions can be "redirected" to, do the following:

SEGMENT ScratchSeg
ScratchPad      resb 64000

This should be included at the beginning of the program along with other segment definitions. Then, instead of setting ES to point to the VGA memory segment, have ES point to the ScratchSeg segment when plotting pixels.

Once an entire frame has been drawn on the scratch segment, it is very simple to copy it to the VGA screen:

        mov     ax, ScratchSeg  ; from scratch segment
        mov     ds, ax
        mov     ax, 0A000h      ; to graphics screen
        mov     es, ax
        cld                     ; set direction flag forward
        mov     esi, ScratchPad ; set the source offset
        xor     edi, edi        ; dest. offset will always be 0
        mov     ecx, 320*200/4  ; 320*200, copying doublewords
        rep movsd

This will issue a MOV command 16,000 times, each time moving a DWORD (4 pixels) from the ScratchSeg segment to the VGA screen.

Note: Each segment declared in this fashion occupies 64k = 64000 bytes of memory. Real mode only allows 640k of total memory, so only declare at most 2 or 3 scratch segments.