Pārlūkot izejas kodu

Merge branch 'master' into showwindow

Conflicts:
	src/window.c
Camilla Berglund 13 gadi atpakaļ
vecāks
revīzija
9a183090e0

+ 0 - 1152
examples/particles.c

@@ -1,1152 +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>
-
-// 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()
-//========================================================================
-
-int main( int argc, char **argv )
-{
-    int        i, frames, benchmark;
-    double     t0, t;
-    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 );
-        }
-    }
-
-    // Initialize GLFW
-    if( !glfwInit() )
-    {
-        fprintf( stderr, "Failed to initialize GLFW\n" );
-        exit( EXIT_FAILURE );
-    }
-
-    // Open OpenGL fullscreen window
-    if( !glfwCreateWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) )
-    {
-        fprintf( stderr, "Failed to open GLFW window\n" );
-        glfwTerminate();
-        exit( EXIT_FAILURE );
-    }
-
-    // Set window title
-    glfwSetWindowTitle( "Particle engine" );
-
-    // Disable VSync (we want to get as high FPS as possible!)
-    glfwSwapInterval( 0 );
-
-    // Window resize callback function
-    glfwSetWindowSizeCallback( Resize );
-
-    // Set keyboard input callback function
-    glfwSetKeyCallback( KeyFun );
-
-    // Upload particle texture
-    glGenTextures( 1, &particle_tex_id );
-    glBindTexture( GL_TEXTURE_2D, particle_tex_id );
-    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-    glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT,
-                  0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture );
-
-    // Upload floor texture
-    glGenTextures( 1, &floor_tex_id );
-    glBindTexture( GL_TEXTURE_2D, floor_tex_id );
-    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-    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,
-                       GL_SEPARATE_SPECULAR_COLOR_EXT );
-    }
-
-    // Set filled polygon mode as default (not wireframe)
-    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
-    wireframe = 0;
-
-    // Clear particle system
-    for( i = 0; i < MAX_PARTICLES; i ++ )
-    {
-        particles[ i ].active = 0;
-    }
-    min_age = 0.0f;
-
-    // Set "running" flag
-    running = 1;
-
-    // Set initial times
-    thread_sync.t  = 0.0;
-    thread_sync.dt = 0.001f;
-
-    // Init threading
-    if( multithreading )
-    {
-        thread_sync.p_frame = 0;
-        thread_sync.d_frame = 0;
-        thread_sync.particles_lock = glfwCreateMutex();
-        thread_sync.p_done = glfwCreateCond();
-        thread_sync.d_done = glfwCreateCond();
-        physics_thread = glfwCreateThread( PhysicsThreadFun, NULL );
-    }
-
-    // Main loop
-    t0 = glfwGetTime();
-    frames = 0;
-    while( running )
-    {
-        // 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;
-        }
-    }
-    t = glfwGetTime() - t0;
-
-    // Wait for particle physics thread to die
-    if( multithreading )
-    {
-        glfwWaitThread( physics_thread, GLFW_WAIT );
-    }
-
-    // Display profiling information
-    printf( "%d frames in %.2f seconds = %.1f FPS", frames, t,
-            (double)frames / t );
-    printf( " (multithreading %s)\n", multithreading ? "on" : "off" );
-
-    // Terminate OpenGL
-    glfwTerminate();
-
-    exit( EXIT_SUCCESS );
-}
-

+ 0 - 854
examples/pong3d.c

