1
0
Fork 0
mirror of https://github.com/gwm17/glfw.git synced 2024-11-23 02:38:52 -05:00

Formatted particles example.

This commit is contained in:
Camilla Berglund 2014-01-11 20:30:37 +01:00
parent d9f53c78a0
commit 3f9117ef85

View File

@ -68,18 +68,24 @@
// Type definitions // Type definitions
//======================================================================== //========================================================================
typedef struct { float x,y,z; } VEC; typedef struct
{
float x, y, z;
} Vec3;
// This structure is used for interleaved vertex arrays (see the // This structure is used for interleaved vertex arrays (see the
// DrawParticles function) - Note: This structure SHOULD be packed on most // draw_particles function)
// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple //
// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas // NOTE: This structure SHOULD be packed on most systems. It uses 32-bit fields
// or whatever to force the structure to be packed. // on 32-bit boundaries, and is a multiple of 64 bits in total (6x32=3x64). If
typedef struct { // it does not work, try using pragmas or whatever to force the structure to be
// packed.
typedef struct
{
GLfloat s, t; // Texture coordinates GLfloat s, t; // Texture coordinates
GLuint rgba; // Color (four ubytes packed into an uint) GLuint rgba; // Color (four ubytes packed into an uint)
GLfloat x, y, z; // Vertex coordinates GLfloat x, y, z; // Vertex coordinates
} VERTEX; } Vertex;
//======================================================================== //========================================================================
@ -165,7 +171,7 @@ const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = {
#define MAX_PARTICLES 3000 #define MAX_PARTICLES 3000
// Life span of a particle (in seconds) // Life span of a particle (in seconds)
#define LIFE_SPAN 8.0f #define LIFE_SPAN 8.f
// A new particle is born every [BIRTH_INTERVAL] second // A new particle is born every [BIRTH_INTERVAL] second
#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) #define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES)
@ -177,13 +183,13 @@ const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = {
#define GRAVITY 9.8f #define GRAVITY 9.8f
// Base initial velocity (m/s) // Base initial velocity (m/s)
#define VELOCITY 8.0f #define VELOCITY 8.f
// Bounce friction (1.0 = no friction, 0.0 = maximum friction) // Bounce friction (1.0 = no friction, 0.0 = maximum friction)
#define FRICTION 0.75f #define FRICTION 0.75f
// "Fountain" height (m) // "Fountain" height (m)
#define FOUNTAIN_HEIGHT 3.0f #define FOUNTAIN_HEIGHT 3.f
// Fountain radius (m) // Fountain radius (m)
#define FOUNTAIN_RADIUS 1.6f #define FOUNTAIN_RADIUS 1.6f
@ -223,26 +229,26 @@ static float glow_pos[4];
// Object material and fog configuration constants // Object material and fog configuration constants
//======================================================================== //========================================================================
const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f}; const GLfloat fountain_diffuse[4] = { 0.7f, 1.f, 1.f, 1.f };
const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f}; const GLfloat fountain_specular[4] = { 1.f, 1.f, 1.f, 1.f };
const GLfloat fountain_shininess = 12.0f; const GLfloat fountain_shininess = 12.f;
const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f}; const GLfloat floor_diffuse[4] = { 1.f, 0.6f, 0.6f, 1.f };
const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f}; const GLfloat floor_specular[4] = { 0.6f, 0.6f, 0.6f, 1.f };
const GLfloat floor_shininess = 18.0f; const GLfloat floor_shininess = 18.f;
const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; const GLfloat fog_color[4] = { 0.1f, 0.1f, 0.1f, 1.f };
//======================================================================== //========================================================================
// InitParticle() - Initialize a new particle // Initialize a new particle
//======================================================================== //========================================================================
void InitParticle( PARTICLE *p, double t ) static void init_particle(PARTICLE *p, double t)
{ {
float xy_angle, velocity; float xy_angle, velocity;
// Start position of particle is at the fountain blow-out // Start position of particle is at the fountain blow-out
p->x = 0.0f; p->x = 0.f;
p->y = 0.0f; p->y = 0.f;
p->z = FOUNTAIN_HEIGHT; p->z = FOUNTAIN_HEIGHT;
// Start velocity is up (Z)... // Start velocity is up (Z)...
@ -267,44 +273,42 @@ void InitParticle( PARTICLE *p, double t )
// Store settings for fountain glow lighting // Store settings for fountain glow lighting
glow_pos[0] = 0.4f * (float) sin(1.34 * t); glow_pos[0] = 0.4f * (float) sin(1.34 * t);
glow_pos[1] = 0.4f * (float) sin(3.11 * t); glow_pos[1] = 0.4f * (float) sin(3.11 * t);
glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f; glow_pos[2] = FOUNTAIN_HEIGHT + 1.f;
glow_pos[3] = 1.0f; glow_pos[3] = 1.f;
glow_color[0] = p->r; glow_color[0] = p->r;
glow_color[1] = p->g; glow_color[1] = p->g;
glow_color[2] = p->b; glow_color[2] = p->b;
glow_color[3] = 1.0f; glow_color[3] = 1.f;
// The particle is new-born and active // The particle is new-born and active
p->life = 1.0f; p->life = 1.f;
p->active = 1; p->active = 1;
} }
//======================================================================== //========================================================================
// UpdateParticle() - Update a particle // Update a particle
//======================================================================== //========================================================================
#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) #define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2)
void UpdateParticle( PARTICLE *p, float dt ) static void update_particle(PARTICLE *p, float dt)
{ {
// If the particle is not active, we need not do anything // If the particle is not active, we need not do anything
if (!p->active) if (!p->active)
{
return; return;
}
// The particle is getting older... // The particle is getting older...
p->life = p->life - dt * (1.0f / LIFE_SPAN); p->life -= dt * (1.f / LIFE_SPAN);
// Did the particle die? // Did the particle die?
if( p->life <= 0.0f ) if (p->life <= 0.f)
{ {
p->active = 0; p->active = 0;
return; return;
} }
// Update particle velocity (apply gravity) // Apply gravity
p->vz = p->vz - GRAVITY * dt; p->vz = p->vz - GRAVITY * dt;
// Update particle position // Update particle position
@ -313,7 +317,7 @@ void UpdateParticle( PARTICLE *p, float dt )
p->z = p->z + p->vz * dt; p->z = p->z + p->vz * dt;
// Simple collision detection + response // Simple collision detection + response
if( p->vz < 0.0f ) if (p->vz < 0.f)
{ {
// Particles should bounce on the fountain (with friction) // Particles should bounce on the fountain (with friction)
if ((p->x * p->x + p->y * p->y) < FOUNTAIN_R2 && if ((p->x * p->x + p->y * p->y) < FOUNTAIN_R2 &&
@ -332,35 +336,28 @@ void UpdateParticle( PARTICLE *p, float dt )
p->z = PARTICLE_SIZE / 2 + p->z = PARTICLE_SIZE / 2 +
FRICTION * (PARTICLE_SIZE / 2 - p->z); FRICTION * (PARTICLE_SIZE / 2 - p->z);
} }
} }
} }
//======================================================================== //========================================================================
// ParticleEngine() - The main frame for the particle engine. Called once // The main frame for the particle engine. Called once per frame.
// per frame.
//======================================================================== //========================================================================
void ParticleEngine( double t, float dt ) static void particle_engine(double t, float dt)
{ {
int i; int i;
float dt2; float dt2;
// Update particles (iterated several times per frame if dt is too // Update particles (iterated several times per frame if dt is too large)
// large) while (dt > 0.f)
while( dt > 0.0f )
{ {
// Calculate delta time for this iteration // Calculate delta time for this iteration
dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T;
// Update particles
for (i = 0; i < MAX_PARTICLES; i++) for (i = 0; i < MAX_PARTICLES; i++)
{ update_particle(&particles[i], dt2);
UpdateParticle( &particles[ i ], dt2 );
}
// Increase minimum age
min_age += dt2; min_age += dt2;
// Should we create any new particle(s)? // Should we create any new particle(s)?
@ -373,21 +370,20 @@ void ParticleEngine( double t, float dt )
{ {
if (!particles[i].active) if (!particles[i].active)
{ {
InitParticle( &particles[ i ], t + min_age ); init_particle(&particles[i], t + min_age);
UpdateParticle( &particles[ i ], min_age ); update_particle(&particles[i], min_age);
break; break;
} }
} }
} }
// Decrease frame delta time
dt -= dt2; dt -= dt2;
} }
} }
//======================================================================== //========================================================================
// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex // Draw all active particles. We use OpenGL 1.1 vertex
// arrays for this in order to accelerate the drawing. // arrays for this in order to accelerate the drawing.
//======================================================================== //========================================================================
@ -396,13 +392,14 @@ void ParticleEngine( double t, float dt )
// the L1 data cache on most CPUs) // the L1 data cache on most CPUs)
#define PARTICLE_VERTS 4 // Number of vertices per particle #define PARTICLE_VERTS 4 // Number of vertices per particle
void DrawParticles( double t, float dt ) static void draw_particles(double t, float dt)
{ {
int i, particle_count; int i, particle_count;
VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr; Vertex vertex_array[BATCH_PARTICLES * PARTICLE_VERTS];
Vertex* vptr;
float alpha; float alpha;
GLuint rgba; GLuint rgba;
VEC quad_lower_left, quad_lower_right; Vec3 quad_lower_left, quad_lower_right;
GLfloat mat[16]; GLfloat mat[16];
PARTICLE* pptr; PARTICLE* pptr;
@ -437,7 +434,6 @@ void DrawParticles( double t, float dt )
// Don't update z-buffer, since all particles are transparent! // Don't update z-buffer, since all particles are transparent!
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
// Enable blending
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
@ -464,8 +460,7 @@ void DrawParticles( double t, float dt )
while (running && thread_sync.p_frame <= thread_sync.d_frame) while (running && thread_sync.p_frame <= thread_sync.d_frame)
{ {
struct timespec ts = { 0, 100000000 }; struct timespec ts = { 0, 100000000 };
cnd_timedwait( &thread_sync.p_done, &thread_sync.particles_lock, cnd_timedwait(&thread_sync.p_done, &thread_sync.particles_lock, &ts);
&ts );
} }
// Store the frame time and delta time for the physics thread // Store the frame time and delta time for the physics thread
@ -478,39 +473,38 @@ void DrawParticles( double t, float dt )
else else
{ {
// Perform particle physics in this thread // Perform particle physics in this thread
ParticleEngine( t, dt ); particle_engine(t, dt);
} }
// Loop through all particles and build vertex arrays. // Loop through all particles and build vertex arrays.
particle_count = 0; particle_count = 0;
vptr = vertex_array; vptr = vertex_array;
pptr = particles; pptr = particles;
for (i = 0; i < MAX_PARTICLES; i++) for (i = 0; i < MAX_PARTICLES; i++)
{ {
if (pptr->active) if (pptr->active)
{ {
// Calculate particle intensity (we set it to max during 75% // Calculate particle intensity (we set it to max during 75%
// of its life, then it fades out) // of its life, then it fades out)
alpha = 4.0f * pptr->life; alpha = 4.f * pptr->life;
if( alpha > 1.0f ) if (alpha > 1.f)
{ alpha = 1.f;
alpha = 1.0f;
}
// Convert color from float to 8-bit (store it in a 32-bit // Convert color from float to 8-bit (store it in a 32-bit
// integer using endian independent type casting) // integer using endian independent type casting)
((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f); ((GLubyte*) &rgba)[0] = (GLubyte)(pptr->r * 255.f);
((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f); ((GLubyte*) &rgba)[1] = (GLubyte)(pptr->g * 255.f);
((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f); ((GLubyte*) &rgba)[2] = (GLubyte)(pptr->b * 255.f);
((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f); ((GLubyte*) &rgba)[3] = (GLubyte)(alpha * 255.f);
// 3) Translate the quad to the correct position in modelview // 3) Translate the quad to the correct position in modelview
// space and store its parameters in vertex arrays (we also // space and store its parameters in vertex arrays (we also
// store texture coord and color information for each vertex). // store texture coord and color information for each vertex).
// Lower left corner // Lower left corner
vptr->s = 0.0f; vptr->s = 0.f;
vptr->t = 0.0f; vptr->t = 0.f;
vptr->rgba = rgba; vptr->rgba = rgba;
vptr->x = pptr->x + quad_lower_left.x; vptr->x = pptr->x + quad_lower_left.x;
vptr->y = pptr->y + quad_lower_left.y; vptr->y = pptr->y + quad_lower_left.y;
@ -518,8 +512,8 @@ void DrawParticles( double t, float dt )
vptr ++; vptr ++;
// Lower right corner // Lower right corner
vptr->s = 1.0f; vptr->s = 1.f;
vptr->t = 0.0f; vptr->t = 0.f;
vptr->rgba = rgba; vptr->rgba = rgba;
vptr->x = pptr->x + quad_lower_right.x; vptr->x = pptr->x + quad_lower_right.x;
vptr->y = pptr->y + quad_lower_right.y; vptr->y = pptr->y + quad_lower_right.y;
@ -527,8 +521,8 @@ void DrawParticles( double t, float dt )
vptr ++; vptr ++;
// Upper right corner // Upper right corner
vptr->s = 1.0f; vptr->s = 1.f;
vptr->t = 1.0f; vptr->t = 1.f;
vptr->rgba = rgba; vptr->rgba = rgba;
vptr->x = pptr->x - quad_lower_left.x; vptr->x = pptr->x - quad_lower_left.x;
vptr->y = pptr->y - quad_lower_left.y; vptr->y = pptr->y - quad_lower_left.y;
@ -536,8 +530,8 @@ void DrawParticles( double t, float dt )
vptr ++; vptr ++;
// Upper left corner // Upper left corner
vptr->s = 0.0f; vptr->s = 0.f;
vptr->t = 1.0f; vptr->t = 1.f;
vptr->rgba = rgba; vptr->rgba = rgba;
vptr->x = pptr->x - quad_lower_right.x; vptr->x = pptr->x - quad_lower_right.x;
vptr->y = pptr->y - quad_lower_right.y; vptr->y = pptr->y - quad_lower_right.y;
@ -581,11 +575,9 @@ void DrawParticles( double t, float dt )
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
// Disable texturing and blending
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND); glDisable(GL_BLEND);
// Allow Z-buffer updates again
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
} }
@ -597,14 +589,16 @@ void DrawParticles( double t, float dt )
#define FOUNTAIN_SIDE_POINTS 14 #define FOUNTAIN_SIDE_POINTS 14
#define FOUNTAIN_SWEEP_STEPS 32 #define FOUNTAIN_SWEEP_STEPS 32
static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = { static const float fountain_side[FOUNTAIN_SIDE_POINTS * 2] =
1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, {
0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f, 1.2f, 0.f, 1.f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f,
1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f, 0.4f, 1.95f, 0.41f, 2.f, 0.8f, 2.2f, 1.2f, 2.4f,
0.5f, 3.0f, 0.0f, 3.0f 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.f, 1.f, 3.f,
0.5f, 3.f, 0.f, 3.f
}; };
static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = { static const float fountain_normal[FOUNTAIN_SIDE_POINTS * 2] =
{
1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f,
1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f,
0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f,
@ -613,10 +607,10 @@ static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = {
//======================================================================== //========================================================================
// DrawFountain() - Draw a fountain // Draw a fountain
//======================================================================== //========================================================================
void DrawFountain( void ) static void draw_fountain(void)
{ {
static GLuint fountain_list = 0; static GLuint fountain_list = 0;
double angle; double angle;
@ -626,11 +620,9 @@ void DrawFountain( void )
// The first time, we build the fountain display list // The first time, we build the fountain display list
if (!fountain_list) if (!fountain_list)
{ {
// Start recording of a new display list
fountain_list = glGenLists(1); fountain_list = glGenLists(1);
glNewList(fountain_list, GL_COMPILE_AND_EXECUTE); glNewList(fountain_list, GL_COMPILE_AND_EXECUTE);
// Set fountain material
glMaterialfv(GL_FRONT, GL_DIFFUSE, fountain_diffuse); glMaterialfv(GL_FRONT, GL_DIFFUSE, fountain_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, fountain_specular); glMaterialfv(GL_FRONT, GL_SPECULAR, fountain_specular);
glMaterialf(GL_FRONT, GL_SHININESS, fountain_shininess); glMaterialf(GL_FRONT, GL_SHININESS, fountain_shininess);
@ -659,35 +651,28 @@ void DrawFountain( void )
y * fountain_side[n * 2], y * fountain_side[n * 2],
fountain_side[n * 2 + 1]); fountain_side[n * 2 + 1]);
} }
glEnd(); glEnd();
} }
// End recording of display list
glEndList(); glEndList();
} }
else else
{
// Playback display list
glCallList(fountain_list); glCallList(fountain_list);
} }
}
//======================================================================== //========================================================================
// TesselateFloor() - Recursive function for building variable tesselated // Recursive function for building variable tesselated floor
// floor
//======================================================================== //========================================================================
void TesselateFloor( float x1, float y1, float x2, float y2, static void tessellate_floor(float x1, float y1, float x2, float y2, int depth)
int recursion )
{ {
float delta, x, y; float delta, x, y;
// Last recursion? // Last recursion?
if( recursion >= 5 ) if (depth >= 5)
{ delta = 999999.f;
delta = 999999.0f;
}
else else
{ {
x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2));
@ -700,36 +685,35 @@ void TesselateFloor( float x1, float y1, float x2, float y2,
{ {
x = (x1 + x2) * 0.5f; x = (x1 + x2) * 0.5f;
y = (y1 + y2) * 0.5f; y = (y1 + y2) * 0.5f;
TesselateFloor( x1,y1, x, y, recursion + 1 ); tessellate_floor(x1, y1, x, y, depth + 1);
TesselateFloor( x,y1, x2, y, recursion + 1 ); tessellate_floor(x, y1, x2, y, depth + 1);
TesselateFloor( x1, y, x,y2, recursion + 1 ); tessellate_floor(x1, y, x, y2, depth + 1);
TesselateFloor( x, y, x2,y2, recursion + 1 ); tessellate_floor(x, y, x2, y2, depth + 1);
} }
else else
{ {
glTexCoord2f( x1*30.0f, y1*30.0f ); glTexCoord2f(x1 * 30.f, y1 * 30.f);
glVertex3f( x1*80.0f, y1*80.0f , 0.0f ); glVertex3f( x1 * 80.f, y1 * 80.f, 0.f);
glTexCoord2f( x2*30.0f, y1*30.0f ); glTexCoord2f(x2 * 30.f, y1 * 30.f);
glVertex3f( x2*80.0f, y1*80.0f , 0.0f ); glVertex3f( x2 * 80.f, y1 * 80.f, 0.f);
glTexCoord2f( x2*30.0f, y2*30.0f ); glTexCoord2f(x2 * 30.f, y2 * 30.f);
glVertex3f( x2*80.0f, y2*80.0f , 0.0f ); glVertex3f( x2 * 80.f, y2 * 80.f, 0.f);
glTexCoord2f( x1*30.0f, y2*30.0f ); glTexCoord2f(x1 * 30.f, y2 * 30.f);
glVertex3f( x1*80.0f, y2*80.0f , 0.0f ); glVertex3f( x1 * 80.f, y2 * 80.f, 0.f);
} }
} }
//======================================================================== //========================================================================
// DrawFloor() - Draw floor. We builde the floor recursively, and let the // Draw floor. We build the floor recursively and let the tessellation in the
// tesselation in the centre (near x,y=0,0) be high, while the selleation // center (near x,y=0,0) be high, while the tessellation around the edges be
// around the edges be low. // low.
//======================================================================== //========================================================================
void DrawFloor( void ) static void draw_floor(void)
{ {
static GLuint floor_list = 0; static GLuint floor_list = 0;
// Select floor texture
if (!wireframe) if (!wireframe)
{ {
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -739,33 +723,27 @@ void DrawFloor( void )
// The first time, we build the floor display list // The first time, we build the floor display list
if (!floor_list) if (!floor_list)
{ {
// Start recording of a new display list
floor_list = glGenLists(1); floor_list = glGenLists(1);
glNewList(floor_list, GL_COMPILE_AND_EXECUTE); glNewList(floor_list, GL_COMPILE_AND_EXECUTE);
// Set floor material
glMaterialfv(GL_FRONT, GL_DIFFUSE, floor_diffuse); glMaterialfv(GL_FRONT, GL_DIFFUSE, floor_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, floor_specular); glMaterialfv(GL_FRONT, GL_SPECULAR, floor_specular);
glMaterialf(GL_FRONT, GL_SHININESS, floor_shininess); glMaterialf(GL_FRONT, GL_SHININESS, floor_shininess);
// Draw floor as a bunch of triangle strips (high tesselation // Draw floor as a bunch of triangle strips (high tesselation
// improves lighting) // improves lighting)
glNormal3f( 0.0f, 0.0f, 1.0f ); glNormal3f(0.f, 0.f, 1.f);
glBegin(GL_QUADS); glBegin(GL_QUADS);
TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 ); tessellate_floor(-1.f, -1.f, 0.f, 0.f, 0);
TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 ); tessellate_floor( 0.f, -1.f, 1.f, 0.f, 0);
TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 ); tessellate_floor( 0.f, 0.f, 1.f, 1.f, 0);
TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 ); tessellate_floor(-1.f, 0.f, 0.f, 1.f, 0);
glEnd(); glEnd();
// End recording of display list
glEndList(); glEndList();
} }
else else
{
// Playback display list
glCallList(floor_list); glCallList(floor_list);
}
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
@ -773,27 +751,26 @@ void DrawFloor( void )
//======================================================================== //========================================================================
// SetupLights() - Position and configure light sources // Position and configure light sources
//======================================================================== //========================================================================
void SetupLights( void ) static void setup_lights(void)
{ {
float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; float l1pos[4], l1amb[4], l1dif[4], l1spec[4];
float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; float l2pos[4], l2amb[4], l2dif[4], l2spec[4];
// Set light source 1 parameters // Set light source 1 parameters
l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f; l1pos[0] = 0.f; l1pos[1] = -9.f; l1pos[2] = 8.f; l1pos[3] = 1.f;
l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f; l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.f;
l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f; l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.f;
l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f; l1spec[0] = 1.f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.f;
// Set light source 2 parameters // Set light source 2 parameters
l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f; l2pos[0] = -15.f; l2pos[1] = 12.f; l2pos[2] = 1.5f; l2pos[3] = 1.f;
l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f; l2amb[0] = 0.f; l2amb[1] = 0.f; l2amb[2] = 0.f; l2amb[3] = 1.f;
l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f; l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.f;
l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f; l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.f; l2spec[3] = 0.f;
// Configure light sources in OpenGL
glLightfv(GL_LIGHT1, GL_POSITION, l1pos); glLightfv(GL_LIGHT1, GL_POSITION, l1pos);
glLightfv(GL_LIGHT1, GL_AMBIENT, l1amb); glLightfv(GL_LIGHT1, GL_AMBIENT, l1amb);
glLightfv(GL_LIGHT1, GL_DIFFUSE, l1dif); glLightfv(GL_LIGHT1, GL_DIFFUSE, l1dif);
@ -806,7 +783,6 @@ void SetupLights( void )
glLightfv(GL_LIGHT3, GL_DIFFUSE, glow_color); glLightfv(GL_LIGHT3, GL_DIFFUSE, glow_color);
glLightfv(GL_LIGHT3, GL_SPECULAR, glow_color); glLightfv(GL_LIGHT3, GL_SPECULAR, glow_color);
// Enable light sources
glEnable(GL_LIGHT1); glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2); glEnable(GL_LIGHT2);
glEnable(GL_LIGHT3); glEnable(GL_LIGHT3);
@ -814,10 +790,10 @@ void SetupLights( void )
//======================================================================== //========================================================================
// Draw() - Main rendering function // Main rendering function
//======================================================================== //========================================================================
void Draw( double t ) static void draw_scene(double t)
{ {
double xpos, ypos, zpos, angle_x, angle_y, angle_z; double xpos, ypos, zpos, angle_x, angle_y, angle_z;
static double t_old = 0.0; static double t_old = 0.0;
@ -827,14 +803,11 @@ void Draw( double t )
dt = (float) (t - t_old); dt = (float) (t - t_old);
t_old = t; t_old = t;
// Setup viewport
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
// Clear color and Z-buffer glClearColor(0.1f, 0.1f, 0.1f, 1.f);
glClearColor( 0.1f, 0.1f, 0.1f, 1.0f );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup projection
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
gluPerspective(65.0, (double) width / (double) height, 1.0, 60.0); gluPerspective(65.0, (double) width / (double) height, 1.0, 60.0);
@ -859,39 +832,31 @@ void Draw( double t )
zpos = 4.0 + 2.0 * cos((M_PI / 180.0) * 4.9 * t); zpos = 4.0 + 2.0 * cos((M_PI / 180.0) * 4.9 * t);
glTranslated(-xpos, -ypos, -zpos); glTranslated(-xpos, -ypos, -zpos);
// Enable face culling
glFrontFace(GL_CCW); glFrontFace(GL_CCW);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
// Enable lighting setup_lights();
SetupLights();
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
// Enable fog (dim details far away)
glEnable(GL_FOG); glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_EXP); glFogi(GL_FOG_MODE, GL_EXP);
glFogf(GL_FOG_DENSITY, 0.05f); glFogf(GL_FOG_DENSITY, 0.05f);
glFogfv(GL_FOG_COLOR, fog_color); glFogfv(GL_FOG_COLOR, fog_color);
// Draw floor draw_floor();
DrawFloor();
// Enable Z-buffering
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
// Draw fountain draw_fountain();
DrawFountain();
// Disable fog & lighting
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glDisable(GL_FOG); glDisable(GL_FOG);
// Draw all particles (must be drawn after all solid objects have been // Particles must be drawn after all solid objects have been drawn
// drawn!) draw_particles(t, dt);
DrawParticles( t, dt );
// Z-buffer not needed anymore // Z-buffer not needed anymore
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -899,21 +864,21 @@ void Draw( double t )
//======================================================================== //========================================================================
// Resize() - GLFW window resize callback function // Window resize callback function
//======================================================================== //========================================================================
void Resize( GLFWwindow* window, int x, int y ) static void resize_callback(GLFWwindow* window, int w, int h)
{ {
width = x; width = w;
height = y > 0 ? y : 1; // Prevent division by zero in aspect calc. height = h > 0 ? h : 1; // Prevent division by zero in aspect calc.
} }
//======================================================================== //========================================================================
// Input callback functions // Key callback functions
//======================================================================== //========================================================================
void KeyFun( GLFWwindow* window, int key, int scancode, int action, int mods ) static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
if (action == GLFW_PRESS) if (action == GLFW_PRESS)
{ {
@ -935,32 +900,27 @@ void KeyFun( GLFWwindow* window, int key, int scancode, int action, int mods )
//======================================================================== //========================================================================
// PhysicsThreadFun() - Thread for updating particle physics // Thread for updating particle physics
//======================================================================== //========================================================================
int PhysicsThreadFun( void *arg ) static int physics_thread_main(void* arg)
{ {
while( running ) for (;;)
{ {
// Lock mutex
mtx_lock(&thread_sync.particles_lock); mtx_lock(&thread_sync.particles_lock);
// Wait for particle drawing to be done // Wait for particle drawing to be done
while (running && thread_sync.p_frame > thread_sync.d_frame) while (running && thread_sync.p_frame > thread_sync.d_frame)
{ {
struct timespec ts = { 0, 100000000 }; struct timespec ts = { 0, 100000000 };
cnd_timedwait( &thread_sync.d_done, &thread_sync.particles_lock, cnd_timedwait(&thread_sync.d_done, &thread_sync.particles_lock, &ts);
&ts );
} }
// No longer running?
if (!running) if (!running)
{
break; break;
}
// Update particles // Update particles
ParticleEngine( thread_sync.t, thread_sync.dt ); particle_engine(thread_sync.t, thread_sync.dt);
// Update frame counter // Update frame counter
thread_sync.p_frame++; thread_sync.p_frame++;
@ -975,7 +935,7 @@ int PhysicsThreadFun( void *arg )
//======================================================================== //========================================================================
// main() // main
//======================================================================== //========================================================================
int main(int argc, char** argv) int main(int argc, char** argv)
@ -989,32 +949,27 @@ int main( int argc, char **argv )
multithreading = 1; multithreading = 1;
benchmark = 0; benchmark = 0;
// Check command line arguments
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
{ {
// Use benchmarking? // Use benchmarking?
if (strcmp(argv[i], "-b") == 0) if (strcmp(argv[i], "-b") == 0)
{
benchmark = 1; benchmark = 1;
}
// Force multithreading off? // Force multithreading off?
else if (strcmp(argv[i], "-s") == 0) else if (strcmp(argv[i], "-s") == 0)
{
multithreading = 0; multithreading = 0;
}
// With a Finder launch on Mac OS X we get a bogus -psn_0_46268417 // With a Finder launch on Mac OS X we get a bogus -psn_0_46268417
// kind of argument (actual numbers vary). Ignore it. // kind of argument (actual numbers vary). Ignore it.
else if( strncmp( argv[i], "-psn_", 5) == 0 ); else if (strncmp(argv[i], "-psn_", 5) == 0)
;
// Usage // Usage
else else
{ {
if (strcmp(argv[i], "-?") != 0) if (strcmp(argv[i], "-?") != 0)
{
printf("Unknonwn option %s\n\n", argv[i]); printf("Unknonwn option %s\n\n", argv[i]);
}
printf("Usage: %s [options]\n", argv[0]); printf("Usage: %s [options]\n", argv[0]);
printf("\n"); printf("\n");
printf("Options:\n"); printf("Options:\n");
@ -1025,18 +980,16 @@ int main( int argc, char **argv )
printf("Program runtime controls:\n"); printf("Program runtime controls:\n");
printf(" w Toggle wireframe mode\n"); printf(" w Toggle wireframe mode\n");
printf(" ESC Exit program\n"); printf(" ESC Exit program\n");
exit( 0 ); exit(EXIT_FAILURE);
} }
} }
// Initialize GLFW
if (!glfwInit()) if (!glfwInit())
{ {
fprintf(stderr, "Failed to initialize GLFW\n"); fprintf(stderr, "Failed to initialize GLFW\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Open OpenGL fullscreen window
window = glfwCreateWindow(WIDTH, HEIGHT, "Particle Engine", window = glfwCreateWindow(WIDTH, HEIGHT, "Particle Engine",
glfwGetPrimaryMonitor(), NULL); glfwGetPrimaryMonitor(), NULL);
if (!window) if (!window)
@ -1051,11 +1004,8 @@ int main( int argc, char **argv )
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSwapInterval(0); glfwSwapInterval(0);
// Window resize callback function glfwSetWindowSizeCallback(window, resize_callback);
glfwSetWindowSizeCallback( window, Resize ); glfwSetKeyCallback(window, key_callback);
// Set keyboard input callback function
glfwSetKeyCallback( window, KeyFun );
// Upload particle texture // Upload particle texture
glGenTextures(1, &particle_tex_id); glGenTextures(1, &particle_tex_id);
@ -1079,7 +1029,6 @@ int main( int argc, char **argv )
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture); 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture);
// Check if we have GL_EXT_separate_specular_color, and if so use it
if (glfwExtensionSupported("GL_EXT_separate_specular_color")) if (glfwExtensionSupported("GL_EXT_separate_specular_color"))
{ {
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT,
@ -1092,19 +1041,16 @@ int main( int argc, char **argv )
// Clear particle system // Clear particle system
for (i = 0; i < MAX_PARTICLES; i++) for (i = 0; i < MAX_PARTICLES; i++)
{
particles[i].active = 0; particles[i].active = 0;
}
min_age = 0.0f;
// Set "running" flag min_age = 0.f;
running = 1; running = 1;
// Set initial times // Set initial times
thread_sync.t = 0.0; thread_sync.t = 0.0;
thread_sync.dt = 0.001f; thread_sync.dt = 0.001f;
// Init threading
if (multithreading) if (multithreading)
{ {
thread_sync.p_frame = 0; thread_sync.p_frame = 0;
@ -1113,56 +1059,46 @@ int main( int argc, char **argv )
cnd_init(&thread_sync.p_done); cnd_init(&thread_sync.p_done);
cnd_init(&thread_sync.d_done); cnd_init(&thread_sync.d_done);
if (thrd_create( &physics_thread, PhysicsThreadFun, NULL ) != thrd_success) if (thrd_create(&physics_thread, physics_thread_main, NULL) != thrd_success)
{ {
glfwTerminate(); glfwTerminate();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
// Main loop
t0 = glfwGetTime(); t0 = glfwGetTime();
frames = 0; frames = 0;
while (running) while (running)
{ {
// Get frame time // Get frame time
t = glfwGetTime() - t0; t = glfwGetTime() - t0;
// Draw... draw_scene(t);
Draw( t );
// Swap buffers
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
// Check if window was closed
running = running && !glfwWindowShouldClose(window); running = running && !glfwWindowShouldClose(window);
// Increase frame count
frames++; frames++;
// End of benchmark? // End of benchmark?
if (benchmark && t >= 60.0) if (benchmark && t >= 60.0)
{
running = 0; running = 0;
} }
}
t = glfwGetTime() - t0; t = glfwGetTime() - t0;
// Wait for particle physics thread to die // Wait for particle physics thread to die
if (multithreading) if (multithreading)
{
thrd_join(physics_thread, NULL); thrd_join(physics_thread, NULL);
}
// Display profiling information // Display profiling information
printf( "%d frames in %.2f seconds = %.1f FPS", frames, t, printf("%d frames in %.2f seconds = %.1f FPS", frames, t, (double) frames / t);
(double)frames / t );
printf(" (multithreading %s)\n", multithreading ? "on" : "off"); printf(" (multithreading %s)\n", multithreading ? "on" : "off");
glfwDestroyWindow(window); glfwDestroyWindow(window);
// Terminate OpenGL
glfwTerminate(); glfwTerminate();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);