Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

1. Terrain Class

Posted on : 25-03-2010 | By : Swiftless | In : Terrain

Tags: , , , , ,

1

Terrain is one of those things that so far, hasn’t been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the world. And is probably my inspiration for these tutorials.

Jump To:

heightfield.h Source
heightfield.cpp Source

main.cpp Source
Download

Heightfield.H File:

This tutorial is going on the basis that you have read at least some of the previous OpenGL tutorials. It pretty much starts off where the second camera tutorial ends. This tutorial unlike my previous OpenGL tutorials, is going to expand into multiple custom files include header and source code files while my previous tutorials just kept everything in the one file, and became quite messy. Anyway, time to begin.

First off we are going to look into our heightfield.h file. This is going to be our global header file for the creation of our terrain. I am going to create a custom class in here called SwiftHeightField with the following code:

// class SwiftHeightField {
// };

In here, I am going to start off with two public functions. The first is a boolean function that will handle that loading and creation of our heightfield, while the second will render our terrain.

We will start off by creating our Create function. The code will look like:

// class SwiftHeightField {

// public:
// bool Create(char *hFileName, int hWidth, int hHeight);
// };

The first variable hFileName will be the filename for the .RAW file we store our terrain height data in. The next two are the width and the height of the file in pixels so that we can load it in correctly.

The next function I am going to add is the Render function. This is just a basic void function that doesn’t return any value. Our heightfield.h file will look like this:

// class SwiftHeightField {

// public:
// bool Create(char *hFileName, int hWidth, int hHeight);
// void Render(void);
// };

This is all we are going to do in our heightfield.h file for now. Seems quite basic, but I want to keep it as basic as possible :-)

1.
2.
3.
4.
5.
6.
  class SwiftHeightField {

public:
bool Create(char *hFileName, int hWidth, int hHeight);

void Render(void);
};

Heightfield.CPP File:

Here is the start of our heightfield.cpp source code file. The first thing we need to do now is load in our heightfield.h file with the following line:

// #include "heightfield.h"

Our creation and rendering functions are going to be pretty much empty, because in this tutorial we are just starting off and getting everything ready for later when we really get into coding.

So we have our Create function:

// bool SwiftHeightField::Create(char *hFileName, int hWidth, int hHeight){
// return true;
// }

And our Render function:

// void SwiftHeightField::Render(void){

// }

1.
2.
3.
4.
5.
6.

7.
8.
9.
10.

  #include “heightfield.h”

bool SwiftHeightField::Create(char *hFileName, int hWidth, int hHeight){

return true;
}

void SwiftHeightField::Render(void){

}

Main.CPP File:

Here we have our main source code file. This is not going to change much until later on in the tutorials. It is pretty much as I said, the seconds camera tutorial. The first thing we need to do here is include our header file. So we add the line:

// #include "heightfield.h"

Then we need to add a variable that ties into our heightfield class. This is going to be added with:

// SwiftHeightField hField;

Now we have a class to hold our heightfield information for our terrain. So we need to Create our heightfield. So we call our Create function inside an initialization function, before we start drawing. So our Init function becomes:

// void Init (void) {

// glEnable(GL_DEPTH_TEST);

// hField.Create("", 1024, 1024);
// }

Note here that I am not actually loading anything. The blank "" will not throw back an error looking for a file named nothing, because our Create function does not try to load anything yet. (Remember, it’s blank inside, hehe). I just decided to place the integer 1024 for the width and height of the file, because that is the size I am going to be using later on.

We then need to move onto calling our Render function. This goes inside our display function after we perform our camera rotations. Our display function will look as such:

// void display (void) {
// glClearColor (0.0,0.0,0.0,1.0);
// glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// glLoadIdentity();
// camera();

// hField.Render();

// glutSwapBuffers();
// }

This is all we need for now. Check out the next tutorial on loading the heightfield data in here :)

If you have any questions, just email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.

8.
9.
10.
11.
12.
13.
14.
15.
16.

