glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Really Nice Point Smoothing
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture
The code below will initialize each of the particles. We start off by activating each particle. If a particle is not active, it won't appear on the screen, no matter how much life it has.
After we've made the particle active, we give it life. I doubt the way I apply life, and fade the particles is the best way, but once again, it works good! Full life is 1.0f. This also gives the particle full brightness.
for (loop=0; loop<MAX_PARTICLES; loop++) // Initials All The Textures
{
particle[loop].active=true; // Make All The Particles Active
particle[loop].life=1.0f; // Give All The Particles Full Life
We set how fast the particle fades out by giving fade a random value. The variable life will be reduced by fade each time the particle is drawn. The value we end up with will be a random value from 0 to 99. We then divide it by 1000 so that we get a very tiny floating point value. Finally we then add .003 to the final result so that the fade speed is never 0.
particle[loop].fade = float(rand()%100)/1000.0f+0.003f; // Random Fade Speed
Now that our particle is active, and we've given it life, it's time to give it some color. For the initial effect, we want each particle to be a different color. What I do is make each particle one of the 12 colors that we've built in our color table at the top of this program. The math is simple. We take our loop variable and multiply it by the number of colors in our color table divided by the maximum number of particles (MAX_PARTICLES). This prevents the final color value from being higher than our max number of colors (12).
Some quick examples: 900*(12/900)=12. 1000*(12/1000)=12, etc.
particle[loop].r = colors[loop*(12/MAX_PARTICLES)][0]; // Select Red Rainbow Color
particle[loop].g = colors[loop*(12/MAX_PARTICLES)][1]; // Select Red Rainbow Color
particle[loop].b = colors[loop*(12/MAX_PARTICLES)][2]; // Select Red Rainbow Color
Now we'll set the direction that each particle moves, along with the speed. We're going to multiply the results by 10.0f to create a spectacular explosion when the program first starts.
We'll end up with either a positive or negative random value. This value will be used to move the particle in a random direction at a random speed.
particle[loop].xi = float((rand()%50)-26.0f)*10.0f; // Random Speed On X Axis
particle[loop].yi = float((rand()%50)-25.0f)*10.0f; // Random Speed On Y Axis
particle[loop].zi = float((rand()%50)-25.0f)*10.0f; // Random Speed On Z Axis
Finally, we set the amount of gravity acting on each particle. Unlike regular gravity that just pulls things down, our gravity can pull up, down, left, right, forward or backward. To start out we want semi strong gravity pulling downwards. To do this we set xg to 0.0f. No pull left or right on the x plane. We set yg to –0.8f. This creates a semi-strong pull downwards. If the value was positive it would pull upwards. We don't want the particles pulling towards or away from us so we'll set zg to 0.0f.
particle[loop].xg=0.0f; // Set Horizontal Pull To Zero
particle[loop].yg=-0.8f; // Set Vertical Pull Downward
particle[loop].zg=0.0f; // Set Pull On Z Axis To Zero
}
return TRUE; // Initialization Went OK
}
Now for the fun stuff. The next section of code is where we draw the particle, check for gravity, etc. It's important that you understand what's going on, so please read carefully :)
We reset the Modelview Matrix only once. We'll position the particles using the glVertex3f() command instead of using tranlations, that way we don't alter the modelview matrix while drawing our particles.
int DrawGLScene(GLvoid) // Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The ModelView Matrix
We start off by creating a loop. This loop will update each one of our particles.
for (loop=0; loop<MAX_PARTICLES; loop++) // Loop Through All The Particles
{
First thing we do is check to see if the particle is active. If it's not active, it wont be updated. In this program they're all active, all the time. But in a program of your own, you may want to make certain particles inactive.
if (particle[loop].active) // If The Particle Is Active
{
The next three variables x, y and z are temporary variables that we'll use to hold the particles x, y and z position. Notice we add zoom to the z position so that our scene is moved into the screen based on the value stored in zoom. particle[loop].x holds our x position for whatever particle we are drawing (particle loop). particle[loop].y holds our y position for our particle and particle[loop].z holds our z position.
float x=particle[loop].x; // Grab Our Particle X Position
float y=particle[loop].y; // Grab Our Particle Y Position
float z=particle[loop].z+zoom; // Particle Z Pos + Zoom
Now that we have the particle position, we can color the particle. particle[loop].r holds the red intensity of our particle, particle[loop].g holds our green intensity, and particle[loop].b holds our blue intensity. Notice I use the particles life for the alpha value. As the particle dies, it becomes more and more transparent, until it eventually doesn't exist. That's why the particles life should never be more than 1.0f. If you need the particles to burn longer, try reducing the fade speed so that the particle doesn't fade out as fast.
// Draw The Particle Using Our RGB Values, Fade The Particle Based On It's Life
glColor4f(particle[loop].r, particle[loop].g, particle[loop].b, particle[loop].life);
We have the particle position and the color is set. All that we have to do now is draw our particle. Instead of using a textured quad, I've decided to use a textured triangle strip to speed the program up a bit. Most 3D cards can draw triangles alot faster than they can draw quads. Some 3D cards will convert the quad to two triangles for you, but some don't. So we'll do the work ourselves. We start off by telling OpenGL we want to draw a triangle strip.
glBegin(GL_TRIANGLE_STRIP); // Build Quad From A Triangle Strip
Quoted directly from the red book: A triangle strip draws a series of triangles (three sided polygons) using vertices V0, V1 , V2, then V2, V1, V3 (note the order), then V2, V3, V4, and so on. The ordering is to ensure that the triangles are all drawn with the same orientation so that the strip can correctly form part of a surface. Preserving the orientation is important for some operations, such as culling. There must be at least 3 points for anything to be drawn.
So the first triangle is drawn using vertices 0, 1 and 2. If you look at the picture you'll see that vertex points 0, 1 and 2 do indeed make up the first triangle (top right, top left, bottom right). The second triangle is drawn using vertices 2, 1 and 3. Again, if you look at the picture, vertices 2, 1 and 3 create the second triangle (bottom right, top left, bottom left). Notice that both triangles are drawn with the same winding (counter-clockwise orientation). I've seen quite a few web sites that claim every second triangle is wound the opposite direction. This is not the case. OpenGL will rearrange the vertices to ensure that all of the triangles are wound the same way!