www.pudn.com > Particles1.zip > main.cpp
/**********************************************************************
Particle Engine / Billboarding
October, 21st, 2002
This tutorial was written by Philipp Crocoll
Contact:
philipp.crocoll@web.de
www.codecolony.de
Every comment would be appreciated.
If you want to use parts of any code of mine:
let me know and
use it!
If you get cool effects with this particle engine,
I would be happy if you could send me the code. If you want to,
I can upload it. This code is only a part of what you can do with
this engine.
***********************************************************************
ESC : Exit
w,a,s,d,r,f,x,y,c,v : move / turn
**********************************************************************/
#include //includes gl.h and glu.h
#include //load the texture
#include //random function
#include //sine and cosine functions
#include "Camera.h"
#include "particles.h"
//Particle variables:
CCCParticleSystem g_ParticleSystem1;
CCCParticleSystem g_ParticleSystem2;
CCCParticleSystem g_ParticleSystem3;
CCCParticleSystem g_ParticleSystem4;
CCCParticleSystem g_ParticleSystem5;
CCCParticleSystem g_ParticleSystem6;
//g_Camera:
CCamera g_Camera;
//Time handling (note: use QueryPerformanceCounter in "real" projects!)
long unsigned int g_iLastRenderTime = 0;
//code from the camera tutorial:
void DrawNet(GLfloat size, GLint LinesX, GLint LinesZ)
{
glBegin(GL_LINES);
for (int xc = 0; xc < LinesX; xc++)
{
glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size,
0.0,
size / 2.0);
glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size,
0.0,
size / -2.0);
}
for (int zc = 0; zc < LinesX; zc++)
{
glVertex3f( size / 2.0,
0.0,
-size / 2.0 + zc / (GLfloat)(LinesZ-1)*size);
glVertex3f( size / -2.0,
0.0,
-size / 2.0 + zc / (GLfloat)(LinesZ-1)*size);
}
glEnd();
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Load a new modelview matrix -> we can apply new transformations
//Update the scene:
long unsigned int iNowTime = timeGetTime();
float timePassed = float(iNowTime-g_iLastRenderTime)/1000.0f; //divide by 1000
g_ParticleSystem1.UpdateSystem(timePassed);
g_ParticleSystem2.UpdateSystem(timePassed);
g_ParticleSystem3.UpdateSystem(timePassed);
g_ParticleSystem4.UpdateSystem(timePassed);
g_ParticleSystem5.UpdateSystem(timePassed);
g_ParticleSystem6.UpdateSystem(timePassed);
g_iLastRenderTime = iNowTime;
//render everything:
g_Camera.Render();
//render an opaque quadrangle: (if you want to see how to do this...)
/* glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f,0.0,1.0f);
glBegin(GL_POLYGON);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glVertex3f(1.0f,1.0f,0.0f);
glVertex3f(0.0f,1.0f,0.0f);
glEnd();
*/
//render the nets, so switch off blending and texturing:
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
//enable depth testing (and z-buffer-writing)
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
GLfloat size = 2.0;
GLint LinesX = 30;
GLint LinesZ = 30;
glColor3f(1.0,0.0,0.0);
glPushMatrix();
glTranslatef(0.0,0.0 ,0.0);
DrawNet(size,LinesX,LinesZ);
glTranslatef(0.0,size,0.0);
DrawNet(size,LinesX,LinesZ);
glPopMatrix();
//Render system 2 first, it's not textured:
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
//Calculate the point size depending from the camera's distance to the emitter:
//(in order to be 100% exact we would have to pass the camera position to the
//particles' render function. This method would then have to calculate the point size for each particle!)
float zDist = g_Camera.GetPosition().z - g_ParticleSystem2.m_EmitterPosition.z;
float xDist = g_Camera.GetPosition().x - g_ParticleSystem2.m_EmitterPosition.x;
float CamDistToEmitter = sqrt(SQR(zDist)+SQR(xDist));
if (CamDistToEmitter < 0.2f) //avoid too big particles
CamDistToEmitter = 0.2f;
glPointSize(1.0f/CamDistToEmitter);
g_ParticleSystem2.Render();
//Now enable texturing and render the other particle systems:
glEnable(GL_TEXTURE_2D);
g_ParticleSystem1.Render();
g_ParticleSystem3.Render();
g_ParticleSystem4.Render();
g_ParticleSystem5.Render();
g_ParticleSystem6.Render();
glDepthMask(GL_TRUE);
glFlush(); //Finish rendering
glutSwapBuffers(); //Swap the buffers ->make the result of rendering visible
}
void Reshape(int x, int y)
{
if (y == 0 || x == 0) return; //Nothing is visible then, so return
//Set a new projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Angle of view:40 degrees
//Near clipping plane distance: 0.5
//Far clipping plane distance: 20.0
gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.05,10.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,x,y); //Use the whole window for rendering
}
void KeyDown(unsigned char key, int x, int y)
{
switch(key)
{
case 27: //ESC
exit(0);
break;
case 'a':
g_Camera.RotateY(5.0);
Display();
break;
case 'd':
g_Camera.RotateY(-5.0);
Display();
break;
case 'w':
g_Camera.MoveForwards( -0.1 ) ;
Display();
break;
case 's':
g_Camera.MoveForwards( 0.1 ) ;
Display();
break;
case 'x':
g_Camera.RotateX(5.0);
Display();
break;
case 'y':
g_Camera.RotateX(-5.0);
Display();
break;
case 'c':
g_Camera.StrafeRight(-0.1);
Display();
break;
case 'v':
g_Camera.StrafeRight(0.1);
Display();
break;
case 'f':
g_Camera.Move(F3dVector(0.0,-0.3,0.0));
Display();
break;
case 'r':
g_Camera.Move(F3dVector(0.0,0.3,0.0));
Display();
break;
}
}
void InitParticles()
{
//INIT SYSTEM 1 (FIRE1)
g_ParticleSystem1.Initialize(300);
g_ParticleSystem1.m_iParticlesCreatedPerSec = 300;
g_ParticleSystem1.m_fCreationVariance = 0.0f;
g_ParticleSystem1.m_bRecreateWhenDied = false;
g_ParticleSystem1.m_fMinDieAge = 0.5f;
g_ParticleSystem1.m_fMaxDieAge = 1.5f;
g_ParticleSystem1.SetCreationColor(1.0f,0.0f,0.0f,
1.0f,0.5f,0.0f);
g_ParticleSystem1.SetDieColor(1.0f,1.0f,1.0f,
1.0f,0.5f,0.0f);
g_ParticleSystem1.SetAlphaValues(1.0f,1.0f,0.0f,0.0f);
g_ParticleSystem1.SetEmitter(0.0f,0.0f,0.5f,
0.1f,0.0f,0.1f);
g_ParticleSystem1.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f);
g_ParticleSystem1.SetSizeValues(0.04f,0.08f,0.06f,0.12f);
g_ParticleSystem1.m_fMaxEmitSpeed = 0.2f;
g_ParticleSystem1.m_fMinEmitSpeed = 0.3f;
g_ParticleSystem1.SetEmissionDirection(0.0f,1.0f,0.0f,
0.08f,0.5f,0.08f);
g_ParticleSystem1.m_bParticlesLeaveSystem = true;
g_ParticleSystem1.SetSpinSpeed(-0.82*PI,0.82*PI);
g_ParticleSystem1.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR;
g_ParticleSystem1.LoadTextureFromFile("particle1.tga");
//INIT SYSTEM 2 (POINTS, FIREWORK)
g_ParticleSystem2.Initialize(800); //particle system must not have more than 800 particles
g_ParticleSystem2.m_iParticlesCreatedPerSec = 800; //we create all particles in the first second of the system's life
g_ParticleSystem2.m_fMinDieAge = 2.5f; //but the particles live longer than one second
g_ParticleSystem2.m_fMaxDieAge = 2.5f; //-> this causes the system to "shoot" periodically
g_ParticleSystem2.m_fCreationVariance = 1.0f;
g_ParticleSystem2.m_bRecreateWhenDied = true;
g_ParticleSystem2.SetCreationColor(1.0f,1.0f,1.0f,
0.5f,0.5f,0.5f);
g_ParticleSystem2.SetDieColor(0.0f,1.0f,0.0f,
0.0f,0.3f,0.0f);
g_ParticleSystem2.SetAlphaValues(1.0f,1.0f,0.0f,0.0f);
g_ParticleSystem2.SetEmitter(0.8f,0.0f,0.0f,
0.02f,0.0f,0.02f);
g_ParticleSystem2.SetAcceleration(F3dVector(0.0f,-1.0f,0.0f),0.83f,1.4f);
g_ParticleSystem2.SetSizeValues(3.0f,3.0f,4.0f,4.0f);
g_ParticleSystem2.m_fMaxEmitSpeed = 0.82f;
g_ParticleSystem2.m_fMinEmitSpeed = 1.3f;
g_ParticleSystem2.SetEmissionDirection(-1.0f,2.0f,0.0f,
0.5f,0.5f,0.5f);
g_ParticleSystem2.m_bParticlesLeaveSystem = true;
//INIT SYSTEM 3 (RAIN)
g_ParticleSystem3.Initialize(10000);
g_ParticleSystem3.m_iParticlesCreatedPerSec = 4950;
g_ParticleSystem3.m_fCreationVariance = 0.0f;
g_ParticleSystem3.m_bRecreateWhenDied = false;
g_ParticleSystem3.m_fMinDieAge = 2.0f;
g_ParticleSystem3.m_fMaxDieAge = 2.0f;
g_ParticleSystem3.SetCreationColor(0.0f,0.0f,1.0f,
0.3f,0.3f,1.0f);
g_ParticleSystem3.SetDieColor(0.4f,0.4f,1.0f,
0.0f,0.0f,1.0f);
g_ParticleSystem3.SetAlphaValues(1.0f,1.0f,1.0f,1.0f);
g_ParticleSystem3.SetEmitter(0.0f,2.0f,0.0f,
1.0f,0.0f,1.0f);
g_ParticleSystem3.SetAcceleration(NULL_VECTOR,0.0f,0.0f);
g_ParticleSystem3.SetSizeValues(0.01f,0.01f,0.01f,0.01f);
g_ParticleSystem3.m_fMaxEmitSpeed = 1.0f;
g_ParticleSystem3.m_fMinEmitSpeed = 1.0f;
g_ParticleSystem3.SetEmissionDirection(0.0f,-1.0f,0.0f,
0.00f,0.0f,0.00f);
g_ParticleSystem3.m_bParticlesLeaveSystem = true;
g_ParticleSystem3.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR_BUTVERTICAL;
g_ParticleSystem3.LoadTextureFromFile("particle2.tga");
//INIT SYSTEM 4 (SMOKE)
g_ParticleSystem4.Initialize(150);
g_ParticleSystem4.m_iParticlesCreatedPerSec = 50;
g_ParticleSystem4.m_fCreationVariance = 0.0f;
g_ParticleSystem4.m_bRecreateWhenDied = false;
g_ParticleSystem4.m_fMinDieAge = 2.5f;
g_ParticleSystem4.m_fMaxDieAge = 3.5f;
g_ParticleSystem4.SetCreationColor(0.1f,0.1f,0.1f,
0.2f,0.2f,0.2f);
g_ParticleSystem4.SetDieColor(0.0f,0.0f,0.0f,
0.0f,0.0f,0.0f);
g_ParticleSystem4.SetAlphaValues(1.0f,1.0f,0.0f,0.0f);
g_ParticleSystem4.SetEmitter(-0.8f,0.0f,0.0f,
0.0f,0.0f,0.0f);
g_ParticleSystem4.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f);
g_ParticleSystem4.SetSizeValues(0.0f,0.0f,1.12f,1.22f);
g_ParticleSystem4.m_fMaxEmitSpeed = 0.01f;
g_ParticleSystem4.m_fMinEmitSpeed = 0.04f;
g_ParticleSystem4.SetEmissionDirection(0.0f,1.0f,0.0f,
0.08f,0.5f,0.08f);
g_ParticleSystem4.m_bParticlesLeaveSystem = true;
g_ParticleSystem4.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR;
g_ParticleSystem4.LoadTextureFromFile("particle3.tga");
//INIT SYSTEM 5 ("ENGINE")
g_ParticleSystem5.Initialize(300);
g_ParticleSystem5.m_iParticlesCreatedPerSec = 200;
g_ParticleSystem5.m_fCreationVariance = 0.0f;
g_ParticleSystem5.m_bRecreateWhenDied = false;
g_ParticleSystem5.m_fMinDieAge = 1.0f;
g_ParticleSystem5.m_fMaxDieAge = 1.3f;
g_ParticleSystem5.SetCreationColor(0.5f,0.0f,0.0f,
0.5f,0.1f,0.1f);
g_ParticleSystem5.SetDieColor(0.2f,0.2f,0.0f,
0.8f,0.8f,0.0f);
g_ParticleSystem5.SetAlphaValues(1.0f,1.0f,0.3f,0.3f);
g_ParticleSystem5.SetEmitter(0.0f,0.0f,-1.0f,
0.02f,0.02f,0.0f);
g_ParticleSystem5.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.0f,0.0f);
g_ParticleSystem5.SetSizeValues(0.12f,0.12f,0.06f,0.06f);
g_ParticleSystem5.m_fMaxEmitSpeed = 0.12f;
g_ParticleSystem5.m_fMinEmitSpeed = 0.14f;
g_ParticleSystem5.SetEmissionDirection(0.0f,0.0f,1.0f,
0.00f,0.0f,0.00f);
g_ParticleSystem5.m_bParticlesLeaveSystem = true;
g_ParticleSystem5.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR;
g_ParticleSystem5.LoadTextureFromFile("particle3.tga");
//INIT SYSTEM 6 (FIRE2)
g_ParticleSystem6.Initialize(300);
g_ParticleSystem6.m_iParticlesCreatedPerSec = 300;
g_ParticleSystem6.m_bRecreateWhenDied = false;
g_ParticleSystem6.m_fMinDieAge = 0.5f;
g_ParticleSystem6.m_fMaxDieAge = 1.0f;
g_ParticleSystem6.SetCreationColor(1.0f,0.0f,0.0f,
1.0f,0.5f,0.0f);
g_ParticleSystem6.SetDieColor(1.0f,1.0f,1.0f,
1.0f,0.5f,0.0f);
g_ParticleSystem6.SetAlphaValues(1.0f,1.0f,0.0f,0.0f);
g_ParticleSystem6.SetEmitter(0.0f,0.0f,0.5f,
0.18f,0.0f,0.18f);
g_ParticleSystem6.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f);
g_ParticleSystem6.SetSizeValues(0.04f,0.08f,0.06f,0.12f);
g_ParticleSystem6.m_fMaxEmitSpeed = 0.12f;
g_ParticleSystem6.m_fMinEmitSpeed = 0.23f;
g_ParticleSystem6.SetEmissionDirection(0.0f,1.0f,0.0f,
0.08f,0.5f,0.08f);
g_ParticleSystem6.m_bParticlesLeaveSystem = true;
g_ParticleSystem6.SetSpinSpeed(-0.82*PI,0.82*PI);
g_ParticleSystem6.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR;
g_ParticleSystem6.LoadTextureFromFile("particle1.tga");
}
int main(int argc, char **argv)
{
//Initialize GLUT
glutInit(&argc, argv);
//Lets use doublebuffering, RGB(A)-mode and a depth buffer
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800,600);
//Create a window with rendering context and everything else we need
glutCreateWindow("Particle Engine and Billboarding");
//Init some state variables:
glDisable(GL_DEPTH_TEST);
glClearColor(0.1,0.1,0.1,1.0);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //also try GL_LINE
g_Camera.Move(F3dVector(0.0f,0.3f,3.0f));
//INITIALIZE THE PARTICLE SYSTEM:
InitParticles();
//Assign the event-handling routines
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutKeyboardFunc(KeyDown);
glutIdleFunc(Display); //If there is no msg, we have to repaint
g_iLastRenderTime = timeGetTime();
//Let GLUT get the msgs and tell us the ones we need
glutMainLoop();
return 0;
}