If this page looks like garbage then you need one of these browsers...Please sign my programmer's page guestbook. |
Writing Graphics FunctionsOkay, so you got a glimpse about graphics modes and now we want to try putting some of that knowledge to use on some real functions that work. Okay, let's consider our options. For us Borland users, we have these functions that initialize the graphics modes (initgraph) and then close it (closegraph) etc.. Frankly, I don't use them. There are hard for me to figure out and what if I want to directly set the screen mode. If you think that the closegraph function does this, better reread the documentation. This function restores the screen to the mode prior to setting it to our graphics mode. If it was already in another graphics mode prior to calling initgraph function, then that graphics mode is where it returns to. For this type of function, I prefer Microsoft's '_setvideomode' function, but that is a Microsoft function not a Borland function. So what do we do here? Write our own function to directly set the video mode with a call to the BIOS. Which graphics mode should we use? We've seen the strengths and weeknesses of each of the modes on the previous page. CGA is fairly easy to work with but gives us very few colors. Unless we like working with planes, I would stay away from the EGA and most of the VGA modes, except one. The mode of choice: Mode 13HThe easiest mode to work with and from what I've seen, the video mode of choice for most game developers is VGA's mode 13H. This mode is a 320x200x256 mode that is laid out in a linear fashion in memory. The screen starts in memory location A000:0000 and continues for 64000 bytes to location A000:F9FF. Let's look at how we go about switching modes via that BIOS. If we supply register AX with the video mode with which we wish to change to and make an interrupt call to interupt number 10H (or 16), well, we've just created our own function in a nutshell. Observe...
#include <dos.h> #include <conio.h> #define Mode13H 0x13 #define TextMode 0x03 void SetVideoMode(int Mode) { union REGS regs; regs.x.ax = Mode; int86(0x10, ®s, ®s); } int main(void) { /* Tell the compilor to use the BIOS for cprintf and cputs functions */ directvideo = 0; cputs("Currently in text mode.\r\nPress a key..."); getch(); SetVideoMode(Mode13H); cputs("Now in VGA mode 13H.\r\nPress a key..."); getch(); SetVideoMode(TextMode); cputs("Now back in text mode.\r\nPress a key..."); getch(); return 0; }
Somebody sent me an e-mail with another similar method for switching screen modes. Thanks Josh... Now I must pause for a second to explain the 'directvideo = 0' line. In Borland's Turbo C++ compilor, conio.h declares a global variable called directvideo. If this variable is set to a non-zero value (true), the functions in conio.h will write directly to the video hardware. Which will not work unless your display adapters are strictly IBM compatible, an I'm betting most are not, at least not totally. So instead I set the variable to 0 (false) forcing the conio.h functions to use the BIOS for screen writes which requires that your PC is IBM BIOS compatible (in which most are). So now you see how easy it is to set the screen to any video mode of our choice. I hope so. Now let's take a look at the layout of this video mode.
Looking at the screen of mode 13H we see four pixels set in the four corners of the screen. Notice also that the four pixels also have their corresponding memory locations written on top of them. You may be able to spot a relationship right off, but let's disect it a bit and see if we can find one. All four of these memory locations are in segment A000, so it is safe to assume that every pixel on the screen is stored in this segment. Now let's look at the offset. Hmmmm... Pixel (0,0) is stored at the offset of 0000H or just plain zero. Move over to the far right side from this pixel and the offset off pixel (319,0) reads 013F. Convert to decimal, we get 319! Looks like a pattern here... |
Don't be fooled because the highest offset in VGA's mode 13H is 63999. There are indeed 64000 pixels (and bytes) on this screen (320x200). The 63999 comes from what is known as the 'off by one' symptom in computers. As a C programmer, I'm sure you are aware that arrays you create always have as their highest element, one less than the number of elements you assigned. This is because the number zero is counted too. |
Going to the lower left, the offset now reads F8C0. Translating... That comes out to decimal 63680 (???) what relationship do we have here? Lets move to the right at pixel (319,199) the offset reads F9FF. That comes out to 63999 and proves that there are 64000 pixels on the screen. But what of the relationship between the pixels and the memory locations? Divide the 63680 by the 199 from pixel (0,199). The answer is 320, the exact number of pixels across each row! Subtract 63680 from 63999, just as I thought, 319... Okay, enough Tom foolery. The relationship is simple. The row, or the Y value in the ordered pair (x,y) is a multiple of 320 with the X value being the final offset. You can determine the memory location like this: A000 (segment) : Y x 320 + X (offset) [convert to hex of course] In other words, if we wanted to plot a pixel say at (100,100). Just multiply Y (100) by 320 (32000) and add X (100) to equal 32100. Convert to hexadecimal (7D64) that's our offset. Pixel 100,100 is located at A000:7D64. Okay, now what do we do with that? Send your questions, comments, or ideas to: wilkeg@gamewood.net This page hosted by
Get your own Free Home Page |