17.
18.
19.
20.
21.
22.
23.
24.
25.

26.
27.
28.
29.
30.
31.
32.
33.
34.

35.
36.
37.
38.
39.
40.
41.
42.
43.

44.
45.
46.
47.
48.
49.
50.
51.
52.

53.
54.
55.
56.
57.
58.
59.
60.
61.

62.
63.
64.
65.
66.
67.
68.
69.
70.

71.
72.
73.
74.
75.
76.
77.
78.
79.

80.
81.
82.
83.
84.
85.
86.
87.
88.

89.
90.
91.
92.
93.
94.
95.
96.
97.

98.
99.
100.
101.
102.
103.
104.
105.
106.

107.
108.
109.
110.
111.
112.
113.
114.
115.

116.
117.
118.
119.
120.
121.
122.
123.
124.

125.
126.
127.
128.

  #include <GL/glew.h>
#include <GL/gl.h>

#include <GL/glext.h>
#include <GL/GLUT.h>

#include <math.h>

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <fstream>

#include <assert.h>

#include “heightfield.h”

#pragma comment(lib,“glew32.lib”)

float xpos = 851.078, ypos = 351.594, zpos = 281.033, xrot = 
758, yrot = 238, angle=0.0;

float lastx, lasty;

float bounce;
float cScale = 1.0;

SwiftHeightField hField;

void camera (void) {
int posX = (int)xpos;

int posZ = (int)zpos;

glRotatef(xrot,1.0,0.0,0.0);
glRotatef(yrot,0.0,1.0,0.0);

glTranslated(-xpos,-ypos,-zpos);
}

void display (void) {

glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
camera();

hField.Render();

glutSwapBuffers();
}

void Init (void) {
glEnable(GL_DEPTH_TEST);

hField.Create(“”, 1024, 1024);
}

void mouseMovement(int x, int y) {

int diffx=x-lastx;
int diffy=y-lasty;
lastx=x;

lasty=y;
xrot += (float) diffy;
yrot += (float) diffx;

}

void keyboard (unsigned char key, int x, int y) {

if (key == ‘w’)
{
float xrotrad, yrotrad;

yrotrad = (yrot / 180 * 3.141592654f);
xrotrad = (xrot / 180 * 3.141592654f);

xpos += float(sin(yrotrad)) * cScale;
zpos -= float(cos(yrotrad)) * cScale;

ypos -= float(sin(xrotrad)) ;
bounce += 0.04;

}

if (key == ‘s’)
{
float xrotrad, yrotrad;

yrotrad = (yrot / 180 * 3.141592654f);
xrotrad = (xrot / 180 * 3.141592654f);

xpos -= float(sin(yrotrad)) * cScale;
zpos += float(cos(yrotrad)) * cScale;

ypos += float(sin(xrotrad));
bounce += 0.04;

}

if (key == ‘d’)
{
float yrotrad;

yrotrad = (yrot / 180 * 3.141592654f);
xpos += float(cos(yrotrad)) * cScale;

zpos += float(sin(yrotrad)) * cScale;
}

if (key == ‘a’)
{
float yrotrad;

yrotrad = (yrot / 180 * 3.141592654f);
xpos -= float(cos(yrotrad)) * cScale;

zpos -= float(sin(yrotrad)) * cScale;
}

}

void reshape (int w, int h) {
glViewport (0, 0, (GLsizei)w, (GLsizei)h);

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 1000.0);

glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(“A basic OpenGL Window);

Init();
glutDisplayFunc(display);
glutIdleFunc(display);

glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutPassiveMotionFunc(mouseMovement);

glutMainLoop ();
return 0;
} 

Download:

Download heightfield.h Source Code for this Tutorial

Download heightfield.cpp Source Code for this Tutorial

Download main.cpp Source Code for this Tutorial

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 7.3/10 (6 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 2 votes)

35. OpenGL Tiling Engine

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

12

Well due to a request, here is a tiling example for you all.