@@ -1,854 +0,0 @@
-//========================================================================
-// This is a small test application for GLFW.
-// This is an OpenGL port of the famous "PONG" game (the first computer
-// game ever?). It is very simple, and could be improved alot. It was
-// created in order to show off the gaming capabilities of GLFW.
-//========================================================================
-
-#include <GL/glfw.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-
-//========================================================================
-// Constants
-//========================================================================
-
-// Screen resolution
-#define WIDTH        640
-#define HEIGHT       480
-
-// Player size (units)
-#define PLAYER_XSIZE  0.05f
-#define PLAYER_YSIZE  0.15f
-
-// Ball size (units)
-#define BALL_SIZE  0.02f
-
-// Maximum player movement speed (units / second)
-#define MAX_SPEED    1.5f
-
-// Player movement acceleration (units / seconds^2)
-#define ACCELERATION  4.0f
-
-// Player movement deceleration (units / seconds^2)
-#define DECELERATION  2.0f
-
-// Ball movement speed (units / second)
-#define BALL_SPEED    0.4f
-
-// Menu options
-#define MENU_NONE    0
-#define MENU_PLAY    1
-#define MENU_QUIT    2
-
-// Game events
-#define NOBODY_WINS  0
-#define PLAYER1_WINS 1
-#define PLAYER2_WINS 2
-
-// Winner ID
-#define NOBODY       0
-#define PLAYER1      1
-#define PLAYER2      2
-
-// Camera positions
-#define CAMERA_CLASSIC   0
-#define CAMERA_ABOVE     1
-#define CAMERA_SPECTATOR 2
-#define CAMERA_DEFAULT   CAMERA_CLASSIC
-
-
-//========================================================================
-// Textures
-//========================================================================
-
-#define TEX_TITLE    0
-#define TEX_MENU     1
-#define TEX_INSTR    2
-#define TEX_WINNER1  3
-#define TEX_WINNER2  4
-#define TEX_FIELD    5
-#define NUM_TEXTURES 6
-
-// Texture names
-char * tex_name[ NUM_TEXTURES ] = {
-    "pong3d_title.tga",
-    "pong3d_menu.tga",
-    "pong3d_instr.tga",
-    "pong3d_winner1.tga",
-    "pong3d_winner2.tga",
-    "pong3d_field.tga"
-};
-
-// OpenGL texture object IDs
-GLuint tex_id[ NUM_TEXTURES ];
-
-
-//========================================================================
-// Global variables
-//========================================================================
-
-// Display information
-int width, height;
-
-// Frame information
-double thistime, oldtime, dt, starttime;
-
-// Camera information
-int camerapos;
-
-// Player information
-struct {
-    double ypos;     // -1.0 to +1.0
-    double yspeed;   // -MAX_SPEED to +MAX_SPEED
-} player1, player2;
-
-// Ball information
-struct {
-    double xpos, ypos;
-    double xspeed, yspeed;
-} ball;
-
-// And the winner is...
-int winner;
-
-// Lighting configuration
-const GLfloat env_ambient[4]     = {1.0f,1.0f,1.0f,1.0f};
-const GLfloat light1_position[4] = {-3.0f,3.0f,2.0f,1.0f};
-const GLfloat light1_diffuse[4]  = {1.0f,1.0f,1.0f,0.0f};
-const GLfloat light1_ambient[4]  = {0.0f,0.0f,0.0f,0.0f};
-
-// Object material properties
-const GLfloat player1_diffuse[4] = {1.0f,0.3f,0.3f,1.0f};
-const GLfloat player1_ambient[4] = {0.3f,0.1f,0.0f,1.0f};
-const GLfloat player2_diffuse[4] = {0.3f,1.0f,0.3f,1.0f};
-const GLfloat player2_ambient[4] = {0.1f,0.3f,0.1f,1.0f};
-const GLfloat ball_diffuse[4]    = {1.0f,1.0f,0.5f,1.0f};
-const GLfloat ball_ambient[4]    = {0.3f,0.3f,0.1f,1.0f};
-const GLfloat border_diffuse[4]  = {0.3f,0.3f,1.0f,1.0f};
-const GLfloat border_ambient[4]  = {0.1f,0.1f,0.3f,1.0f};
-const GLfloat floor_diffuse[4]   = {1.0f,1.0f,1.0f,1.0f};
-const GLfloat floor_ambient[4]   = {0.3f,0.3f,0.3f,1.0f};
-
-
-//========================================================================
-// LoadTextures() - Load textures from disk and upload to OpenGL card
-//========================================================================
-
-GLboolean LoadTextures( void )
-{
-    int  i;
-
-    // Generate texture objects
-    glGenTextures( NUM_TEXTURES, tex_id );
-
-    // Load textures
-    for( i = 0; i < NUM_TEXTURES; i ++ )
-    {
-        // Select texture object
-        glBindTexture( GL_TEXTURE_2D, tex_id[ i ] );
-
-        // Set texture parameters
-        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
-        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
-        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-
-        // Upload texture from file to texture memory
-        if( !glfwLoadTexture2D( tex_name[ i ], 0 ) )
-        {
-            fprintf( stderr, "Failed to load texture %s\n", tex_name[ i ] );
-            return GL_FALSE;
-        }
-    }
-
-    return GL_TRUE;
-}
-
-
-//========================================================================
-// DrawImage() - Draw a 2D image as a texture
-//========================================================================
-
-void DrawImage( int texnum, float x1, float x2, float y1, float y2 )
-{
-    glEnable( GL_TEXTURE_2D );
-    glBindTexture( GL_TEXTURE_2D, tex_id[ texnum ] );
-    glBegin( GL_QUADS );
-      glTexCoord2f( 0.0f, 1.0f );
-      glVertex2f( x1, y1 );
-      glTexCoord2f( 1.0f, 1.0f );
-      glVertex2f( x2, y1 );
-      glTexCoord2f( 1.0f, 0.0f );
-      glVertex2f( x2, y2 );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex2f( x1, y2 );
-    glEnd();
-    glDisable( GL_TEXTURE_2D );
-}
-
-
-//========================================================================
-// GameMenu() - Game menu (returns menu option)
-//========================================================================
-
-int GameMenu( void )
-{
-    int option;
-
-    // Enable sticky keys
-    glfwEnable( GLFW_STICKY_KEYS );
-
-    // Wait for a game menu key to be pressed
-    do
-    {
-        // Get window size
-        glfwGetWindowSize( &width, &height );
-
-        // Set viewport
-        glViewport( 0, 0, width, height );
-
-        // Clear display
-        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
-        glClear( GL_COLOR_BUFFER_BIT );
-
-        // Setup projection matrix
-        glMatrixMode( GL_PROJECTION );
-        glLoadIdentity();
-        glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f );
-
-        // Setup modelview matrix
-        glMatrixMode( GL_MODELVIEW );
-        glLoadIdentity();
-
-        // Display title
-        glColor3f( 1.0f, 1.0f, 1.0f );
-        DrawImage( TEX_TITLE, 0.1f, 0.9f, 0.0f, 0.3f );
-
-        // Display menu
-        glColor3f( 1.0f, 1.0f, 0.0f );
-        DrawImage( TEX_MENU, 0.38f, 0.62f, 0.35f, 0.5f );
-
-        // Display instructions
-        glColor3f( 0.0f, 1.0f, 1.0f );
-        DrawImage( TEX_INSTR, 0.32f, 0.68f, 0.65f, 0.85f );
-
-        // Swap buffers
-        glfwSwapBuffers();
-
-        // Check for keys
-        if( glfwGetKey( 'Q' ) || !glfwGetWindowParam( GLFW_OPENED ) )
-        {
-            option = MENU_QUIT;
-        }
-        else if( glfwGetKey( GLFW_KEY_F1 ) )
-        {
-            option = MENU_PLAY;
-        }
-        else
-        {
-            option = MENU_NONE;
-        }
-
-        // To avoid horrible busy waiting, sleep for at least 20 ms
-        glfwSleep( 0.02 );
-    }
-    while( option == MENU_NONE );
-
-    // Disable sticky keys
-    glfwDisable( GLFW_STICKY_KEYS );
-
-    return option;
-}
-
-
-//========================================================================
-// NewGame() - Initialize a new game
-//========================================================================
-
-void NewGame( void )
-{
-    // Frame information
-    starttime = thistime = glfwGetTime();
-
-    // Camera information
-    camerapos = CAMERA_DEFAULT;
-
-    // Player 1 information
-    player1.ypos   = 0.0;
-    player1.yspeed = 0.0;
-
-    // Player 2 information
-    player2.ypos   = 0.0;
-    player2.yspeed = 0.0;
-
-    // Ball information
-    ball.xpos = -1.0 + PLAYER_XSIZE;
-    ball.ypos = player1.ypos;
-    ball.xspeed = 1.0;
-    ball.yspeed = 1.0;
-}
-
-
-//========================================================================
-// PlayerControl() - Player control
-//========================================================================
-
-void PlayerControl( void )
-{
-    float joy1pos[ 2 ], joy2pos[ 2 ];
-
-    // Get joystick X & Y axis positions
-    glfwGetJoystickPos( GLFW_JOYSTICK_1, joy1pos, 2 );
-    glfwGetJoystickPos( GLFW_JOYSTICK_2, joy2pos, 2 );
-
-    // Player 1 control
-    if( glfwGetKey( 'A' ) || joy1pos[ 1 ] > 0.2f )
-    {
-        player1.yspeed += dt * ACCELERATION;
-        if( player1.yspeed > MAX_SPEED )
-        {
-            player1.yspeed = MAX_SPEED;
-        }
-    }
-    else if( glfwGetKey( 'Z' ) || joy1pos[ 1 ] < -0.2f )
-    {
-        player1.yspeed -= dt * ACCELERATION;
-        if( player1.yspeed < -MAX_SPEED )
-        {
-            player1.yspeed = -MAX_SPEED;
-        }
-    }
-    else
-    {
-        player1.yspeed /= exp( DECELERATION * dt );
-    }
-
-    // Player 2 control
-    if( glfwGetKey( 'K' ) || joy2pos[ 1 ] > 0.2f )
-    {
-        player2.yspeed += dt * ACCELERATION;
-        if( player2.yspeed > MAX_SPEED )
-        {
-            player2.yspeed = MAX_SPEED;
-        }
-    }
-    else if( glfwGetKey( 'M' ) || joy2pos[ 1 ] < -0.2f )
-    {
-        player2.yspeed -= dt * ACCELERATION;
-        if( player2.yspeed < -MAX_SPEED )
-        {
-            player2.yspeed = -MAX_SPEED;
-        }
-    }
-    else
-    {
-        player2.yspeed /= exp( DECELERATION * dt );
-    }
-
-    // Update player 1 position
-    player1.ypos += dt * player1.yspeed;
-    if( player1.ypos > 1.0 - PLAYER_YSIZE )
-    {
-        player1.ypos = 1.0 - PLAYER_YSIZE;
-        player1.yspeed = 0.0;
-    }
-    else if( player1.ypos < -1.0 + PLAYER_YSIZE )
-    {
-        player1.ypos = -1.0 + PLAYER_YSIZE;
-        player1.yspeed = 0.0;
-    }
-
-    // Update player 2 position
-    player2.ypos += dt * player2.yspeed;
-    if( player2.ypos > 1.0 - PLAYER_YSIZE )
-    {
-        player2.ypos = 1.0 - PLAYER_YSIZE;
-        player2.yspeed = 0.0;
-    }
-    else if( player2.ypos < -1.0 + PLAYER_YSIZE )
-    {
-        player2.ypos = -1.0 + PLAYER_YSIZE;
-        player2.yspeed = 0.0;
-    }
-}
-
-
-//========================================================================
-// BallControl() - Ball control
-//========================================================================
-
-int BallControl( void )
-{
-    int event;
-    double ballspeed;
-
-    // Calculate new ball speed
-    ballspeed = BALL_SPEED * (1.0 + 0.02*(thistime-starttime));
-    ball.xspeed = ball.xspeed > 0 ? ballspeed : -ballspeed;
-    ball.yspeed = ball.yspeed > 0 ? ballspeed : -ballspeed;
-    ball.yspeed *= 0.74321;
-
-    // Update ball position
-    ball.xpos += dt * ball.xspeed;
-    ball.ypos += dt * ball.yspeed;
-
-    // Did the ball hit a top/bottom wall?
-    if( ball.ypos >= 1.0 )
-    {
-        ball.ypos = 2.0 - ball.ypos;
-        ball.yspeed = -ball.yspeed;
-    }
-    else if( ball.ypos <= -1.0 )
-    {
-        ball.ypos = -2.0 - ball.ypos;
-        ball.yspeed = -ball.yspeed;
-    }
-
-    // Did the ball hit/miss a player?
-    event = NOBODY_WINS;
-
-    // Is the ball entering the player 1 goal?
-    if( ball.xpos < -1.0 + PLAYER_XSIZE )
-    {
-        // Did player 1 catch the ball?
-        if( ball.ypos > (player1.ypos-PLAYER_YSIZE) &&
-            ball.ypos < (player1.ypos+PLAYER_YSIZE) )
-        {
-            ball.xpos = -2.0 + 2.0*PLAYER_XSIZE - ball.xpos;
-            ball.xspeed = -ball.xspeed;
-        }
-        else
-        {
-            event = PLAYER2_WINS;
-        }
-    }
-
-    // Is the ball entering the player 2 goal?
-    if( ball.xpos > 1.0 - PLAYER_XSIZE )
-    {
-        // Did player 2 catch the ball?
-        if( ball.ypos > (player2.ypos-PLAYER_YSIZE) &&
-            ball.ypos < (player2.ypos+PLAYER_YSIZE) )
-        {
-            ball.xpos = 2.0 - 2.0*PLAYER_XSIZE - ball.xpos;
-            ball.xspeed = -ball.xspeed;
-        }
-        else
-        {
-            event = PLAYER1_WINS;
-        }
-    }
-
-    return event;
-}
-
-
-//========================================================================
-// DrawBox() - Draw a 3D box
-//========================================================================
-
-#define TEX_SCALE 4.0f
-
-
-void DrawBox( float x1, float y1, float z1, float x2, float y2, float z2 )
-{
-    // Draw six sides of a cube
-    glBegin( GL_QUADS );
-      // Side 1 (down)
-      glNormal3f( 0.0f, 0.0f, -1.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x1,y2,z1 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x2,y2,z1 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x2,y1,z1 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x1,y1,z1 );
-      // Side 2 (up)
-      glNormal3f( 0.0f, 0.0f, 1.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x1,y1,z2 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x2,y1,z2 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x2,y2,z2 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x1,y2,z2 );
-      // Side 3 (backward)
-      glNormal3f( 0.0f, -1.0f, 0.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x1,y1,z1 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x2,y1,z1 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x2,y1,z2 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x1,y1,z2 );
-      // Side 4 (forward)
-      glNormal3f( 0.0f, 1.0f, 0.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x1,y2,z2 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x2,y2,z2 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x2,y2,z1 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x1,y2,z1 );
-      // Side 5 (left)
-      glNormal3f( -1.0f, 0.0f, 0.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x1,y1,z2 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x1,y2,z2 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x1,y2,z1 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x1,y1,z1 );
-      // Side 6 (right)
-      glNormal3f( 1.0f, 0.0f, 0.0f );
-      glTexCoord2f( 0.0f, 0.0f );
-      glVertex3f( x2,y1,z1 );
-      glTexCoord2f( TEX_SCALE, 0.0f );
-      glVertex3f( x2,y2,z1 );
-      glTexCoord2f( TEX_SCALE, TEX_SCALE );
-      glVertex3f( x2,y2,z2 );
-      glTexCoord2f( 0.0f, TEX_SCALE );
-      glVertex3f( x2,y1,z2 );
-    glEnd();
-}
-
-
-//========================================================================
-// UpdateDisplay() - Draw graphics (all game related OpenGL stuff goes
-// here)
-//========================================================================
-
-void UpdateDisplay( void )
-{
-    // Get window size
-    glfwGetWindowSize( &width, &height );
-
-    // Set viewport
-    glViewport( 0, 0, width, height );
-
-    // Clear display
-    glClearColor( 0.02f, 0.02f, 0.02f, 0.0f );
-    glClearDepth( 1.0f );
-    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-
-    // Setup projection matrix
-    glMatrixMode( GL_PROJECTION );
-    glLoadIdentity();
-    gluPerspective(
-        55.0f,                            // Angle of view
-        (GLfloat)width/(GLfloat)height,   // Aspect
-        1.0f,                             // Near Z
-        100.0f                            // Far Z
-    );
-
-    // Setup modelview matrix
-    glMatrixMode( GL_MODELVIEW );
-    glLoadIdentity();
-    switch( camerapos )
-    {
-    default:
-    case CAMERA_CLASSIC:
-        gluLookAt(
-            0.0f, 0.0f, 2.5f,
-            0.0f, 0.0f, 0.0f,
-            0.0f, 1.0f, 0.0f
-        );
-        break;
-    case CAMERA_ABOVE:
-        gluLookAt(
-            0.0f, 0.0f, 2.5f,
-            (float)ball.xpos, (float)ball.ypos, 0.0f,
-            0.0f, 1.0f, 0.0f
-        );
-        break;
-    case CAMERA_SPECTATOR:
-        gluLookAt(
-            0.0f, -2.0, 1.2f,
-            (float)ball.xpos, (float)ball.ypos, 0.0f,
-            0.0f, 0.0f, 1.0f
-        );
-        break;
-    }
-
-    // Enable depth testing
-    glEnable( GL_DEPTH_TEST );
-    glDepthFunc( GL_LEQUAL );
-
-    // Enable lighting
-    glEnable( GL_LIGHTING );
-    glLightModelfv( GL_LIGHT_MODEL_AMBIENT, env_ambient );
-    glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE );
-    glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
-    glLightfv( GL_LIGHT1, GL_POSITION, light1_position );
-    glLightfv( GL_LIGHT1, GL_DIFFUSE,  light1_diffuse );
-    glLightfv( GL_LIGHT1, GL_AMBIENT,  light1_ambient );
-    glEnable( GL_LIGHT1 );
-
-    // Front face is counter-clock-wise
-    glFrontFace( GL_CCW );
-
-    // Enable face culling (not necessary, but speeds up rendering)
-    glCullFace( GL_BACK );
-    glEnable( GL_CULL_FACE );
-
-    // Draw Player 1
-    glMaterialfv( GL_FRONT, GL_DIFFUSE, player1_diffuse );
-    glMaterialfv( GL_FRONT, GL_AMBIENT, player1_ambient );
-    DrawBox( -1.f,              (GLfloat)player1.ypos-PLAYER_YSIZE, 0.f,
-             -1.f+PLAYER_XSIZE, (GLfloat)player1.ypos+PLAYER_YSIZE, 0.1f );
-
-    // Draw Player 2
-    glMaterialfv( GL_FRONT, GL_DIFFUSE, player2_diffuse );
-    glMaterialfv( GL_FRONT, GL_AMBIENT, player2_ambient );
-    DrawBox( 1.f-PLAYER_XSIZE, (GLfloat)player2.ypos-PLAYER_YSIZE, 0.f,
-             1.f,              (GLfloat)player2.ypos+PLAYER_YSIZE, 0.1f );
-
-    // Draw Ball
-    glMaterialfv( GL_FRONT, GL_DIFFUSE, ball_diffuse );
-    glMaterialfv( GL_FRONT, GL_AMBIENT, ball_ambient );
-    DrawBox( (GLfloat)ball.xpos-BALL_SIZE, (GLfloat)ball.ypos-BALL_SIZE, 0.f,
-             (GLfloat)ball.xpos+BALL_SIZE, (GLfloat)ball.ypos+BALL_SIZE, BALL_SIZE*2 );
-
-    // Top game field border
-    glMaterialfv( GL_FRONT, GL_DIFFUSE, border_diffuse );
-    glMaterialfv( GL_FRONT, GL_AMBIENT, border_ambient );
-    DrawBox( -1.1f, 1.0f, 0.0f,  1.1f, 1.1f, 0.1f );
-    // Bottom game field border
-    glColor3f( 0.0f, 0.0f, 0.7f );
-    DrawBox( -1.1f, -1.1f, 0.0f,  1.1f, -1.0f, 0.1f );
-    // Left game field border
-    DrawBox( -1.1f, -1.0f, 0.0f,  -1.0f, 1.0f, 0.1f );
-    // Left game field border
-    DrawBox( 1.0f, -1.0f, 0.0f,  1.1f, 1.0f, 0.1f );
-
-    // Enable texturing
-    glEnable( GL_TEXTURE_2D );
-    glBindTexture( GL_TEXTURE_2D, tex_id[ TEX_FIELD ] );
-
-    // Game field floor
-    glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse );
-    glMaterialfv( GL_FRONT, GL_AMBIENT, floor_ambient );
-    DrawBox( -1.01f, -1.01f, -0.01f,  1.01f, 1.01f, 0.0f );
-
-    // Disable texturing
-    glDisable( GL_TEXTURE_2D );
-
-    // Disable face culling
-    glDisable( GL_CULL_FACE );
-
-    // Disable lighting
-    glDisable( GL_LIGHTING );
-
-    // Disable depth testing
-    glDisable( GL_DEPTH_TEST );
-}
-
-
-//========================================================================
-// GameOver()
-//========================================================================
-
-void GameOver( void )
-{
-    // Enable sticky keys
-    glfwEnable( GLFW_STICKY_KEYS );
-
-    // Until the user presses ESC or SPACE
-    while( !glfwGetKey( GLFW_KEY_ESC ) && !glfwGetKey( ' ' ) &&
-           glfwGetWindowParam( GLFW_OPENED ) )
-    {
-        // Draw display
-        UpdateDisplay();
-
-        // Setup projection matrix
-        glMatrixMode( GL_PROJECTION );
-        glLoadIdentity();
-        glOrtho( 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f );
-
-        // Setup modelview matrix
-        glMatrixMode( GL_MODELVIEW );
-        glLoadIdentity();
-
-        // Enable blending
-        glEnable( GL_BLEND );
-
-        // Dim background
-        glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );
-        glColor4f( 0.3f, 0.3f, 0.3f, 0.3f );
-        glBegin( GL_QUADS );
-          glVertex2f( 0.0f, 0.0f );
-          glVertex2f( 1.0f, 0.0f );
-          glVertex2f( 1.0f, 1.0f );
-          glVertex2f( 0.0f, 1.0f );
-        glEnd();
-
-        // Display winner text
-        glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR );
-        if( winner == PLAYER1 )
-        {
-            glColor4f( 1.0f, 0.5f, 0.5f, 1.0f );
-            DrawImage( TEX_WINNER1, 0.35f, 0.65f, 0.46f, 0.54f );
-        }
-        else if( winner == PLAYER2 )
-        {
-            glColor4f( 0.5f, 1.0f, 0.5f, 1.0f );
-            DrawImage( TEX_WINNER2, 0.35f, 0.65f, 0.46f, 0.54f );
-        }
-
-        // Disable blending
-        glDisable( GL_BLEND );
-
-        // Swap buffers
-        glfwSwapBuffers();
-    }
-
-    // Disable sticky keys
-    glfwDisable( GLFW_STICKY_KEYS );
-}
-
-
-//========================================================================
-// GameLoop() - Game loop
-//========================================================================
-
-void GameLoop( void )
-{
-    int playing, event;
-
-    // Initialize a new game
-    NewGame();
-
-    // Enable sticky keys
-    glfwEnable( GLFW_STICKY_KEYS );
-
-    // Loop until the game ends
-    playing = GL_TRUE;
-    while( playing && glfwGetWindowParam( GLFW_OPENED ) )
-    {
-        // Frame timer
-        oldtime = thistime;
-        thistime = glfwGetTime();
-        dt = thistime - oldtime;
-
-        // Get user input and update player positions
-        PlayerControl();
-
-        // Move the ball, and check if a player hits/misses the ball
-        event = BallControl();
-
-        // Did we have a winner?
-        switch( event )
-        {
-        case PLAYER1_WINS:
-            winner = PLAYER1;
-            playing = GL_FALSE;
-            break;
-        case PLAYER2_WINS:
-            winner = PLAYER2;
-            playing = GL_FALSE;
-            break;
-        default:
-            break;
-        }
-
-        // Did the user press ESC?
-        if( glfwGetKey( GLFW_KEY_ESC ) )
-        {
-            playing = GL_FALSE;
-        }
-
-        // Did the user change camera view?
-        if( glfwGetKey( '1' ) )
-        {
-            camerapos = CAMERA_CLASSIC;
-        }
-        else if( glfwGetKey( '2' ) )
-        {
-            camerapos = CAMERA_ABOVE;
-        }
-        else if( glfwGetKey( '3' ) )
-        {
-            camerapos = CAMERA_SPECTATOR;
-        }
-
-        // Draw display
-        UpdateDisplay();
-
-        // Swap buffers
-        glfwSwapBuffers();
-    }
-
-    // Disable sticky keys
-    glfwDisable( GLFW_STICKY_KEYS );
-
-    // Show winner
-    GameOver();
-}
-
-
-//========================================================================
-// main() - Program entry point
-//========================================================================
-
-int main( void )
-{
-    int menuoption;
-
-    // Initialize GLFW
-    if( !glfwInit() )
-    {
-        fprintf( stderr, "Failed to initialize GLFW\n" );
-        exit( EXIT_FAILURE );
-    }
-
-    // Open OpenGL window
-    if( !glfwCreateWindow( WIDTH, HEIGHT, 0,0,0,0, 16,0, GLFW_FULLSCREEN ) )
-    {
-        fprintf( stderr, "Failed to open GLFW window\n" );
-        glfwTerminate();
-        exit( EXIT_FAILURE );
-    }
-
-    glfwSwapInterval( 1 );
-
-    // Load all textures
-    if( !LoadTextures() )
-    {
-        glfwTerminate();
-        exit( EXIT_FAILURE );
-    }
-
-    // Main loop
-    do
-    {
-        // Get menu option
-        menuoption = GameMenu();
-
-        // If the user wants to play, let him...
-        if( menuoption == MENU_PLAY )
-        {
-            GameLoop();
-        }
-    }
-    while( menuoption != MENU_QUIT );
-
-    // Unload all textures
-    if( glfwGetWindowParam( GLFW_OPENED ) )
-    {
-        glDeleteTextures( NUM_TEXTURES, tex_id );
-    }
-
-    // Terminate GLFW
-    glfwTerminate();
-
-    exit( EXIT_SUCCESS );
-}
-

