//========================================================================
// 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, <