To tile in OpenGL, it is not that easy to merge or combine textures to create a simple 2D tiling game.
It is easier for us to draw a bunch of quads that take up the space of the world in which we want
to tile and assign different textures to those quads according to what is in our map file.

Here is the example of a map file that I am using for this tutorial, which is integrated into the code:

int cMap[10][10] = { //our map
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};

Now if you don’t like storing this in your program, you can just as easily store all of this in a file and loadit in when you need it.

So now that we have our ‘map’, we want to load in our two textures for our two states, 1 or 0, which will beeither grass or dirt in the case of the textures I have created.

I am setting 1 to be dirt, and 0 will be grass.

So as this is building on from the texturing tutorial, we need to create another variable to hold our other texture, as we already setup the first texture in the first tutorial.
GLuint texture2; //the array for our second texture

Now that we have our textures, we need to load them in, do this just like you did in the texturing tutorial:

    //Load our texture
    texture = LoadTexture(“texture.raw”, 256, 256);
    texture2 = LoadTexture(“texture2.raw”, 256, 256);

    glutMainLoop ();

    //Free our texture
    FreeTexture(texture);
    FreeTexture(texture2);

So now that we have our map, and our textures, we need to now draw it all. I am creating a method called drawTiles(). This method will be called in the display function and takes no parameters.

void drawTiles (void) { //our function to draw the tiles
First thing we want to do is start looping through the height of the map, the value of 10 here is specific
to this application. If you have a bigger or smaller map, change this value as you need.
for (int i = 0; i < 10; i++) //loop through the height of the map
{
Then we will want to loop through the width of the map, just as I said above, the value 10 is specific
to this tutorial.
for (int j = 0; j < 10; j++) //loop through the width of the map
{
Now here is where the main part of our tiling takes place, we need to check if the map value at the
current [i][j] position is either a 0 or a 1. If it is a 0, then we bind the grass texture to the quad
that we are about to draw.
if (cMap[i][j] == 0) //if the map at this position contains a 0
{
glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
}
Else we automatically assign it to dirt. If you have more than two states, you will need to make several if statements,
and if you do not want a default, then you will remove the else and replace it with an if.
else //otherwise
{
glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
}

The rest of the code draws a quad at the current i, j position we are at.
Drawing a quad should be simple for you at this stage. So I will not explain it.
glPushMatrix(); //push the matrix so that our translations only affect this tile
glTranslatef(j, -i, 0); //translate the tile to where it should belong

glBegin (GL_QUADS); //begin drawing our quads
glTexCoord2d(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord

glTexCoord2d(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to

glTexCoord2d(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);

glTexCoord2d(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glEnd();
glPopMatrix(); //pop the matrix
} //end first loop
} //end second loop
}

And there we have it, you can now create a 2D tiled map for use with a game. Simple wasn’t it? :-)
If you have any questions, email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.

  

#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>

GLuint texture; //the array for our texture
GLuint texture2; //the array for our second texture

int cMap[10][10] = { //our map
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};

//function to load the RAW file

GLuint LoadTexture( const char * filename, int width, int height )
{
    GLuint texture;
    unsigned char * data;
    FILE * file;

    //The following code will read in our RAW file
    file = fopen( filename, “rb” );
    if ( file == NULL ) return 0;
    data = (unsigned char *)malloc( width * height * 3 );
    fread( data, width * height * 3, 1, file );
    fclose( file );

    glGenTextures( 1, &texture )
    glBindTexture( GL_TEXTURE_2D, texture );
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE
 ); //set texture environment parameters

    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
GL_LINEAR
 );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR
 );

    //Here we are setting the parameter to repeat the texture 
instead of clamping the texture

    //to the edge of our shape. 
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT
 );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT
 );

    //Generate the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, 
GL_RGB,
 GL_UNSIGNED_BYTE, data);
    free( data ); //free the texture
    return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