BIN
examples/pong3d_field.tga


BIN
examples/pong3d_instr.tga


BIN
examples/pong3d_menu.tga


BIN
examples/pong3d_title.tga


BIN
examples/pong3d_winner1.tga


BIN
examples/pong3d_winner2.tga


+ 6 - 6
include/GL/glfw3.h

@@ -528,11 +528,11 @@ GLFWAPI void glfwSetGammaRamp(const GLFWgammaramp* ramp);
 GLFWAPI void glfwWindowHint(int target, int hint);
 GLFWAPI GLFWwindow glfwCreateWindow(int width, int height, int mode, const char* title, GLFWwindow share);
 GLFWAPI void glfwDestroyWindow(GLFWwindow window);
-GLFWAPI void glfwSetWindowTitle(GLFWwindow, const char* title);
-GLFWAPI void glfwGetWindowSize(GLFWwindow, int* width, int* height);
-GLFWAPI void glfwSetWindowSize(GLFWwindow, int width, int height);
-GLFWAPI void glfwGetWindowPos(GLFWwindow, int* xpos, int* ypos);
-GLFWAPI void glfwSetWindowPos(GLFWwindow, int xpos, int ypos);
+GLFWAPI void glfwSetWindowTitle(GLFWwindow window, const char* title);
+GLFWAPI void glfwGetWindowSize(GLFWwindow window, int* width, int* height);
+GLFWAPI void glfwSetWindowSize(GLFWwindow window, int width, int height);
+GLFWAPI void glfwGetWindowPos(GLFWwindow window, int* xpos, int* ypos);
+GLFWAPI void glfwSetWindowPos(GLFWwindow window, int xpos, int ypos);
 GLFWAPI void glfwIconifyWindow(GLFWwindow window);
 GLFWAPI void glfwRestoreWindow(GLFWwindow window);
 GLFWAPI void glfwShowWindow(GLFWwindow window);
