aboutsummaryrefslogtreecommitdiff
path: root/tests/glfw/particles.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/glfw/particles.c')
-rw-r--r--tests/glfw/particles.c1166
1 files changed, 0 insertions, 1166 deletions
diff --git a/tests/glfw/particles.c b/tests/glfw/particles.c
deleted file mode 100644
index 15c133a0..00000000
--- a/tests/glfw/particles.c
+++ /dev/null
@@ -1,1166 +0,0 @@
-//========================================================================
-// This is a simple, but cool particle engine (buzz-word meaning many
-// small objects that are treated as points and drawn as textures
-// projected on simple geometry).
-//
-// This demonstration generates a colorful fountain-like animation. It
-// uses several advanced OpenGL teqhniques:
-//
-// 1) Lighting (per vertex)
-// 2) Alpha blending
-// 3) Fog
-// 4) Texturing
-// 5) Display lists (for drawing the static environment geometry)
-// 6) Vertex arrays (for drawing the particles)
-// 7) GL_EXT_separate_specular_color is used (if available)
-//
-// Even more so, this program uses multi threading. The program is
-// essentialy divided into a main rendering thread and a particle physics
-// calculation thread. My benchmarks under Windows 2000 on a single
-// processor system show that running this program as two threads instead
-// of a single thread means no difference (there may be a very marginal
-// advantage for the multi threaded case). On dual processor systems I
-// have had reports of 5-25% of speed increase when running this program
-// as two threads instead of one thread.
-//
-// The default behaviour of this program is to use two threads. To force
-// a single thread to be used, use the command line switch -s.
-//
-// To run a fixed length benchmark (60 s), use the command line switch -b.
-//
-// Benchmark results (640x480x16, best of three tests):
-//
-// CPU GFX 1 thread 2 threads
-// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS
-// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS
-//
-// One more thing: Press 'w' during the demo to toggle wireframe mode.
-//========================================================================
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <GL/glfw.h>
-
-#ifdef EMSCRIPTEN
-#include <emscripten/emscripten.h>
-#endif
-
-// Define tokens for GL_EXT_separate_specular_color if not already defined
-#ifndef GL_EXT_separate_specular_color
-#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
-#define GL_SINGLE_COLOR_EXT 0x81F9
-#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
-#endif // GL_EXT_separate_specular_color
-
-// Some <math.h>'s do not define M_PI
-#ifndef M_PI
-#define M_PI 3.141592654
-#endif
-
-// Desired fullscreen resolution
-#define WIDTH 640
-#define HEIGHT 480
-
-
-//========================================================================
-// Type definitions
-//========================================================================
-
-typedef struct { float x,y,z; } VEC;
-
-// 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 {
- GLfloat s, t; // Texture coordinates
- GLuint rgba; // Color (four ubytes packed into an uint)
- GLfloat x, y, z; // Vertex coordinates
-} VERTEX;
-
-
-//========================================================================
-// Program control global variables
-//========================================================================
-
-// "Running" flag (true if program shall continue to run)
-int running;
-
-// Window dimensions
-int width, height;
-
-// "wireframe" flag (true if we use wireframe view)
-int wireframe;
-
-// "multithreading" flag (true if we use multithreading)
-int multithreading;
-
-// Thread synchronization
-struct {
- double t; // Time (s)
- float dt; // Time since last frame (s)
- int p_frame; // Particle physics frame number
- int d_frame; // Particle draw frame number
- GLFWcond p_done; // Condition: particle physics done
- GLFWcond d_done; // Condition: particle draw done
- GLFWmutex particles_lock; // Particles data sharing mutex
-} thread_sync;
-
-
-//========================================================================
-// Texture declarations (we hard-code them into the source code, since
-// they are so simple)
-//========================================================================
-
-#define P_TEX_WIDTH 8 // Particle texture dimensions
-#define P_TEX_HEIGHT 8
-#define F_TEX_WIDTH 16 // Floor texture dimensions
-#define F_TEX_HEIGHT 16
-
-// Texture object IDs
-GLuint particle_tex_id, floor_tex_id;
-
-// Particle texture (a simple spot)
-const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00,
- 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00,
- 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00,
- 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00,
- 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00,
- 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-// Floor texture (your basic checkered floor)
-const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = {
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30,
- 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0,
- 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0,
- 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-};
-
-
-//========================================================================
-// These are fixed constants that control the particle engine. In a
-// modular world, these values should be variables...
-//========================================================================
-
-// Maximum number of particles
-#define MAX_PARTICLES 3000
-
-// Life span of a particle (in seconds)
-#define LIFE_SPAN 8.0f
-
-// A new particle is born every [BIRTH_INTERVAL] second
-#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES)
-
-// Particle size (meters)
-#define PARTICLE_SIZE 0.7f
-
-// Gravitational constant (m/s^2)
-#define GRAVITY 9.8f
-
-// Base initial velocity (m/s)
-#define VELOCITY 8.0f
-
-// Bounce friction (1.0 = no friction, 0.0 = maximum friction)
-#define FRICTION 0.75f
-
-// "Fountain" height (m)
-#define FOUNTAIN_HEIGHT 3.0f
-
-// Fountain radius (m)
-#define FOUNTAIN_RADIUS 1.6f
-
-// Minimum delta-time for particle phisics (s)
-#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f)
-
-
-//========================================================================
-// Particle system global variables
-//========================================================================
-
-// This structure holds all state for a single particle
-typedef struct {
- float x,y,z; // Position in space
- float vx,vy,vz; // Velocity vector
- float r,g,b; // Color of particle
- float life; // Life of particle (1.0 = newborn, < 0.0 = dead)
- int active; // Tells if this particle is active
-} PARTICLE;
-
-// Global vectors holding all particles. We use two vectors for double
-// buffering.
-static PARTICLE particles[ MAX_PARTICLES ];
-
-// Global variable holding the age of the youngest particle
-static float min_age;
-
-// Color of latest born particle (used for fountain lighting)
-static float glow_color[4];
-
-// Position of latest born particle (used for fountain lighting)
-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};
-
-
-//========================================================================
-// InitParticle() - Initialize a new particle
-//========================================================================
-
-void InitParticle( 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->z = FOUNTAIN_HEIGHT;
-
- // Start velocity is up (Z)...
- p->vz = 0.7f + (0.3f/4096.f) * (float) (rand() & 4095);
-
- // ...and a randomly chosen X/Y direction
- xy_angle = (2.f * (float)M_PI / 4096.f) * (float) (rand() & 4095);
- p->vx = 0.4f * (float) cos( xy_angle );
- p->vy = 0.4f * (float) sin( xy_angle );
-
- // Scale velocity vector according to a time-varying velocity
- velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t )));
- p->vx *= velocity;
- p->vy *= velocity;
- p->vz *= velocity;
-
- // Color is time-varying
- p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 );
- p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 );
- p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 );
-
- // 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_color[0] = p->r;
- glow_color[1] = p->g;
- glow_color[2] = p->b;
- glow_color[3] = 1.0f;
-
- // The particle is new-born and active
- p->life = 1.0f;
- p->active = 1;
-}
-
-
-//========================================================================
-// UpdateParticle() - Update a particle
-//========================================================================
-
-#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2)
-
-void UpdateParticle( 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);
-
- // Did the particle die?
- if( p->life <= 0.0f )
- {
- p->active = 0;
- return;
- }
-
- // Update particle velocity (apply gravity)
- p->vz = p->vz - GRAVITY * dt;
-
- // Update particle position
- p->x = p->x + p->vx * dt;
- p->y = p->y + p->vy * dt;
- p->z = p->z + p->vz * dt;
-
- // Simple collision detection + response
- if( p->vz < 0.0f )
- {
- // Particles should bounce on the fountain (with friction)
- if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 &&
- p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) )
- {
- p->vz = -FRICTION * p->vz;
- p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 +
- FRICTION * (FOUNTAIN_HEIGHT +
- PARTICLE_SIZE/2 - p->z);
- }
-
- // Particles should bounce on the floor (with friction)
- else if( p->z < PARTICLE_SIZE/2 )
- {
- p->vz = -FRICTION * p->vz;
- p->z = PARTICLE_SIZE/2 +
- FRICTION * (PARTICLE_SIZE/2 - p->z);
- }
-
- }
-}
-
-
-//========================================================================
-// ParticleEngine() - The main frame for the particle engine. Called once
-// per frame.
-//========================================================================
-
-void ParticleEngine( double t, float dt )
-{
- int i;
- float dt2;
-
- // Update particles (iterated several times per frame if dt is too
- // large)
- while( dt > 0.0f )
- {
- // 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 );
- }
-
- // Increase minimum age
- min_age += dt2;
-
- // Should we create any new particle(s)?
- while( min_age >= BIRTH_INTERVAL )
- {
- min_age -= BIRTH_INTERVAL;
-
- // Find a dead particle to replace with a new one
- for( i = 0; i < MAX_PARTICLES; i ++ )
- {
- if( !particles[ i ].active )
- {
- InitParticle( &particles[ i ], t + min_age );
- UpdateParticle( &particles[ i ], min_age );
- break;
- }
- }
- }
-
- // Decrease frame delta time
- dt -= dt2;
- }
-}
-
-
-//========================================================================
-// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex
-// arrays for this in order to accelerate the drawing.
-//========================================================================
-
-#define BATCH_PARTICLES 70 // Number of particles to draw in each batch
- // (70 corresponds to 7.5 KB = will not blow
- // the L1 data cache on most CPUs)
-#define PARTICLE_VERTS 4 // Number of vertices per particle
-
-void DrawParticles( double t, float dt )
-{
- int i, particle_count;
- VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr;
- float alpha;
- GLuint rgba;
- VEC quad_lower_left, quad_lower_right;
- GLfloat mat[ 16 ];
- PARTICLE *pptr;
-
- // Here comes the real trick with flat single primitive objects (s.c.
- // "billboards"): We must rotate the textured primitive so that it
- // always faces the viewer (is coplanar with the view-plane).
- // We:
- // 1) Create the primitive around origo (0,0,0)
- // 2) Rotate it so that it is coplanar with the view plane
- // 3) Translate it according to the particle position
- // Note that 1) and 2) is the same for all particles (done only once).
-
- // Get modelview matrix. We will only use the upper left 3x3 part of
- // the matrix, which represents the rotation.
- glGetFloatv( GL_MODELVIEW_MATRIX, mat );
-
- // 1) & 2) We do it in one swift step:
- // Although not obvious, the following six lines represent two matrix/
- // vector multiplications. The matrix is the inverse 3x3 rotation
- // matrix (i.e. the transpose of the same matrix), and the two vectors
- // represent the lower left corner of the quad, PARTICLE_SIZE/2 *
- // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
- // The upper left/right corners of the quad is always the negative of
- // the opposite corners (regardless of rotation).
- quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]);
- quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]);
- quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]);
- quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]);
- quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]);
- quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]);
-
- // Don't update z-buffer, since all particles are transparent!
- glDepthMask( GL_FALSE );
-
- // Enable blending
- glEnable( GL_BLEND );
- glBlendFunc( GL_SRC_ALPHA, GL_ONE );
-
- // Select particle texture
- if( !wireframe )
- {
- glEnable( GL_TEXTURE_2D );
- glBindTexture( GL_TEXTURE_2D, particle_tex_id );
- }
-
- // Set up vertex arrays. We use interleaved arrays, which is easier to
- // handle (in most situations) and it gives a linear memeory access
- // access pattern (which may give better performance in some
- // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords,
- // 4 ubytes for color and 3 floats for vertex coord (in that order).
- // Most OpenGL cards / drivers are optimized for this format.
- glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array );
-
- // Is particle physics carried out in a separate thread?
- if( multithreading )
- {
- // Wait for particle physics thread to be done
- glfwLockMutex( thread_sync.particles_lock );
- while( running && thread_sync.p_frame <= thread_sync.d_frame )
- {
- glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock,
- 0.1 );
- }
-
- // Store the frame time and delta time for the physics thread
- thread_sync.t = t;
- thread_sync.dt = dt;
-
- // Update frame counter
- thread_sync.d_frame ++;
- }
- else
- {
- // Perform particle physics in this thread
- ParticleEngine( 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;
- }
-
- // 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);
-
- // 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->rgba = rgba;
- vptr->x = pptr->x + quad_lower_left.x;
- vptr->y = pptr->y + quad_lower_left.y;
- vptr->z = pptr->z + quad_lower_left.z;
- vptr ++;
-
- // Lower right corner
- vptr->s = 1.0f;
- vptr->t = 0.0f;
- vptr->rgba = rgba;
- vptr->x = pptr->x + quad_lower_right.x;
- vptr->y = pptr->y + quad_lower_right.y;
- vptr->z = pptr->z + quad_lower_right.z;
- vptr ++;
-
- // Upper right corner
- vptr->s = 1.0f;
- vptr->t = 1.0f;
- vptr->rgba = rgba;
- vptr->x = pptr->x - quad_lower_left.x;
- vptr->y = pptr->y - quad_lower_left.y;
- vptr->z = pptr->z - quad_lower_left.z;
- vptr ++;
-
- // Upper left corner
- vptr->s = 0.0f;
- vptr->t = 1.0f;
- vptr->rgba = rgba;
- vptr->x = pptr->x - quad_lower_right.x;
- vptr->y = pptr->y - quad_lower_right.y;
- vptr->z = pptr->z - quad_lower_right.z;
- vptr ++;
-
- // Increase count of drawable particles
- particle_count ++;
- }
-
- // If we have filled up one batch of particles, draw it as a set
- // of quads using glDrawArrays.
- if( particle_count >= BATCH_PARTICLES )
- {
- // The first argument tells which primitive type we use (QUAD)
- // The second argument tells the index of the first vertex (0)
- // The last argument is the vertex count
- glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );
- particle_count = 0;
- vptr = vertex_array;
- }
-
- // Next particle
- pptr ++;
- }
-
- // We are done with the particle data: Unlock mutex and signal physics
- // thread
- if( multithreading )
- {
- glfwUnlockMutex( thread_sync.particles_lock );
- glfwSignalCond( thread_sync.d_done );
- }
-
- // Draw final batch of particles (if any)
- glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );
-
- // Disable vertex arrays (Note: glInterleavedArrays implicitly called
- // glEnableClientState for vertex, texture coord and color arrays)
- glDisableClientState( GL_VERTEX_ARRAY );
- 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 );
-}
-
-
-//========================================================================
-// Fountain geometry specification
-//========================================================================
-
-#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_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,
- 0.0000f,1.00000f, 0.0000f,1.00000f
-};
-
-
-//========================================================================
-// DrawFountain() - Draw a fountain
-//========================================================================
-
-void DrawFountain( void )
-{
- static GLuint fountain_list = 0;
- double angle;
- float x, y;
- int m, n;
-
- // 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 );
-
- // Build fountain using triangle strips
- for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ )
- {
- glBegin( GL_TRIANGLE_STRIP );
- for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ )
- {
- angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS);
- x = (float) cos( angle );
- y = (float) sin( angle );
-
- // Draw triangle strip
- glNormal3f( x * fountain_normal[ n*2+2 ],
- y * fountain_normal[ n*2+2 ],
- fountain_normal[ n*2+3 ] );
- glVertex3f( x * fountain_side[ n*2+2 ],
- y * fountain_side[ n*2+2 ],
- fountain_side[ n*2+3 ] );
- glNormal3f( x * fountain_normal[ n*2 ],
- y * fountain_normal[ n*2 ],
- fountain_normal[ n*2+1 ] );
- glVertex3f( x * fountain_side[ n*2 ],
- 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
-//========================================================================
-
-void TesselateFloor( float x1, float y1, float x2, float y2,
- int recursion )
-{
- float delta, x, y;
-
- // Last recursion?
- if( recursion >= 5 )
- {
- delta = 999999.0f;
- }
- else
- {
- x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2));
- y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2));
- delta = x*x + y*y;
- }
-
- // Recurse further?
- if( delta < 0.1f )
- {
- 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 );
- }
- 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 );
- }
-}
-
-
-//========================================================================
-// 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.
-//========================================================================
-
-void DrawFloor( void )
-{
- static GLuint floor_list = 0;
-
- // Select floor texture
- if( !wireframe )
- {
- glEnable( GL_TEXTURE_2D );
- glBindTexture( GL_TEXTURE_2D, floor_tex_id );
- }
-
- // 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 );
- 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 );
- glEnd();
-
- // End recording of display list
- glEndList();
- }
- else
- {
- // Playback display list
- glCallList( floor_list );
- }
-
- glDisable( GL_TEXTURE_2D );
-
-}
-
-
-//========================================================================
-// SetupLights() - Position and configure light sources
-//========================================================================
-
-void SetupLights( 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;
-
- // 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;
-
- // Configure light sources in OpenGL
- glLightfv( GL_LIGHT1, GL_POSITION, l1pos );
- glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb );
- glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif );
- glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec );
- glLightfv( GL_LIGHT2, GL_POSITION, l2pos );
- glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb );
- glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif );
- glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec );
- glLightfv( GL_LIGHT3, GL_POSITION, glow_pos );
- 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 );
-}
-
-
-//========================================================================
-// Draw() - Main rendering function
-//========================================================================
-
-void Draw( double t )
-{
- double xpos, ypos, zpos, angle_x, angle_y, angle_z;
- static double t_old = 0.0;
- float dt;
-
- // Calculate frame-to-frame delta time
- 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 );
- 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 );
-
- // Setup camera
- glMatrixMode( GL_MODELVIEW );
- glLoadIdentity();
-
- // Rotate camera
- angle_x = 90.0 - 10.0;
- angle_y = 10.0 * sin( 0.3 * t );
- angle_z = 10.0 * t;
- glRotated( -angle_x, 1.0, 0.0, 0.0 );
- glRotated( -angle_y, 0.0, 1.0, 0.0 );
- glRotated( -angle_z, 0.0, 0.0, 1.0 );
-
- // Translate camera
- xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) +
- 2.0 * sin( (M_PI/180.0) * 3.1 * t );
- ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) +
- 2.0 * cos( (M_PI/180.0) * 2.9 * 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();
- 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();
-
- // Enable Z-buffering
- glEnable( GL_DEPTH_TEST );
- glDepthFunc( GL_LEQUAL );
- glDepthMask( GL_TRUE );
-
- // Draw fountain
- DrawFountain();
-
- // 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 );
-
- // Z-buffer not needed anymore
- glDisable( GL_DEPTH_TEST );
-}
-
-
-//========================================================================
-// Resize() - GLFW window resize callback function
-//========================================================================
-
-void GLFWCALL Resize( int x, int y )
-{
- width = x;
- height = y > 0 ? y : 1; // Prevent division by zero in aspect calc.
-}
-
-
-//========================================================================
-// Input callback functions
-//========================================================================
-
-void GLFWCALL KeyFun( int key, int action )
-{
- if( action == GLFW_PRESS )
- {
- switch( key )
- {
- case GLFW_KEY_ESC:
- running = 0;
- break;
- case 'W':
- wireframe = !wireframe;
- glPolygonMode( GL_FRONT_AND_BACK,
- wireframe ? GL_LINE : GL_FILL );
- break;
- default:
- break;
- }
- }
-}
-
-
-//========================================================================
-// PhysicsThreadFun() - Thread for updating particle physics
-//========================================================================
-
-void GLFWCALL PhysicsThreadFun( void *arg )
-{
- while( running )
- {
- // Lock mutex
- glfwLockMutex( thread_sync.particles_lock );
-
- // Wait for particle drawing to be done
- while( running && thread_sync.p_frame > thread_sync.d_frame )
- {
- glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock,
- 0.1 );
- }
-
- // No longer running?
- if( !running )
- {
- break;
- }
-
- // Update particles
- ParticleEngine( thread_sync.t, thread_sync.dt );
-
- // Update frame counter
- thread_sync.p_frame ++;
-
- // Unlock mutex and signal drawing thread
- glfwUnlockMutex( thread_sync.particles_lock );
- glfwSignalCond( thread_sync.p_done );
- }
-}
-
-
-//========================================================================
-// main()
-//========================================================================
-
-double t0, t;
-int frames, benchmark;
-void iteration(){
- // Get frame time
- t = glfwGetTime() - t0;
-
- // Draw...
- Draw( t );
-
- // Swap buffers
- glfwSwapBuffers();
-
- // Check if window was closed
- running = running && glfwGetWindowParam( GLFW_OPENED );
-
- // Increase frame count
- frames ++;
-
- // End of benchmark?
- if( benchmark && t >= 60.0 )
- {
- running = 0;
- }
-}
-
-int main( int argc, char **argv )
-{
- int i;
- GLFWthread physics_thread = 0;
-
- // Use multithreading by default, but don't benchmark
- 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 );
-
- // 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" );
- printf( " -b Benchmark (run program for 60 s)\n" );
- printf( " -s Run program as single thread (default is to use two threads)\n" );
- printf( " -? Display this text\n" );
- printf( "\n");
- printf( "Program runtime controls:\n" );
- printf( " w Toggle wireframe mode\n" );
- printf( " ESC Exit program\n" );
- exit( 0 );
- }
- }
<