void drawTiles (void) { //our function to draw the tiles
    for (int i = 0; i < 10; i++) //loop through the height of the map
    {
        for (int j = 0; j < 10; j++) //loop through the width of the map
        {
            if (cMap[i][j] == 0) //if the map at this position contains a 0
            {
                glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
            }
            else //otherwise
            {
                glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
            }
            
            glPushMatrix(); //push the matrix so that our translations only affect
 this tile

                glTranslatef(j, -i, 0); //translate the tile to where it should belong

                glBegin (GL_QUADS); //begin drawing our quads
                    glTexCoord2d(0.0, 0.0);
                    glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord

                    glTexCoord2d(1.0, 0.0);
                    glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to

                    glTexCoord2d(1.0, 1.0);
                    glVertex3f(1.0, 1.0, 0.0);

                    glTexCoord2d(0.0, 1.0);
                    glVertex3f(0.0, 1.0, 0.0);
                glEnd();
            glPopMatrix(); //pop the matrix
        } //end first loop
    } //end second loop
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable( GL_TEXTURE_2D );
    glTranslatef(-5, 4, -20); //translate back a bit to view the map correctly

    drawTiles(); //draw our tiles
    glutSwapBuffers();
}
void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);

    //Load our texture
    texture = LoadTexture(“texture.raw”, 256, 256);
    texture2 = LoadTexture(“texture2.raw”, 256, 256);

    glutMainLoop ();

    //Free our texture
    FreeTexture(texture);
    FreeTexture(texture2);

    return 0;
}

Download Texture(.RAW file)