@@ -567,7 +567,7 @@ GLFWAPI void glfwSetScrollCallback(GLFWscrollfun cbfun);
 
 /* Joystick input */
 GLFWAPI int glfwGetJoystickParam(int joy, int param);
-GLFWAPI int glfwGetJoystickPos(int joy, float* pos, int numaxes);
+GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes);
 GLFWAPI int glfwGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons);
 
 /* Clipboard */

+ 3 - 0
readme.html

@@ -301,6 +301,7 @@ version of GLFW.</p>
   <li>Renamed <code>GLFW_BUILD_DLL</code> to <code>_GLFW_BUILD_DLL</code></li>
   <li>Renamed <code>version</code> test to <code>glfwinfo</code></li>
   <li>Renamed <code>GLFW_NO_GLU</code> to <code>GLFW_INCLUDE_GLU</code> and made it disabled by default</li>
+  <li>Renamed <code>glfwGetJoystickPos</code> to <code>glfwGetJoystickAxes</code> to match <code>glfwGetJoystickButtons</code></li>
   <li>Renamed mouse position functions to cursor position equivalents</li>
   <li>Replaced <code>glfwOpenWindow</code> and <code>glfwCloseWindow</code> with <code>glfwCreateWindow</code> and <code>glfwDestroyWindow</code></li>
   <li>Replaced ad hoc build system with CMake</li>
