Professional Documents
Culture Documents
Introduction
------------
This series of tutorials describes a method of drawing filled polygons
using 3 rendering techniques: Solid, Gouraud shading, and texture mapping.
The code in this tutorial was written in Turbo C++ but can be ported to
other graphics libraries and operating systems. I did not use the
WGT functions in this one, so the wgtgfx.c file contains a few routines
which are needed for the demos. I have decided to explain the method
used for these routines since I had to discover them on my own, and
think you can learn from the code.
2.0 - Pseudo-code
-----------------
Our basic shaded line routine looks like this:
Calculate the step value
Make a color variable equal to the left endpoint color.
For x = x1 to x2
Put pixel on screen
Add step value to the color
End for
To make a step value with the whole portion in the upper byte, first we
need to shift the colors to the left by 8 bits. This will put the
color value in the high byte and leave the fraction as 0. Now to calculate
the step value, divide it by the length.
void shadedline (int x1, int firstcolor, int x2, int lastcolor, int y)
{
int length;
int numcolors;
int colorvalue;
int step;
int x;
length = x2 - x1 + 1;
if (length > 0)
{
numcolors = lastcolor - firstcolor + 1;
x1 is the left coordinate of the line, with firstcolor being the color
of this point.
x2 is the right coordinate of the line, with lastcolor being the color
of this point.
The following code shows how the drawpixel code has been simplified and
put directly into the shadedline routine.
void shadedline (int x1, int firstcolor, int x2, int lastcolor, int y)
{
int length;
int numcolors;
int colorvalue;
int step;
int x;
unsigned char far * dest; /* Ptr to the screen */
length = x2 - x1 + 1;
if (length > 0)
{
numcolors = lastcolor - firstcolor + 1;
colorvalue += step;
}
}
}
The code below shows how inline assembly is used to speed up the
routine:
void shadedline (int x1, int firstcolor, int x2, int lastcolor, int y)
{
int length;
int numcolors;
int colorvalue;
int step;
int x;
unsigned char far * dest; /* Ptr to the screen */
length = x2 - x1 + 1;
if (length > 0)
{
numcolors = lastcolor - firstcolor + 1;
typedef struct
{
int x,y;
} point;
Since each vertex now has a color associated with it, we will add another
variable to this structure, called col. The point structure becomes the
gpoint structure, which looks like this:
typedef struct
{
int x,y;
unsigned char col;
} gpoint;
int startcol[200];
int endcol[200];
When the list is created, we will have 2 x coordinates and a color value
associated with each of them. This is all the information we need to call
the shadedline routine.
The polyline routine becomes the gpolyline routine, which also calculates
the colors at the ends of each horizontal line. To do this, we use fixed
point math, similar to the way we calculated the colors along the length
of the line. This time we are adding the step value to the color
for every pixel we move down, instead of across.
void gpolyline (int x1, int y1, int col1, int x2, int y2, int col2)
/* Calculates the coordinates of a line given two
vertices (x1,y1) with color col1, and (x2,y2) with color col2.
*/
{
int tmp,y;
long x,m;
long col, colstep; /* First color, and the step value */
The fillpoly routine becomes the shadedpoly routine, which calls gpolyline
with the correct coordinates and color of each vertex, and finally the
shadedline routine.
for (i = 0; i < 200; i++) /* Now draw the horizontal line list */
if (startx[i] != -16000) /* Indicates there is a line on this row */
{
if (endx[i] == -16000)
endx[i] = startx[i]; /* In case there was only one
point found on this row */
shadedline (startx[i], startcol[i], endx[i], endcol[i], i);
/* Draw a shaded line between the two x coordinates, on the row i. */
}
}
The second case is easy to solve, since you can just decrease the length
of the line. In other words, chop off the pixels past 319. Note that
you should clip the line AFTER you calculate the step value since
changing the length will change the step value as well.
The code for clipping the right side would look something like this:
if (x2 > 319) /* Set right coordinate to right clipping coordinate */
x2 = 319;
The first case is a tricky one. We cannot simply set x1 to 0, since the
first color would be wrong. We have to increase the colorvalue to skip
over the pixels past the left edge. We know that for each pixel the
colorvalue is increased by the step value, so we can multiply the
step value by the number of pixels past the left edge and add the
result to the colorvalue. This will advance the color to the correct
value.
The code for clipping the right edge would look like this:
void shadedline (int x1, int firstcolor, int x2, int lastcolor, int y)
{
int length;
int numcolors;
int colorvalue;
int step;
int x;
unsigned char far * dest; /* Ptr to the screen */
int dist;
length = x2 - x1 + 1;
if (length > 0)
{
numcolors = lastcolor - firstcolor + 1;
length = x2 - x1 + 1;
Gouraud shading also involves calculating the normal of the polygon and
comparing it with the direction of the lightsource in order to find
realistic values of colors at each vertex. Since this deals with 3D
graphics, it is out of the scope of this tutorial. You don't always need
to take this into account however. You can base the color on the z value
of the vertex, or leave this out completely if you are strictly dealing
with 2D graphics. As well, you may want to set the colors of the vertices
once and leave them the same throughout the rest of the program.
I hope you enjoyed this tutorial. The next topic is texture mapping, which
is only a small change on the code presented here (believe it or not!).