Download the second Texture (.RAW file)

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.7/10 (3 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

32. OpenGL Particle Engine

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , ,

7

Today we are going to be working with particle engines. The one here
is pretty basic but extremely easy to use and expand on. I have even
added texture masking for weirdly shaped particles. But unfortunately
I am yet to change the color of these on-the-fly without disrupting the
masking so for the moment, you cannot change the color to a number such as
0.1, 0.2, 0.3… it must be a whole number. Eg: 1 or 0.

Anyway, lets get on with the tutorial.

————————————————————————
Section 1: Variables

First off, we need to declare our header files. For this project we need
#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <math.h>

This first variable I am going to use to hold the number of particles
we will display on the screen at any one time.
const ParticleCount = 500

Of course we also need something to hold our textures.
GLfloat texture[10];

Now here, I am creating a Type called PARTICLES which will hold all
our information for our particles.
typedef struct
{

The X position
double Xpos;
The Y position
double Ypos;
The Z position
double Zpos;
The movement on the X axis while being displayed
double Xmov;
The movement on the Z axis while being displayed
double Zmov;
The amount of Red within the object
double Red;
The amount of Green within the object
double Green;
The amount of Blue within the object
double Blue;
The angle of rotation
double Direction;
How fast it accelerates upwards
double Acceleration;
How fast it decelerates downwards
double Deceleration;
How much we wish to scale it
double Scalez;
}PARTICLES;

And now we will create a variable that will hold each of the PARTICLES
information for each actual Particle
PARTICLES Particle[ParticleCount];

————————————————————————
Section 2: Creation

To create the particles I am going to call the function glCreateParticles
during the initialization section of the code with:
glCreateParticles

Now for the creation function:
void glCreateParticles (void) {
This will be a temporary variable to cycle through our particles
int i;
We are going to loop through our particles until we reach the end
for (i = 1; i < ParticleCount; i++)
{

Set the inital X position to 0
Particle[i].Xpos = 0;
Set the inital Y position to -5
Particle[i].Ypos = -5;
Set the inital Z position to -5
Particle[i].Zpos = -5;
Set the amount of movement on the X axis to a random number, we dont want
all our particles doing the same thing :-P
Particle[i].Xmov = (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005) – (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005);
Set the amount of movement on the Z axis to a random number, as above, we dont
want all our particles doing the same thing :P
Particle[i].Zmov = (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005) – (((((((2 – 1 + 1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1) * 0.005);
Set the amount of Red to 1
Particle[i].Red = 1;
Set the amount of Green to 1
Particle[i].Green = 1;
Set the amount of Blue to 1
Particle[i].Blue = 1;
Scale the particle to 1 quarter of its original size
Particle[i].Scalez = 0.25;
Set the initial rotation angle to 0
Particle[i].Direction = 0;
Set the amount of acceleration to a random number so they climb to different
heights
Particle[i].Acceleration = ((((((8 – 5 + 2) * rand()%11) + 5) – 1 + 1) * rand()%11) + 1) * 0.02;
Decrease their acceleration by 0.0025. They will slow down at a constant
rate but you will not see a difference
Particle[i].Deceleration = 0.0025;
}
}

—————————————————————————-
Section 3: Updating the Particles

The particles would not be effective, if they stayed at their inital state, so
we want them to change and acctually move. I am doing this by calling:
glUpdateParticles in my Display function.

void glUpdateParticles (void) {
Once again, another temporary variable to handle the cycle through the particles
int i;
Loop through all of the particles
for (i = 1; i < ParticleCount; i++)
{

Set the color of the current particle
glColor3f (Particle[i].Red, Particle[i].Green, Particle[i].Blue);

Move the particle on the Y axes, adding on the amount of acceleration
and then subtracting the rate of deceleration
Particle[i].Ypos = Particle[i].Ypos + Particle[i].Acceleration – Particle[i].Deceleration;
Increase the deceleration rate so the particle falls gaining speed
Particle[i].Deceleration = Particle[i].Deceleration + 0.0025;

Move the particle on the X axis
Particle[i].Xpos = Particle[i].Xpos + Particle[i].Xmov;
Move the particle on the Z axis
Particle[i].Zpos = Particle[i].Zpos + Particle[i].Zmov;

Rotate the particle
Particle[i].Direction = Particle[i].Direction + ((((((int)(0.5 – 0.1 + 0.1) * rand()%11) + 1) – 1 + 1) * rand()%11) + 1);

Now here I am saying that if the particle goes beneath its initial height
which I set earlier to -5, then it will restart the particle changing some
of the variables.
if (Particle[i].Ypos < -5)
{

Set the X position
Particle[i].Xpos = 0;
Set the Y position
Particle[i].Ypos = -5;
Set the Z position
Particle[i].Zpos = -5;
Set the amount of Red
Particle[i].Red = 1;
Set the amount of Green
Particle[i].Green = 1;
Set the amount of Blue
Particle[i].Blue = 1;
Set the angle of rotation
Particle[i].Direction = 0;
Adjust the Acceleration rate to another random number
Particle[i].Acceleration = ((((((8 – 5 + 2) * rand()%11) + 5) – 1 + 1) * rand()%11) + 1) * 0.02;
Reset the Deceleration rate
Particle[i].Deceleration = 0.0025;
}
}
}

—————————————————————————-
Section 4: Drawing the Particles

To draw the particles, I am calling the following function: glDrawParticle
from within the Display function, after the updating function.

void glDrawParticles (void) {
Yet another temporary variable for our cycles
int i;
Looping through our particles again
for (i = 1; i < ParticleCount; i++)
{

Distinguish the start of our current particle, we do not wish for them
all to be affected by the ones prior
glPushMatrix();

Translate the particle on the X, Y and Z axis accordingly
glTranslatef (Particle[i].Xpos, Particle[i].Ypos, Particle[i].Zpos);

Rotate the particle
glRotatef (Particle[i].Direction – 90, 0, 0, 1);
Scale the particle
glScalef (Particle[i].Scalez, Particle[i].Scalez, Particle[i].Scalez);

Disable Depth Testing so our masking appears as one
glDisable (GL_DEPTH_TEST);
Enable blending
glEnable (GL_BLEND);

Set the blending function to Take our Destination Colour and combine it with
Zero which is Black
glBlendFunc (GL_DST_COLOR, GL_ZERO);
Bind our mask
glBindTexture (GL_TEXTURE_2D, texture[0]);

Draw our shape

glBegin (GL_QUADS);
glTexCoord2d (0, 0);
glVertex3f (-1, -1, 0);
glTexCoord2d (1, 0);
glVertex3f (1, -1, 0);
glTexCoord2d (1, 1);
glVertex3f (1, 1, 0);
glTexCoord2d (0, 1);
glVertex3f (-1, 1, 0);
glEnd();

Then set out blending function to combine White with White
glBlendFunc (GL_ONE, GL_ONE);
Bind our texture
glBindTexture (GL_TEXTURE_2D, texture[1]);

Draw the shape

glBegin (GL_QUADS);
glTexCoord2d (0, 0);
glVertex3f (-1, -1, 0);
glTexCoord2d (1, 0);
glVertex3f (1, -1, 0);
glTexCoord2d (1, 1);
glVertex3f (1, 1, 0);
glTexCoord2d (0, 1);
glVertex3f (-1, 1, 0);
glEnd();

Re-enable Depth Testing
glEnable(GL_DEPTH_TEST);

End the changes to the current object
glPopMatrix();

}
}
}

————————————————————————-

And there we have it, a simple particle engine that pumps out 500 particles
at a steady framerate of 80 frames per second.

If you have any questions, feel free to email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.

  #include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <math.h>

GLfloat texture[10];

const ParticleCount = 500;

typedef struct
{
double Xpos;
double Ypos;
double Zpos;
double Xmov;
double Zmov;
double Red;
double Green;
double Blue;
double Direction;
double Acceleration;
double Deceleration;
double Scalez;
bool Visible;
}PARTICLES;

PARTICLES Particle[ParticleCount];

GLuint LoadTextureRAW( const char * filename, int width, 
int height);
void FreeTexture( GLuint texturez );

void square (void) {
    glBindTexture( GL_TEXTURE_2D, texture[0] );
    glBegin (GL_QUADS);
    glTexCoord2d(0.0,0.0);
    glVertex2d(-1.0,-1.0);
    glTexCoord2d(1.0,0.0);
    glVertex2d(1.0,-1.0);
    glTexCoord2d(1.0,1.0);
    glVertex2d(1.0,1.0);
    glTexCoord2d(0.0,1.0);
    glVertex2d(-1.0,1.0);
    glEnd();
}

void glCreateParticles (void) {
int i;
for (i = 1; i < ParticleCount; i++)
{
Particle[i].Xpos = 0;
Particle[i].Ypos = -5;
Particle[i].Zpos = -5;
Particle[i].Xmov = (((((((2 - 1 + 1) * rand()%11) + 1) - 1 + 1) *
rand()%11) + 1) * 0.005) - (((((((2 - 1 + 1) * rand()%11) + 1) - 1 + 1
) * rand()%11) + 1) * 0.005);
Particle[i].Zmov = (((((((2 - 1 + 1) * rand()%11) + 1) - 1 + 1) *
rand()%11) + 1) * 0.005) - (((((((2 - 1 + 1) * rand()%11) + 1) - 1 + 1
) * rand()%11) + 1) * 0.005);
Particle[i].Red = 1;
Particle[i].Green = 1;
Particle[i].Blue = 1;
Particle[i].Scalez = 0.25;
Particle[i].Direction = 0;
Particle[i].Acceleration = ((((((8 - 5 + 2) * rand()%11) + 5
) - 1 + 1) * rand()%11) + 1) * 0.02;
Particle[i].Deceleration = 0.0025;
}
}

void glUpdateParticles (void) {
int i;
for (i = 1; i < ParticleCount; i++)
{

glColor3f (Particle[i].Red, Particle[i].Green,
Particle[i].Blue);

Particle[i].Ypos = Particle[i].Ypos + Particle[i]
.Acceleration - Particle[i].Deceleration;
Particle[i].Deceleration = Particle[i].Deceleration +
0.0025;

Particle[i].Xpos = Particle[i].Xpos + Particle[i].Xmov;
Particle[i].Zpos = Particle[i].Zpos + Particle[i].Zmov;

Particle[i].Direction = Particle[i].Direction + ((((((int
)(0.5 - 0.1 + 0.1) * rand()%11) + 1) - 1 + 1) * rand()%11) + 1);

if (Particle[i].Ypos < -5)
{
Particle[i].Xpos = 0;
Particle[i].Ypos = -5;
Particle[i].Zpos = -5;
Particle[i].Red = 1;
Particle[i].Green = 1;
Particle[i].Blue = 1;
Particle[i].Direction = 0;
Particle[i].Acceleration = ((((((8 - 5 + 2) * rand()%11) + 5
) - 1 + 1) * rand()%11) + 1) * 0.02;
Particle[i].Deceleration = 0.0025;
}

}
}

void glDrawParticles (void) {
int i;
for (i = 1; i < ParticleCount; i++)
{
glPushMatrix();

    glTranslatef (Particle[i].Xpos, Particle[i].Ypos, Particle[i].Zpos);
    glRotatef (Particle[i].Direction - 90, 0, 0, 1);
   
    glScalef (Particle[i].Scalez, Particle[i].Scalez, Particle[i].Scalez);
   
    glDisable (GL_DEPTH_TEST);
    glEnable (GL_BLEND);
        
    glBlendFunc (GL_DST_COLOR, GL_ZERO);
    glBindTexture (GL_TEXTURE_2D, texture[0]);

    glBegin (GL_QUADS);
    glTexCoord2d (0, 0);
    glVertex3f (-1, -1, 0);
    glTexCoord2d (1, 0);
    glVertex3f (1, -1, 0);
    glTexCoord2d (1, 1);
    glVertex3f (1, 1, 0);
    glTexCoord2d (0, 1);
    glVertex3f (-1, 1, 0);
    glEnd();
    
    glBlendFunc (GL_ONE, GL_ONE);
    glBindTexture (GL_TEXTURE_2D, texture[1]);
    
    glBegin (GL_QUADS);
    glTexCoord2d (0, 0);
    glVertex3f (-1, -1, 0);
    glTexCoord2d (1, 0);
    glVertex3f (1, -1, 0);
    glTexCoord2d (1, 1);
    glVertex3f (1, 1, 0);
    glTexCoord2d (0, 1);
    glVertex3f (-1, 1, 0);
    glEnd();
        
    glEnable(GL_DEPTH_TEST);

glPopMatrix();

}
}

void display (void) {
    glClearDepth (1);
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();  
    glTranslatef (0,0,-10);
    glUpdateParticles();
    glDrawParticles();
    glutSwapBuffers();
}

void init (void) {
    glEnable( GL_TEXTURE_2D );
    glEnable(GL_DEPTH_TEST);

    glCreateParticles();

    texture[0] = LoadTextureRAW( “particle_mask.raw”,256,256
); //load our texture
    texture[1] = LoadTextureRAW( “particle.raw”,256,256);
//load our texture
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    init();
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

//function to load the RAW file

GLuint LoadTextureRAW( const char * filename, int width, 
int height )
{
  GLuint texture;
  unsigned char * data;
  FILE * file;

  file = fopen( filename, “rb” );
  if ( file == NULL ) return 0;

  data = (unsigned char *)malloc( width * height * 3 );

  fread( data, width * height * 3, 1, file );
  fclose( file );

  glGenTextures(1, &texture );            

  glBindTexture(GL_TEXTURE_2D, texture);

  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
GL_REPEAT);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
GL_REPEAT);

  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE );

  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR_MIPMAP_NEAREST );

  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR );

  gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, 
GL_RGB, GL_UNSIGNED_BYTE, data);

  free( data );

  return texture;
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture );
}

Download Texture(.RAW file)

Download Texture Mask(.RAW file)

Download Texture(.BMP file)

Download Texture Mask(.BMP file)

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 6.5/10 (4 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 2 votes)
Improve the web with Nofollow Reciprocity.