@@ -954,6 +955,8 @@ their skills.  Special thanks go out to:</p>
 
   <li>Samuli Tuomola, for support, bug reports and testing</li>
 
+  <li>Torsten Walluhn, for fixing various compilation issues on OS X</li>
+
   <li>Frank Wille, for helping with the AmigaOS port and making GLFW
   compile under IRIX 5.3</li>
 

+ 4 - 4
src/cocoa_joystick.m

@@ -528,7 +528,7 @@ int _glfwPlatformGetJoystickParam(int joy, int param)
 // Get joystick axis positions
 //========================================================================
 
-int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes)
+int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
 {
     int i;
 
@@ -556,12 +556,12 @@ int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes)
         long readScale = axes->maxReport - axes->minReport;
 
         if (readScale == 0)
-            pos[i] = axes->value;
+            axes[i] = axes->value;
         else
-            pos[i] = (2.0f * (axes->value - axes->minReport) / readScale) - 1.0f;
+            axes[i] = (2.0f * (axes->value - axes->minReport) / readScale) - 1.0f;
 
         if (i & 1)
-            pos[i] = -pos[i];
+            axes[i] = -axes[i];
     }
 
     return numaxes;

+ 1 - 1
src/internal.h

@@ -276,7 +276,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window);
 
 // Joystick input
 int _glfwPlatformGetJoystickParam(int joy, int param);
