::/ \::::::.
:/___\:::::::.
/| \::::::::.
:| _/\:::::::::.
:| _|\ \::::::::::.
:::\_____\:::::::::::...........................................FEATURE.ARTICLE
VGA Programming in Mode 13h
by Lord Lucifer
This article will describe how to program VGA graphics Mode 13h using assembly
language. Mode 13h is the 320x200x256 graphics mode, and is fast and very
convenient from a programmer's perspective.
The video buffer begins at address A000:0000 and ends at address A000:F9FF.
This means the buffer is 64000 bytes long and that each pixel in mode 13h is
represented by one byte.
It is easy to set up mode 13h and the video buffer in assembly language:
mov ax,0013h ; Int 10 - Video BIOS Services
int 10h ; ah = 00 - Set Video Mode
; al = 13 - Mode 13h (320x200x256)
mov ax,0A000h ; point segment register es to A000h
mov es,ax ; we can now access the video buffer as
; offsets from register es
At the end of your program, you will probably want to restore the text mode.
Here's how:
mov ax,0003h ; Int 10 - Video BIOS Services
int 10h ; ah = 00 - Set Video Mode
; al = 03 - Mode 03h (80x25x16 text)
Accessing a specific pixel int the buffer is also very easy:
; bx = x coordinate
; ax = y coordinate
mul 320 ; multiply y coord by 320 to get row
add ax,bx ; add this with the x coord to get offset
mov cx,es:[ax] ; now pixel x,y can be accessed as es:[ax]
Hmm... That was easy, but that multiplication is slow and we should get rid of
it. That's easy to do too, simply by using bit shifting instead of multiplica-
tion. Shifting a number to the left is the same as multiplying by 2. We want to
multiply by 320, which is not a multiple of 2, but 320 = 256 + 64, and 256 and
64 are both even multiples of 2. So a faster way to access a pixel is:
; bx = x coordinate
; ax = y coordinate
mov cx,bx ; copy bx to cx, to save it temporatily
shl cx,8 ; shift left by 8, which is the same as
; multiplying by 2^8 = 256
shl bx,6 ; now shift left by 6, which is the same as
; multiplying by 2^6 = 64
add bx,cx ; now add those two together, whis is
; effectively multiplying by 320
add ax,bx ; finally add the x coord to this value
mov cx,es:[ax] ; now pixel x,y can be accessed as es:[ax]
Well, the code is a little bit longer and looks more complicated, but I can
guarantee it's much faster.
To plot colors, we use a color look-up table. This look-up table is a 768
(3x256) array. Each index of the table is really the offset index*3. The 3
bytes at each index hold the corresponding values (0-63) of the red, green,
and blue components. This gives a total of 262144 total possible colors.
However, since the table is only 256 elements big, only 256 different colors
are possible at a given time.
Changing the color palette is accomplished through the use of the I/O ports of
the VGA card:
Port 03C7h is the Palette Register Read port.
Port 03C8h is the Palette Register Write port
Port 03C9h is the Palette Data port
Here is how to change the color palette:
; ax = palette index
; bl = red component (0-63)
; cl = green component (0-63)
; dl = blue component (0-63)
mov dx,03C8h ; 03c8h = Palette Register Write port
out dx,ax ; choose index
mov dx,03C9h ; 03c8h = Palette Data port
out dx,al
mov bl,al ; set red value
out dx,al
mov cl,al ; set green value
out dx,al
mov dl,al ; set blue value
Thats all there is to it. Reading the color palette is similar:
; ax = palette index
; bl = red component (0-63)
; cl = green component (0-63)
; dl = blue component (0-63)
mov dx,03C7h ; 03c7h = Palette Register Read port
out dx,ax ; choose index
mov dx,03C9h ; 03c8h = Palette Data port
in al,dx
mov bl,al ; get red value
in al,dx
mov cl,al ; get green value
in al,dx
mov dl,al ; get blue value
Now all we need to know is how to plot a pixel of a certain color at a certain
location. Its very easy, given what we already know:
; bx = x coordinate
; ax = y coordinate
; dx = color (0-255)
mov cx,bx ; copy bx to cx, to save it temporatily
shl cx,8 ; shift left by 8, which is the same as
; multiplying by 2^8 = 256
shl bx,6 ; now shift left by 6, which is the same as
; multiplying by 2^6 = 64
add bx,cx ; now add those two together, whis is
; effectively multiplying by 320
add ax,bx ; finally add the x coord to this value
mov es:[ax],dx ; copy color dx into memory location
; thats all there is to it
Ok, we now know how to set up Mode 13h, set up the video buffer, plot a pixel,
and edit the color palette.
My next article will go on to show how to draw lines, utilize the vertical
retrace for smoother rendering, and anything else I can figure out by that
time...
|