Well greetings all. For those of you that want to see what we are doing here, you can check it out
at the end of my demo/hack Worthless! I am bosco and I will do my best to teach you guys how to do
the animated, sine-wave picture. This tutorial is based on NeHe's tutorial #6 and you should have at
least that much knowledge. You should download the source package and place the bitmap I've included
in a directory called data where your source code is. Or use your own texture if it's an appropriate
size to be used as a texture with OpenGL.
First things first. Open Tutorial #6 in the applicable source editor. And add the following
somewhere near the top next to their respective counterparts.
#include <math.h> // For the sin() function
float points[ 45 ][ 45 ][3]; // The array for the points on the grid of our "wave"
We'll use this array, "points" to store the individual x, y, z coordinates of our grid. The grid is
45 points by 45 points, which in turn makes 44 quads x 44 quads. Also add the following line toward
the top next to the array.
int wiggle_count = 0;
We'll use this variable to decide when to "cycle" our sine values and animate our wave. Every three
frames looks really good on my box.
Change the filename in the LoadGLTextures() function to the appropriate file. I personally like my
bitmap in the same directory as my executable, but that's just me, so my line looks like this.
texture1 = auxDIBImageLoad("tim.bmp");
Now add the following code to the bottom of the InitGL() function before the closing "}".
for(float float_x = 0.0f; float_x < 9.0f; float_x += 0.2f )
{
for( float float_y = 0.0f; float_y < 9.0f; float_y += 0.2f)
{
points[ int(float_x*5) ][ int(float_y*5) ][0] = float_x - 4.4f;
points[ int(float_x*5) ][ int(float_y*5) ][1] = float_y - 4.4f;
points[ int(float_x*5) ][ int(float_y*5) ][2] = float(sin( ( (float_x*5*8)/360 ) * 3.14159 * 2 ));
}
}
Ok, before I said our grid is 45 points by 45 points. Well to accomplish this without having to push
our scene back too far, we merely use a world coordinate of 9x9 and space the points 0.2 units
apart.
These two loops initialize the points on our grid. I initialize variables in my loop to localize them
in my mind as merely loop variables. Not sure it's kosher. To come up with the array reference we
have to multiply our loop variable by 5 ( i.e. 45 / 9 = 5 ). I subtract 4.4 from each of the
coordinates to put the "wave" centered on the origin. The same effect could be accomplished with a
translate, but I prefer this method.
The final value points[x][y][2] statement is our sine value. The sin() function requires radians. We
take our degree value, which is our float_x multiplied by 5 to get a whole number and then by 8
( i.e. 360/8 is 45 ). Once we have that, to convert to radians we take the degree, divide by 360,
multiply by pi, or an approximation and then multiply by 2.
I'm going to re-write the DrawGLScene function from scratch so clean it out and it replace with the
following code.
GLvoid DrawGLScene(GLvoid)
{
int x, y;
float float_x, float_y, float_xb, float_yb;
Different variables used for controlling the loops. See the code below but most of these serve no
"specific" purpose other than controlling loops and storing temporary values.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-12.0f);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, texture[0]);
You've seen all of this before as well. Same as in tutorial #6 except I merely push my scene back
away from the camera a bit more.
glPolygonMode( GL_BACK, GL_FILL );
glPolygonMode( GL_FRONT, GL_LINE );
These simple specify that we want back facing polygons to be filled completely and that we want
front facing polygons to be outlined only. Mostly personal preference at this point. Has to do with
the orientation of the polygon or the direction of the vertices. See the Red Book for more
information on this. Incidentally, while I'm at it, let me plug that as it's one of the driving
forces behind me learning OpenGL, not to mention NeHe's site! Thanks NeHe. Buy The Programmer's
Guide to OpenGL from Addison-Wesley. It's an invaluable resource as far as I'm concerned. Ok, back
to the tutorial.
glBegin( GL_QUADS );
for( x = 0; x < 44; x++ )
{
for( y = 0; y < 44; y++ )
{
Merely starts the loop to draw our polygons. I use integers here to keep from having to use the
int() function as I did earlier to get the array reference returned as an integer.
float_x = float(x)/44;
float_y = float(y)/44;
float_xb = float(x+1)/44;
float_yb = float(y+1)/44;
We use these four variables for the texture coordinates. Each of our polygons(quads), square in the
grid, has a 1/44 x 1/44 section of the texture mapped on it. The loops will specify the lower left
vertex and then we just add to it accordingly to get the other three ( i.e. x+1 or y+1 ).
glTexCoord2f( float_x, float_y);
glVertex3f( points[x][y][0], points[x][y][1], points[x][y][2] );
glTexCoord2f( float_x, float_yb );
glVertex3f( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );
glTexCoord2f( float_xb, float_yb );
glVertex3f( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );
glTexCoord2f( float_xb, float_y );
glVertex3f( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
}
}
glEnd();
These lines merely make the OpenGL calls to pass all the data we talked about. Four separate calls
to each glTexCoord2f() and glVertex3f(). Continue with the following.
if( wiggle_count == 2 )
{
If we've drawn two scenes, then we want to cycle our sine values giving us "motion".
for( y = 0; y < 45; y++)
{
points[44][y][2] = points[0][y][2];
}
This sets all of the last column of our grid's values to be equal to our grid's first values. If you
have trouble seeing this, think of a conveyor belt. When the item gets pushed off the end the
conveyor belt returns to the beginning to get another item. Same concept here. The point is being
pushed off the end so we send it back to the beginning.
for( x = 0; x < 44; x++ )
{
for( y = 0; y < 45; y++)
{
points[x][y][2] = points[x+1][y][2];
}
}
wiggle_count = 0;
}
wiggle_count++;
What we do here is cycle the rest of the values. Pushing everything one position toward the end. And
so if we did do this, then we want to set our "frame" counter back to zero. If we didn't, in fact,
move our values, then we need to increment our counter. I'll admit this isn't a real "scalable" way
of doing things, but hey what can I say, it looks great on mine and most everyone else's machine and
I'm not perfect.. ( gasp! ) Tweak at will.
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
}
Standard NeHe rotation values. :) And that's it folks. Compile and you should have a nice rotating
bitmapped "wave". I'm not sure what else to say except, whew.. This was LONG! But I hope you guys
can follow it/get something out of it. If you have any questions, want me to clear something up or
tell me how god awful, lol, I code, then send me a note. Also there is a slight visual glitch in
this effect. If you notice it and/or can fix it send me some mail as well. I played with it a bit
and decided it wasn't worth the trouble.. Other than that, this was a blast, but very energy/time
consuming and makes me appreciate the likes of NeHe ALOT more now. Thanks all.
Bosco (bosco4@home.com)
* DOWNLOAD Visual C++ Code For This Lesson.
* DOWNLOAD Visual Fortran Code For This Lesson.
( Conversion by Jean-Philippe Perois )
* DOWNLOAD Delphi Code For This Lesson.
( Conversion by Marc Aarts )
* DOWNLOAD Mac OS Code For This Lesson.
( Conversion by Anthony Parker )
* DOWNLOAD Power Basic Code For This Lesson.
( Conversion by Angus Law )
* DOWNLOAD Java Code For This Lesson.
( Conversion by Darren Hodges )