-int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes);
+int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes);
 int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons);
 
 // Time input

+ 4 - 4
src/joystick.c

@@ -61,7 +61,7 @@ GLFWAPI int glfwGetJoystickParam(int joy, int param)
 // Get joystick axis positions
 //========================================================================
 
-GLFWAPI int glfwGetJoystickPos(int joy, float* pos, int numaxes)
+GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes)
 {
     int i;
 
@@ -77,7 +77,7 @@ GLFWAPI int glfwGetJoystickPos(int joy, float* pos, int numaxes)
         return 0;
     }
 
-    if (pos == NULL || numaxes < 0)
+    if (axes == NULL || numaxes < 0)
     {
         _glfwSetError(GLFW_INVALID_VALUE, NULL);
         return 0;
@@ -85,9 +85,9 @@ GLFWAPI int glfwGetJoystickPos(int joy, float* pos, int numaxes)
 
     // Clear positions
     for (i = 0;  i < numaxes;  i++)
-        pos[i] = 0.0f;
+        axes[i] = 0.0f;
 
-    return _glfwPlatformGetJoystickPos(joy, pos, numaxes);
+    return _glfwPlatformGetJoystickAxes(joy, axes, numaxes);
 }
 
 

+ 7 - 7
src/win32_joystick.c

@@ -116,7 +116,7 @@ int _glfwPlatformGetJoystickParam(int joy, int param)
 // Get joystick axis positions
 //========================================================================
 
