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