Game Programming with DGJPP
Graphics by Lord Azathoth

Start VGA programming
In this page I'll explain how to programming the VGA at a resolution of 320x200x256. I will also include a demo program (see it later).

Structure of the video memory at 320x200x256
The memory structure at this resolution is very simple to use: is only a sequence of bytes mapped in the central memory. First, remember this: a pixel on the screen is a byte in the memory. So at a resolution of 320x200 the screen use 64000 bytes of memory. This memory start at the address A000:0000 (A0000 in protected mode) of the main memory. Under a real mode system is simple to access at this memory by using a far pointer, like this:

	char far *vgamemory = (char *)0xA0000000L;
or (on old compilators)

	char far *vgamemory = (char *)MK_FP(0xA000, 0);
But under DJGPP isn't so simple because the memory is protected, so you can't access directly to all the memory of the system. The best solution is to disable the protection of the DOS memory by calling the procedure __djgpp_nearptr_enable(). There are a simple code that shows how to access at the DOS memory:

	#include <sys/nearptr.h>

	__djgpp_nearptr_enable();
	vgamemory=(char *)(0xa0000 + __djgpp_conventional_base);

	 __djgpp_nearptr_disable();
The header nearptr.h is necessary for the prototipes of the functions. We should use __djgpp_conventional_base to get the right address of the DOS memory (the protected mode is very intricate). At the end of the program, use __djgpp_nearptr_disable() to get the program back to regular protected mode. But you must remember that with this code you disable the protection of the memory, so you can damage the DOS area and block the system. Use the program info (you must download the file txi390b.zip) for more informations.
For clearing the screen with a specified color simply call the function memset() with a pointer to the video memory.

Setting the VGA mode 320x200x256
The BIOS supplies a procedure that provide to set the VGA mode 320x200x256 via interrupt 10h. We must only set a register (ax) and call this interrupt. To return to the text mode (usually mode 03h) we can use the same procedure. There are the simple code to swap to the wanted mode:

#define TEXT_MODE 0x03
#define VGA_MODE  0x13

void setmode(short mode)
{
	union REGS regs;

	regs.h.ah = 0x00;	  // Procedure 0x00: Set Video Mode
	regs.h.al = mode;	  // The requested video mode
	int86(0x10,&regs,&regs)	  // Call the BIOS
}
If you set the most significant bit of the register al (use 0x93 instead of 0x13) the video memory is not cleared. If you don't like to use the BIOS you can download the file modes.zip that explain how to set the video mode without the BIOS.

Put the first pixel
In the paragraph Structure of the video memory I've introduced how to access to the video memory. Now is very simple to draw a pixel: is enough to write at the right offset in the video memory. So I've draw a simple image to explain how the video memory is used at this resolution:
The Video Memory If you write a color byte at the start of the video memory (A000:0000) you'll show a pixel at the upper-left corner of the screen (0, 0). When you write at the offset 319 (A000:013F) you'll show a pixel at the upper right corner. Writing at the next byte (A000:0140) and the pixel will appear at the position (0, 1). So we can understand that if we want to show a pixel at the position (x, y) we must write at the address A000:(y*320+x) of the video memory. This is a fast method for write a pixel. But we can optimize a bit the speed by using shifting instead of multiplications. So we divide the number 320 into the powers of two 256 and 64 and we have  320y = 256y + 64y  and next  offset = (y<<8) + (y<<6) + x .

The  basical  algorithms
Lines
lines For drawing a line we must calculate where an immaginary line intersect an immaginary rect. For each square of the rect correspond a pixel on the screen. So for each square intersected by a immaginary line we have a pixel of the real line to draw. We must calculate what squares is intersected by the line. A simple method is by using the equation x-x1=m(y-y1) , but is a bit slow.
Instead we can use the Bresenham's line-drawing algorithm that use only additions and subtractions. It is based on the relation:

	sizex/sizey=countx/county

	sizex and sizey are the sizes of the rectangle that contain the line
	countx and county are the counters impiegated by the algorithm
so we have:

		    county * sizex	
	calculatex= --------------
			sizey		

		    countx * sizey	
	calculatey= --------------
			sizex
But the Bresenham's algorithm transform the equations for drawing the lines without the multiplications and the divisions. See the demo program for the code of the algorithm.

Rectangles
Drawing rectangles is very simple: simply drawing 2 horizontals and 2 verticals lines. But we can make an optimized code that not use the drawline() function and draw a rectangle more faster. We know the structure of the video memory, so is simple to design an algorithm for a rectangle.
rectangle

draw sizex pixels from (x1, y1)
onerow:
   jump 320-sizex pixels
   draw a pixel
   jump sizex-2 (intsizex) pixels
   draw a pixel
while row drawed < sizey-2
jump 320-sizex pixel
draw sizex pixels
See the demo program for the code of the algorithm.

Circles
Now I've no time for this.

Using the palette
In mode 13h we can use 256 colors for display graphics. Each color is selected from a palette of 262144 colors, so if we must use a special color we can modify the default selection of a color for setting the one that we want. For make this is necessary to tell to the VGA card the number of the color that we want to change and next the RGB value. This value is a triple of byte in the range 0..63, that specify the intensity of Red, Green and Blue. Whit the mixing of these colors we can make the wanted color. The VGA card have 3 register for change the palette: RGB_READ for telling the index of the color to read, RGB_WRITE for telling the index of the color to write and RGB_DATA for read/write the RGB value. RGB_RESET is used for prepare the VGA card (isn't necessary). The following code shows how to setting the RGB value of the color 15 (WHITE):

#define RGB_RESET 0x03C6
#define RGB_READ  0x03C7
#define RGB_WRITE 0x03C8
#define RGB_DATA  0x03C9

void setwhite(void)
{
   outp(RGB_RESET, 0xFF);     // Prepare the VGA card
   outp(RGB_WRITE, WHITE);    // Tell that we want to write the color 15 (WHITE)
   outp(RGB_DATA, 64);        // Red value
   outp(RGB_DATA, 64);        // Green value
   outp(RGB_DATA, 64);        // Blue value
}
For setting all the 256 colors simply tell to the VGA card that we want to write the color 0, and next write the RGB of all the colors:

void setpalette(char *palette)
{
   register int i;

   outp(RGB_RESET, 0xFF);		// Prepare the VGA card
   outp(RGB_WRITE, 0);                  // Tell that we want to write the entire palette
   for(i=0;i<256;i++) {
      outp(RGB_DATA, palette[i*3]);     // Red value
      outp(RGB_DATA, palette[i*3+1]);   // Green value
      outp(RGB_DATA, palette[i*3+2]);   // Blue value
   }
}
For reading the RGB value of a color or of all the colors simply write the index to RGB_READ and read the values from RGB_DATA.See the demo program for the code.

How about snow or noise?
Is possible that a noise will appear on the screen when the palette is changed continuously. This effect is done because we change the palette in the same time that the VGA card update the screen. For prevent this effect is necessary to wait the retrace signal of the card via the bit 3 of the register 0x03DA. There are the code:

void waitretrace(void)
{
   // Wait vertical retrace
   while(inportb(0x03DA)&0x08);
   // Wait refresh
   while(!(inportb(0x03DA)&0x08));
}



[main] [prec] [next] [email]

Site Made and Maintained by The Dark Angel <DarkAngel@tin.it>
My ICQ Number is 2063026
You Visited This Page times


This page hosted by Geocities Icon Get your own Free Home Page