-int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes)
+int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
 {
     JOYCAPS jc;
     JOYINFOEX ji;
@@ -137,22 +137,22 @@ int _glfwPlatformGetJoystickPos(int joy, float* pos, int numaxes)
     // Get position values for all axes
     axis = 0;
     if (axis < numaxes)
-        pos[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
+        axes[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
 
     if (axis < numaxes)
-        pos[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
+        axes[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
 
     if (axis < numaxes && jc.wCaps & JOYCAPS_HASZ)
-        pos[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
+        axes[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
 
     if (axis < numaxes && jc.wCaps & JOYCAPS_HASR)
-        pos[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
+        axes[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
 
     if (axis < numaxes && jc.wCaps & JOYCAPS_HASU)
-        pos[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
+        axes[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
 
     if (axis < numaxes && jc.wCaps & JOYCAPS_HASV)
-        pos[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
+        axes[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
 
     return axis;
 }

+ 1 - 1
src/win32_platform.h

@@ -191,7 +191,7 @@ typedef struct _GLFWlibraryWin32
 
     // Timer data
     struct {
-        GLboolean             hasPerformanceCounter;
+        GLboolean             hasPC;
         double                resolution;
         unsigned int          t0_32;
         __int64               t0_64;

+ 4 - 4
src/win32_time.c

@@ -45,13 +45,13 @@ void _glfwInitTimer(void)
 
     if (QueryPerformanceFrequency((LARGE_INTEGER*) &freq))
     {
-        _glfwLibrary.Win32.timer.hasPerformanceCounter = GL_TRUE;
+        _glfwLibrary.Win32.timer.hasPC = GL_TRUE;
         _glfwLibrary.Win32.timer.resolution = 1.0 / (double) freq;
         QueryPerformanceCounter((LARGE_INTEGER*) &_glfwLibrary.Win32.timer.t0_64);
     }
     else
     {
-        _glfwLibrary.Win32.timer.hasPerformanceCounter = GL_FALSE;
+        _glfwLibrary.Win32.timer.hasPC = GL_FALSE;
         _glfwLibrary.Win32.timer.resolution = 0.001; // winmm resolution is 1 ms
         _glfwLibrary.Win32.timer.t0_32 = _glfw_timeGetTime();
     }
@@ -71,7 +71,7 @@ double _glfwPlatformGetTime(void)
     double t;
     __int64 t_64;
 
-    if (_glfwLibrary.Win32.timer.hasPerformanceCounter)
+    if (_glfwLibrary.Win32.timer.hasPC)
     {
         QueryPerformanceCounter((LARGE_INTEGER*) &t_64);
         t =  (double)(t_64 - _glfwLibrary.Win32.timer.t0_64);
@@ -91,7 +91,7 @@ void _glfwPlatformSetTime(double t)
 {
     __int64 t_64;
 
-    if (_glfwLibrary.Win32.timer.hasPerformanceCounter)
+    if (_glfwLibrary.Win32.timer.hasPC)
     {
         QueryPerformanceCounter((LARGE_INTEGER*) &t_64);
         _glfwLibrary.Win32.timer.t0_64 = t_64 - (__int64) (t / _glfwLibrary.Win32.timer.resolution);

+ 6 - 0
src/window.c

@@ -85,6 +85,12 @@ void _glfwSetDefaultWindowHints(void)
     // The default is to show the window and allow window resizing
     _glfwLibrary.hints.resizable = GL_TRUE;
     _glfwLibrary.hints.visible   = GL_TRUE;
+
+    // The default is 24 bits of depth, 8 bits of color
+    _glfwLibrary.hints.depthBits = 24;
+    _glfwLibrary.hints.redBits   = 8;
+    _glfwLibrary.hints.greenBits = 8;
+    _glfwLibrary.hints.blueBits  = 8;
 }
 
 

+ 20 - 7
src/x11_joystick.c

@@ -36,6 +36,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <errno.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -109,6 +110,7 @@ static void pollJoystickEvents(void)
 {
 #ifdef _GLFW_USE_LINUX_JOYSTICKS
     int i;
+    ssize_t result;
     struct js_event e;
 
     for (i = 0;  i <= GLFW_JOYSTICK_LAST;  i++)
@@ -117,8 +119,17 @@ static void pollJoystickEvents(void)
             continue;
 
         // Read all queued events (non-blocking)
-        while (read(_glfwLibrary.X11.joystick[i].fd, &e, sizeof(e)) > 0)
+        for (;;)
         {
+            errno = 0;
+            result = read(_glfwLibrary.X11.joystick[i].fd, &e, sizeof(e));
+
+            if (errno == ENODEV)
+                _glfwLibrary.X11.joystick[i].present = GL_FALSE;
+
+            if (result < sizeof(e))
+                break;
+
             // We don't care if it's an init event or not
             e.type &= ~JS_EVENT_INIT;
 
@@ -221,6 +232,8 @@ void _glfwTerminateJoysticks(void)
 
 int _glfwPlatformGetJoystickParam(int joy, int param)
 {
+    pollJoystickEvents();
+
     if (!_glfwLibrary.X11.joystick[joy].present)
         return 0;
 
@@ -247,20 +260,20 @@ int _glfwPlatformGetJoystickParam(int joy, int param)
 // Get joystick axis positions
 //========================================================================
 
-int _glfwPlatformGetJoystickPos(int joy, float* pos, int numAxes)
+int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numAxes)
 {
     int i;
 
+    pollJoystickEvents();
+
     if (!_glfwLibrary.X11.joystick[joy].present)
         return 0;
 
-    pollJoystickEvents();
-
     if (_glfwLibrary.X11.joystick[joy].numAxes < numAxes)
         numAxes = _glfwLibrary.X11.joystick[joy].numAxes;
 
     for (i = 0;  i < numAxes;  i++)
-        pos[i] = _glfwLibrary.X11.joystick[joy].axis[i];
+        axes[i] = _glfwLibrary.X11.joystick[joy].axis[i];
 
     return numAxes;
 }
@@ -275,11 +288,11 @@ int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
 {
     int i;
 
+    pollJoystickEvents();
+
     if (!_glfwLibrary.X11.joystick[joy].present)
         return 0;
 
-    pollJoystickEvents();
-
     if (_glfwLibrary.X11.joystick[joy].numButtons < numButtons)
         numButtons = _glfwLibrary.X11.joystick[joy].numButtons;
 

+ 0 - 48
src/x11_window.c

@@ -473,17 +473,10 @@ static void processSingleEvent(void)
             // A keyboard key was pressed
             window = findWindow(event.xkey.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for KeyPress event\n");
                 return;
-            }
 
-            // Translate and report key press
             _glfwInputKey(window, translateKey(event.xkey.keycode), GLFW_PRESS);
-
-            // Translate and report character input
             _glfwInputChar(window, translateChar(&event.xkey));
-
             break;
         }
 
@@ -492,10 +485,7 @@ static void processSingleEvent(void)
             // A keyboard key was released
             window = findWindow(event.xkey.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for KeyRelease event\n");
                 return;
-            }
 
             // Do not report key releases for key repeats. For key repeats we
             // will get KeyRelease/KeyPress pairs with similar or identical
@@ -523,9 +513,7 @@ static void processSingleEvent(void)
                 }
             }
 
-            // Translate and report key release
             _glfwInputKey(window, translateKey(event.xkey.keycode), GLFW_RELEASE);
-
             break;
         }
 
@@ -534,10 +522,7 @@ static void processSingleEvent(void)
             // A mouse button was pressed or a scrolling event occurred
             window = findWindow(event.xbutton.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for ButtonPress event\n");
                 return;
-            }
 
             if (event.xbutton.button == Button1)
                 _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
@@ -566,10 +551,7 @@ static void processSingleEvent(void)
             // A mouse button was released
             window = findWindow(event.xbutton.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for ButtonRelease event\n");
                 return;
-            }
 
             if (event.xbutton.button == Button1)
             {
@@ -597,10 +579,7 @@ static void processSingleEvent(void)
             // The cursor entered the window
             window = findWindow(event.xcrossing.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for EnterNotify event\n");
                 return;
-            }
 
             if (window->cursorMode == GLFW_CURSOR_HIDDEN)
                 hideCursor(window);
@@ -614,10 +593,7 @@ static void processSingleEvent(void)
             // The cursor left the window
             window = findWindow(event.xcrossing.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for LeaveNotify event\n");
                 return;
-            }
 
             if (window->cursorMode == GLFW_CURSOR_HIDDEN)
                 showCursor(window);
@@ -631,10 +607,7 @@ static void processSingleEvent(void)
             // The cursor was moved
             window = findWindow(event.xmotion.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for MotionNotify event\n");
                 return;
-            }
 
             if (event.xmotion.x != window->X11.cursorPosX ||
                 event.xmotion.y != window->X11.cursorPosY)
@@ -672,10 +645,7 @@ static void processSingleEvent(void)
             // The window configuration changed somehow
             window = findWindow(event.xconfigure.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for ConfigureNotify event\n");
                 return;
-            }
 
             _glfwInputWindowSize(window,
                                  event.xconfigure.width,
@@ -693,10 +663,7 @@ static void processSingleEvent(void)
             // Custom client message, probably from the window manager
             window = findWindow(event.xclient.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for ClientMessage event\n");
                 return;
-            }
 
             if ((Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmDeleteWindow)
             {
@@ -727,10 +694,7 @@ static void processSingleEvent(void)
             // The window was mapped
             window = findWindow(event.xmap.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for MapNotify event\n");
                 return;
-            }
 
             _glfwInputWindowVisibility(window, GL_TRUE);
             _glfwInputWindowIconify(window, GL_FALSE);
@@ -742,10 +706,7 @@ static void processSingleEvent(void)
             // The window was unmapped
             window = findWindow(event.xmap.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for UnmapNotify event\n");
                 return;
-            }
 
             _glfwInputWindowVisibility(window, GL_FALSE);
             _glfwInputWindowIconify(window, GL_TRUE);
@@ -757,10 +718,7 @@ static void processSingleEvent(void)
             // The window gained focus
             window = findWindow(event.xfocus.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for FocusIn event\n");
                 return;
-            }
 
             _glfwInputWindowFocus(window, GL_TRUE);
 
@@ -775,10 +733,7 @@ static void processSingleEvent(void)
             // The window lost focus
             window = findWindow(event.xfocus.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for FocusOut event\n");
                 return;
-            }
 
             _glfwInputWindowFocus(window, GL_FALSE);
 
@@ -793,10 +748,7 @@ static void processSingleEvent(void)
             // The window's contents was damaged
             window = findWindow(event.xexpose.window);
             if (window == NULL)
-            {
-                fprintf(stderr, "Cannot find GLFW window structure for Expose event\n");
                 return;
-            }
 
             _glfwInputWindowDamage(window);
             break;

+ 31 - 20
tests/glfwinfo.c

@@ -119,6 +119,32 @@ static void list_extensions(int major, int minor)
     putchar('\n');
 }
 
+static GLboolean valid_version(void)
+{
+    int major, minor, revision;
+
+    glfwGetVersion(&major, &minor, &revision);
+
+    printf("GLFW header version: %u.%u.%u\n",
+           GLFW_VERSION_MAJOR,
+           GLFW_VERSION_MINOR,
+           GLFW_VERSION_REVISION);
+
+    printf("GLFW library version: %u.%u.%u\n", major, minor, revision);
+
+    if (major != GLFW_VERSION_MAJOR)
+    {
+        printf("*** ERROR: GLFW major version mismatch! ***\n");
+        return GL_FALSE;
+    }
+
+    if (minor != GLFW_VERSION_MINOR || revision != GLFW_VERSION_REVISION)
+        printf("*** WARNING: GLFW version mismatch! ***\n");
+
+    printf("GLFW library version string: \"%s\"\n", glfwGetVersionString());
+    return GL_TRUE;
+}
+
 int main(int argc, char** argv)
 {
     int ch, profile = 0, strategy = 0, major = 1, minor = 0, revision;
@@ -126,6 +152,9 @@ int main(int argc, char** argv)
     GLint flags, mask;
     GLFWwindow window;
 
+    if (!valid_version())
+        exit(EXIT_FAILURE);
+
     while ((ch = getopt(argc, argv, "dfhlm:n:p:r:")) != -1)
     {
         switch (ch)
@@ -181,6 +210,8 @@ int main(int argc, char** argv)
     argc -= optind;
     argv += optind;
 
+    // Initialize GLFW and create window
+
     glfwSetErrorCallback(error_callback);
 
     if (!glfwInit())
@@ -218,26 +249,6 @@ int main(int argc, char** argv)
 
     glfwMakeContextCurrent(window);
 
-    // Report GLFW version
-
-    glfwGetVersion(&major, &minor, &revision);
-
-    printf("GLFW header version: %u.%u.%u\n",
-           GLFW_VERSION_MAJOR,
-           GLFW_VERSION_MINOR,
-           GLFW_VERSION_REVISION);
-
-    printf("GLFW library version: %u.%u.%u\n", major, minor, revision);
-
-    if (major != GLFW_VERSION_MAJOR ||
-        minor != GLFW_VERSION_MINOR ||
-        revision != GLFW_VERSION_REVISION)
-    {
-        printf("*** WARNING: GLFW version mismatch! ***\n");
-    }
-
-    printf("GLFW library version string: \"%s\"\n", glfwGetVersionString());
-
     // Report OpenGL version
 
     printf("OpenGL context version string: \"%s\"\n", glGetString(GL_VERSION));

+ 1 - 1
tests/joysticks.c

@@ -137,7 +137,7 @@ static void refresh_joysticks(void)
                 j->axes = realloc(j->axes, j->axis_count * sizeof(float));
             }
 
-            glfwGetJoystickPos(GLFW_JOYSTICK_1 + i, j->axes, j->axis_count);
+            glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, j->axes, j->axis_count);
 
             button_count = glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_BUTTONS);
             if (button_count != j->button_count)