Home
About the Author
General Programming
Pascal
Delphi
C&C++
Visual Basic
SQL
JAVA Script
Links
| |
[ C Graphics ] [ C Math ] [ C Misc ] [ Common C&C++ Pitfalls ] [ Ponter Tutorial ]
- Mode 13h
- Setting the palette in mode 13h
- Mode 13h putpixel
Just a quick note. Most of the code in this
graphics section only works with the DJGPP compiler. Maybe with a bit of modification you
can get it to work in other compilers.
Any questions send mail to cplus@teentwo.8m.com
1. The video mode 13h, What is 13h?
Many computer games have used it such as DOOM and DOOM2, the
original C&C the DOS version of C&C-RedAlert. It's also Quake's standard
resolution, and QuakeII's non 3d excelerated standard resolution. So as you can see, it's
a very widely used video mode... at least it WAS, until Microsoft came over and made
direct-x, which by the way is about twice as slow as just programming the graphics support
your self, it's just that you probably can't tell the difference because of how fast
computers are now-a-days anyway.
One of the more interesting questions that comes up about 13h is "What
is it?". There is a very simple answer to that question: 320x200x256.
The only problem with that answer is the fact that not every body knows what it means.The
answer to that question is not quite so simple to answer, although once known is so simple
that you will never forget what it means.
The first number in the list, 320, tells us the
horizontal resolution. Just incase you don't know what a horizontal resolution is, I'll
tell you: it is the number of pixels per row on the screen.
The second number, 200, tells us the vertical
resolution. The vertical resolution is the number of pixels per column on the screen.
The last number, 256, is the amount of possible
colors to be displayed on the screen at once. it is commonly referred to as the
"color palette".
So how do I change the video mode to 13h?
Well, this one is something that there is only one efficient way to do, so I'll just give
you the code right here:
int init_vga_mode(void)
{
union REGS regs;
__djgpp_nearptr_enable();
vgamemory=(char *)(0xA0000 + __djgpp_conventional_base);
if((vgabuffer=(char *)malloc(320*200))==NULL)
{
return(1);
}
regs.h.ah=0x00; //Procedure 0x00: Set Video Mode
regs.h.al=0x13; //The mode to set (0x# = #h)
int86(0x10, regs, regs); //Call BIOS intr 0x10
return(0);
}
The code above will work with DJGPP if you include the following:
- dos.h
- bios.h
- dpmi.h
- stdio.h
- conio.h
- math.h
- stdlib.h
- go32.h
- pc.h
- sys/nearptr.h
And then you also have to declare the following global pointers:
- char *vgamemory;
- char *vgabuffer;
Of course one main question does come to mind... what does all that
code do? Well, it changes the video mode to 13h... But what does each individual line do?!
Well, I'll show you:
The first line is obvious:
int init_vga_mode(void)
It sets up the function, and if you don't know what "setting up a function"
means then you shouldn't be reading this until you do.
The second line (after the "{" ) which is:
union REGS regs;
sets up a union of the type REGS with the name regs. That union will be later used to
store the address of the hardware function that we want to execute.
The third line:
__djgpp_nearptr_enable();
enables the "real memory access by way of pointers" mode. Since DJGPP compiles
protected mode programs, we can't directly access the computer hardware and memory, so we
must use this function to allow use to access them indirectly by using pointers. Again, if
you don't know what a pointer is, you shouldn't be reading this until you do.
Now the third line:
vgamemory=(char *)(0xA0000 + __djgpp_conventional_base);
tells your program that "vgamemory" points to the video memory (which starts at
0xA0000) plus the djgpp conventional base. The DJGPP conventional base is one of the
things that the __djgpp_nearptr_enable() function initializes, we use the DJGPP
conventional base to point to certain sections of memory by adding it to the real-mode
address. So basicly this line makes vgamemory point to a pointer that is pointing to the
video memory (wow, that was a breath full).
The 4th line:
if((vgabuffer=(char *)malloc(320*200))==0)
sets up the video buffer which is actually not needed, but if your going to program real
time graphics then it is (especially with game programming). All it does is it ask if it
can allocate 320*200 bytes of memory for the video buffer, and if it can, then it does.
Well, actually it does something a little different, but it ends out the same way.
The 5th line:
return(1);
is within the above if statement, and this will let you know that it couldn't allocate any
memory for the video buffer because it returns 1 and exits the function if it can't.
The 6th line:
regs.h.ah=0x00;
puts the byte 0x00 into the h.ah section of regs (whcih, if you remember, is a union).
0x00 is the hardware operation that tells the computer that you are about to change the
video mode. Right now this won't do anything, but we need it there for the int86 function
(which is coming).
Now the 7th line:
regs.h.al=0x13;
basically does the same thing as the 6th line except it puts a different byte into a
different section of "regs". The byte 0x13 represents the 13h video mode, this
is what will be past into the 0x00 function so that it knows which video mode to change
to.
The 8th line:
int86(0x10, regs, regs);
calls the bios interrupt 0x10, and passes regs.h.ah to 0x10 as the hardware function to
run, and then it passes regs.h.al to 0x10 (which is basically "run hardware
procedure/function") so that 0x10 will pass it to what ever is in regs.h.ah (in our
case 0x00). So this is the part of our function that actually CHANGES the video mode...
all the stuff before this was just preparing to change it.
The 9th (and last) line:
return(0);
just returns 0, which means that our function has successfully changed the video mode :)
Now how do I change the video mode back?
Well, all you really have to do is call the "video mode changing" hardware
function (0x00) with the text mode byte in regs.h.al, un-allocate the video buffer, and
then turn off the "real memory access by way of pointers" mode. So how do I do
that?! Well, here's the code for you:
void done_vga_mode(void)
{
union REGS regs;
regs.h.ah=0x00; //Procedure 0x00: Set Video Mode
regs.h.al=0x03; //The mode to set (0x# = #h)
int86(0x10, regs, regs); //Call BIOS intr 0x10
free(vgabuffer);
__djgpp_nearptr_disable();
}
So what does each line in that do? It does what I just said above: it calls the video mode
changing hardware function with the text mode byte in regs.h.al, un-allocates the video
buffer, and then turns off the "real memory access by way of pointers" mode.
How does this help me when I don't even know how to plot a pixel?
It doesn't, but if you don't know how to change the color palette then pixel plotting
doesn't help you either.
Any questions send mail to cplus@teentwo.8m.com
2. Setting the palette in mode 13h
What is the color palette?
The color palette is a hardware array (in other words, it's built
into your computers hardware) of pointers that point towards a set of RGB(Red Green Blue)
values. Each pointer in the array points to (as I stated above) an RGB value.
So there are actually 3 values in an RGB value:
R=amount of red in the color=a value that can range from 0-63 (0 being lowest and 63 being
highest)
G=amount of green in the color=a value that can range from 0-63 (0 being lowest and 63
being highest)
B=amount of blue in the color=a value that can range from 0-63 (0 being lowest and 63
being highest)
Therefor a full red would look like this: 63,0,0. And a full green
would look like this: 0,63,0. And a full blue would look like this: 0,0,63. Get the idea?
Good.
So it's just like in art class when you mixed red, yellow and blue paint together to make
different colors... except for two things:
1) Instead of yellow you have green.
2) Your not working with matter, your working with light.
Now I'm guessing that you know what the 1st difference means, but
you might not know what the second means. Basically it means that when you mix all of them
together at there highest strength (63,63,63) you get white (instead of black like with
the paint in art class) and instead of seeing the white paper when there was no paint on
it (0,0,0) you get black. Another way to look at it is by imagining the following:
A white piece of paper in a pitch black room.
- Now when you shine a red light on it (63,0,0), it makes the paper
red..
- When you shine a green light on it (0,63,0), it makes it green..
- When you shine a blue light on it (0,0,63), it makes is blue..
- When you shine all of the lights on it (63,63,63), it lets you see
the real papers color which is white..
- When you don't shine any light on it (0,0,0), the room is pitch dark.
So how do I change the palette's colors?
Well, there are several different ways to do it, my favorite (and the only one that I
actually know the code for) is the following:
void set_palette(int index, int red, int green, int blue)
{
outp(RGB_RESET, 0xFF); //Prepare the VGA card for the color change
outp(RGB_WRITE, index); //Tell which palette register to write to
//The following values can be anywhere from 0 to 63
outp(RGB_DATA, red); //change the red value
outp(RGB_DATA, green); //change the green value
outp(RGB_DATA, blue); //change the blue value
}
And the code above should work with DJGPP as long as you include the
following:
- dos.h
- bios.h
- dpmi.h
- stdio.h
- conio.h
- math.h
- stdlib.h
- go32.h
- pc.h
- sys/nearptr.h
and you define the following:
- #define RGB_RESET 0x03C6
- #define RGB_READ 0x03C7
- #define RGB_WRITE 0x03C8
- #define RGB_DATA 0x03C9
Of course I also have to tell you how to use this function...
basically you tell it which color you want to change (index) and then you give it the RGB
values (red, green, blue) which can each range from 0-63. So if you wanted to change the
color 58 to a RGB value of 20,20,20 (which would be a light gray) you would call the
function like this:
set_palette(58, 20, 20, 20);
Now some of you might be wondering how many colors there are in the
color palette... well, we're working with mode 320x200x256, so that means that we have 256
colors to work with, which are 0 through 255. So the highest number that you can enter
into the index parameter is 255 and the lowest is 0. Now don't get me wrong here, the
number of the color has nothing to do with what the color actually is, it's just a way to
place, find and use the color. example:
In one game you may have a color palette that is set up like so:
0=<0,0,0>
1=<1,1,1>
2=<2,2,2>
etc......
64=<1,0,0>
65=<2,0,0>
66=<3,0,0>
etc......
128=<0,1,0>
129=<0,2,0>
130=<0,3,0>
etc......
192=<0,0,1>
193=<0,0,2>
194=<0,0,3>
etc....... until 255
and then you might have another palette in a different game that's set up like this:
0=<3,7,2>
1=<7,2,5>
2=<9,1,3>
etc....... until 255
So as you can see that there are no restrictions as to which color you can put where, it's
all up to you. The indexes are just there so that your colors are organized and so that
you know where each color is on your color palette.
Now I will show you what the palette changing code does step by
step.
The first line of code:
void set_palette(int index, int red, int green, int blue)
just sets up the function and it's parameters.
The second line (which is after the "{"):
outp(RGB_RESET, 0xFF); //Prepare the VGA card for the color change
does exactly what the comment says: it prepares the VGA card for the palette change. But
how does it do that? It does that by calling 0xFF (which is a standard bios call which is
related to the VGA card) and passing 0x03C6 to it, which tells the VGA card that we want
to change the color palette.
The third line of code:
outp(RGB_WRITE, index); //Tell which palette register to write to
passes the value of our variable "index" to 0x03C8 which tells the VGA card
which color we want to change.
The fourth line of code:
outp(RGB_DATA, red); //change the red value
passes the value of "red" to 0x03C9. 0x03C9 is a hardware function that takes
what ever value is given to it and puts that value into the next color value in line, and
in this case since nothing has been edited since we called 0x03C8 it puts the value of
"red" into the R color value (remember "RGB"?).
The 5th line of code:
outp(RGB_DATA, green); //change the green value
does the same thing as the 4th except since 0x03C9 HAS been called once, it will now put
the value into the G color value instead of the R color value.
the 6th line of code:
outp(RGB_DATA, blue); //change the blue value
changes the B (from RGB) color value.
Color Rotation
Ah, color rotation... the signature of a pro. So what is it? Many older games
used it to make it look like water was moving since they couldn't update each pixel on the
screen (computers were very slow back then). SO WHAT IS IT!? Color rotation... one of the
finest effects one could ever hope to achieve.Well, color rotation is when you change the
color palette to give the affect of movement.
example:
You want to make it look like a water fall was actually falling, and lets say you've
already used up to many compute cycles to be able to afford to update the screen anymore
(yea right, like that could ever happen with a Pentium. But this is hypothetical...
remember?). So what would you do? Well, all you have to do is make lines of color down the
water fall, and each line is a different color palette index like this:
90,90,90,90,90,90
91,91,91,91,91,91
92,92,92,92,92,92
93,93,93,93,93,93
94,94,94,94,94,94
95,95,95,95,95,95
96,96,96,96,96,96
97,97,97,97,97,97
So now we just rotate the colors 90 through 97 so that the RGB value that was in 90 goes
into 91 and the RGB value that was in 91 goes into 92, and 93 goes into 94, etc. and then
at the end 97 goes back into 90. All you have to do is to do this each frame and it will
look like the water fall is falling. Of course strait lines don't look like a water fall,
but you get the idea. You can also do it to achieve different movement effects like a
pixel moving across the screen:
90, 91, 92, 93, 94, 95, 96, 97
And now you make the back ground black (0,0,0) and have all except one of the other colors
be black also and have the one that's not black be white or something like that and then
rotate 90 through 97. When you do that it gives the effect that a white pixel is moving
across the screen against a black back ground.
Any questions send mail to cplus@teentwo.8m.com
3. Mode 13h putpixel
There are faster ways to do this but this is by far
the easiets. This code will work in most compilers and not just DJGPP.
void putpixel(int x, int y, int color)
{
union REGS inregs,outregs;
inregs.h.ah = 12;
inregs.h.al = color;
inregs.x.cx = x;
inregs.x.dx = y;
int86(0x10, &inregs, &outregs);
}
Any questions send mail to cplus@teentwo.8m.com
| |
Newsgroups |
comp.lang.c
comp.lang.c++
comp.programming |
|