particles.c
Go to the documentation of this file.
1 //========================================================================
2 // A simple particle engine with threaded physics
3 // Copyright (c) Marcus Geelnard
4 // Copyright (c) Camilla Löwy <elmindreda@glfw.org>
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 // claim that you wrote the original software. If you use this software
16 // in a product, an acknowledgment in the product documentation would
17 // be appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not
20 // be misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source
23 // distribution.
24 //
25 //========================================================================
26 
27 #if defined(_MSC_VER)
28  // Make MS math.h define M_PI
29  #define _USE_MATH_DEFINES
30 #endif
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <math.h>
36 #include <time.h>
37 
38 #include <tinycthread.h>
39 #include <getopt.h>
40 #include <linmath.h>
41 
42 #include <glad/glad.h>
43 #include <GLFW/glfw3.h>
44 
45 // Define tokens for GL_EXT_separate_specular_color if not already defined
46 #ifndef GL_EXT_separate_specular_color
47 #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
48 #define GL_SINGLE_COLOR_EXT 0x81F9
49 #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
50 #endif // GL_EXT_separate_specular_color
51 
52 
53 //========================================================================
54 // Type definitions
55 //========================================================================
56 
57 typedef struct
58 {
59  float x, y, z;
60 } Vec3;
61 
62 // This structure is used for interleaved vertex arrays (see the
63 // draw_particles function)
64 //
65 // NOTE: This structure SHOULD be packed on most systems. It uses 32-bit fields
66 // on 32-bit boundaries, and is a multiple of 64 bits in total (6x32=3x64). If
67 // it does not work, try using pragmas or whatever to force the structure to be
68 // packed.
69 typedef struct
70 {
71  GLfloat s, t; // Texture coordinates
72  GLuint rgba; // Color (four ubytes packed into an uint)
73  GLfloat x, y, z; // Vertex coordinates
74 } Vertex;
75 
76 
77 //========================================================================
78 // Program control global variables
79 //========================================================================
80 
81 // Window dimensions
83 
84 // "wireframe" flag (true if we use wireframe view)
86 
87 // Thread synchronization
88 struct {
89  double t; // Time (s)
90  float dt; // Time since last frame (s)
91  int p_frame; // Particle physics frame number
92  int d_frame; // Particle draw frame number
93  cnd_t p_done; // Condition: particle physics done
94  cnd_t d_done; // Condition: particle draw done
95  mtx_t particles_lock; // Particles data sharing mutex
96 } thread_sync;
97 
98 
99 //========================================================================
100 // Texture declarations (we hard-code them into the source code, since
101 // they are so simple)
102 //========================================================================
103 
104 #define P_TEX_WIDTH 8 // Particle texture dimensions
105 #define P_TEX_HEIGHT 8
106 #define F_TEX_WIDTH 16 // Floor texture dimensions
107 #define F_TEX_HEIGHT 16
108 
109 // Texture object IDs
111 
112 // Particle texture (a simple spot)
113 const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = {
114  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115  0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00,
116  0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00,
117  0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00,
118  0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00,
119  0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00,
120  0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00,
121  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
122 };
123 
124 // Floor texture (your basic checkered floor)
125 const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = {
126  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
127  0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
128  0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30,
129  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
130  0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30,
131  0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
132  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30,
133  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
134  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
135  0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff,
136  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0,
137  0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
138  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0,
139  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0,
140  0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
141  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
142 };
143 
144 
145 //========================================================================
146 // These are fixed constants that control the particle engine. In a
147 // modular world, these values should be variables...
148 //========================================================================
149 
150 // Maximum number of particles
151 #define MAX_PARTICLES 3000
152 
153 // Life span of a particle (in seconds)
154 #define LIFE_SPAN 8.f
155 
156 // A new particle is born every [BIRTH_INTERVAL] second
157 #define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES)
158 
159 // Particle size (meters)
160 #define PARTICLE_SIZE 0.7f
161 
162 // Gravitational constant (m/s^2)
163 #define GRAVITY 9.8f
164 
165 // Base initial velocity (m/s)
166 #define VELOCITY 8.f
167 
168 // Bounce friction (1.0 = no friction, 0.0 = maximum friction)
169 #define FRICTION 0.75f
170 
171 // "Fountain" height (m)
172 #define FOUNTAIN_HEIGHT 3.f
173 
174 // Fountain radius (m)
175 #define FOUNTAIN_RADIUS 1.6f
176 
177 // Minimum delta-time for particle phisics (s)
178 #define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f)
179 
180 
181 //========================================================================
182 // Particle system global variables
183 //========================================================================
184 
185 // This structure holds all state for a single particle
186 typedef struct {
187  float x,y,z; // Position in space
188  float vx,vy,vz; // Velocity vector
189  float r,g,b; // Color of particle
190  float life; // Life of particle (1.0 = newborn, < 0.0 = dead)
191  int active; // Tells if this particle is active
192 } PARTICLE;
193 
194 // Global vectors holding all particles. We use two vectors for double
195 // buffering.
197 
198 // Global variable holding the age of the youngest particle
199 static float min_age;
200 
201 // Color of latest born particle (used for fountain lighting)
202 static float glow_color[4];
203 
204 // Position of latest born particle (used for fountain lighting)
205 static float glow_pos[4];
206 
207 
208 //========================================================================
209 // Object material and fog configuration constants
210 //========================================================================
211 
212 const GLfloat fountain_diffuse[4] = { 0.7f, 1.f, 1.f, 1.f };
213 const GLfloat fountain_specular[4] = { 1.f, 1.f, 1.f, 1.f };
215 const GLfloat floor_diffuse[4] = { 1.f, 0.6f, 0.6f, 1.f };
216 const GLfloat floor_specular[4] = { 0.6f, 0.6f, 0.6f, 1.f };
218 const GLfloat fog_color[4] = { 0.1f, 0.1f, 0.1f, 1.f };
219 
220 
221 //========================================================================
222 // Print usage information
223 //========================================================================
224 
225 static void usage(void)
226 {
227  printf("Usage: particles [-bfhs]\n");
228  printf("Options:\n");
229  printf(" -f Run in full screen\n");
230  printf(" -h Display this help\n");
231  printf(" -s Run program as single thread (default is to use two threads)\n");
232  printf("\n");
233  printf("Program runtime controls:\n");
234  printf(" W Toggle wireframe mode\n");
235  printf(" Esc Exit program\n");
236 }
237 
238 
239 //========================================================================
240 // Initialize a new particle
241 //========================================================================
242 
243 static void init_particle(PARTICLE *p, double t)
244 {
245  float xy_angle, velocity;
246 
247  // Start position of particle is at the fountain blow-out
248  p->x = 0.f;
249  p->y = 0.f;
250  p->z = FOUNTAIN_HEIGHT;
251 
252  // Start velocity is up (Z)...
253  p->vz = 0.7f + (0.3f / 4096.f) * (float) (rand() & 4095);
254 
255  // ...and a randomly chosen X/Y direction
256  xy_angle = (2.f * (float) M_PI / 4096.f) * (float) (rand() & 4095);
257  p->vx = 0.4f * (float) cos(xy_angle);
258  p->vy = 0.4f * (float) sin(xy_angle);
259 
260  // Scale velocity vector according to a time-varying velocity
261  velocity = VELOCITY * (0.8f + 0.1f * (float) (sin(0.5 * t) + sin(1.31 * t)));
262  p->vx *= velocity;
263  p->vy *= velocity;
264  p->vz *= velocity;
265 
266  // Color is time-varying
267  p->r = 0.7f + 0.3f * (float) sin(0.34 * t + 0.1);
268  p->g = 0.6f + 0.4f * (float) sin(0.63 * t + 1.1);
269  p->b = 0.6f + 0.4f * (float) sin(0.91 * t + 2.1);
270 
271  // Store settings for fountain glow lighting
272  glow_pos[0] = 0.4f * (float) sin(1.34 * t);
273  glow_pos[1] = 0.4f * (float) sin(3.11 * t);
274  glow_pos[2] = FOUNTAIN_HEIGHT + 1.f;
275  glow_pos[3] = 1.f;
276  glow_color[0] = p->r;
277  glow_color[1] = p->g;
278  glow_color[2] = p->b;
279  glow_color[3] = 1.f;
280 
281  // The particle is new-born and active
282  p->life = 1.f;
283  p->active = 1;
284 }
285 
286 
287 //========================================================================
288 // Update a particle
289 //========================================================================
290 
291 #define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2)
292 
293 static void update_particle(PARTICLE *p, float dt)
294 {
295  // If the particle is not active, we need not do anything
296  if (!p->active)
297  return;
298 
299  // The particle is getting older...
300  p->life -= dt * (1.f / LIFE_SPAN);
301 
302  // Did the particle die?
303  if (p->life <= 0.f)
304  {
305  p->active = 0;
306  return;
307  }
308 
309  // Apply gravity
310  p->vz = p->vz - GRAVITY * dt;
311 
312  // Update particle position
313  p->x = p->x + p->vx * dt;
314  p->y = p->y + p->vy * dt;
315  p->z = p->z + p->vz * dt;
316 
317  // Simple collision detection + response
318  if (p->vz < 0.f)
319  {
320  // Particles should bounce on the fountain (with friction)
321  if ((p->x * p->x + p->y * p->y) < FOUNTAIN_R2 &&
322  p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE / 2))
323  {
324  p->vz = -FRICTION * p->vz;
325  p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE / 2 +
327  PARTICLE_SIZE / 2 - p->z);
328  }
329 
330  // Particles should bounce on the floor (with friction)
331  else if (p->z < PARTICLE_SIZE / 2)
332  {
333  p->vz = -FRICTION * p->vz;
334  p->z = PARTICLE_SIZE / 2 +
335  FRICTION * (PARTICLE_SIZE / 2 - p->z);
336  }
337  }
338 }
339 
340 
341 //========================================================================
342 // The main frame for the particle engine. Called once per frame.
343 //========================================================================
344 
345 static void particle_engine(double t, float dt)
346 {
347  int i;
348  float dt2;
349 
350  // Update particles (iterated several times per frame if dt is too large)
351  while (dt > 0.f)
352  {
353  // Calculate delta time for this iteration
354  dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T;
355 
356  for (i = 0; i < MAX_PARTICLES; i++)
357  update_particle(&particles[i], dt2);
358 
359  min_age += dt2;
360 
361  // Should we create any new particle(s)?
362  while (min_age >= BIRTH_INTERVAL)
363  {
365 
366  // Find a dead particle to replace with a new one
367  for (i = 0; i < MAX_PARTICLES; i++)
368  {
369  if (!particles[i].active)
370  {
371  init_particle(&particles[i], t + min_age);
372  update_particle(&particles[i], min_age);
373  break;
374  }
375  }
376  }
377 
378  dt -= dt2;
379  }
380 }
381 
382 
383 //========================================================================
384 // Draw all active particles. We use OpenGL 1.1 vertex
385 // arrays for this in order to accelerate the drawing.
386 //========================================================================
387 
388 #define BATCH_PARTICLES 70 // Number of particles to draw in each batch
389  // (70 corresponds to 7.5 KB = will not blow
390  // the L1 data cache on most CPUs)
391 #define PARTICLE_VERTS 4 // Number of vertices per particle
392 
393 static void draw_particles(GLFWwindow* window, double t, float dt)
394 {
395  int i, particle_count;
396  Vertex vertex_array[BATCH_PARTICLES * PARTICLE_VERTS];
397  Vertex* vptr;
398  float alpha;
399  GLuint rgba;
400  Vec3 quad_lower_left, quad_lower_right;
401  GLfloat mat[16];
402  PARTICLE* pptr;
403 
404  // Here comes the real trick with flat single primitive objects (s.c.
405  // "billboards"): We must rotate the textured primitive so that it
406  // always faces the viewer (is coplanar with the view-plane).
407  // We:
408  // 1) Create the primitive around origo (0,0,0)
409  // 2) Rotate it so that it is coplanar with the view plane
410  // 3) Translate it according to the particle position
411  // Note that 1) and 2) is the same for all particles (done only once).
412 
413  // Get modelview matrix. We will only use the upper left 3x3 part of
414  // the matrix, which represents the rotation.
416 
417  // 1) & 2) We do it in one swift step:
418  // Although not obvious, the following six lines represent two matrix/
419  // vector multiplications. The matrix is the inverse 3x3 rotation
420  // matrix (i.e. the transpose of the same matrix), and the two vectors
421  // represent the lower left corner of the quad, PARTICLE_SIZE/2 *
422  // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
423  // The upper left/right corners of the quad is always the negative of
424  // the opposite corners (regardless of rotation).
425  quad_lower_left.x = (-PARTICLE_SIZE / 2) * (mat[0] + mat[1]);
426  quad_lower_left.y = (-PARTICLE_SIZE / 2) * (mat[4] + mat[5]);
427  quad_lower_left.z = (-PARTICLE_SIZE / 2) * (mat[8] + mat[9]);
428  quad_lower_right.x = (PARTICLE_SIZE / 2) * (mat[0] - mat[1]);
429  quad_lower_right.y = (PARTICLE_SIZE / 2) * (mat[4] - mat[5]);
430  quad_lower_right.z = (PARTICLE_SIZE / 2) * (mat[8] - mat[9]);
431 
432  // Don't update z-buffer, since all particles are transparent!
434 
437 
438  // Select particle texture
439  if (!wireframe)
440  {
443  }
444 
445  // Set up vertex arrays. We use interleaved arrays, which is easier to
446  // handle (in most situations) and it gives a linear memeory access
447  // access pattern (which may give better performance in some
448  // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords,
449  // 4 ubytes for color and 3 floats for vertex coord (in that order).
450  // Most OpenGL cards / drivers are optimized for this format.
451  glInterleavedArrays(GL_T2F_C4UB_V3F, 0, vertex_array);
452 
453  // Wait for particle physics thread to be done
454  mtx_lock(&thread_sync.particles_lock);
455  while (!glfwWindowShouldClose(window) &&
456  thread_sync.p_frame <= thread_sync.d_frame)
457  {
458  struct timespec ts;
459  clock_gettime(CLOCK_REALTIME, &ts);
460  ts.tv_nsec += 100 * 1000 * 1000;
461  ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
462  ts.tv_nsec %= 1000 * 1000 * 1000;
463  cnd_timedwait(&thread_sync.p_done, &thread_sync.particles_lock, &ts);
464  }
465 
466  // Store the frame time and delta time for the physics thread
467  thread_sync.t = t;
468  thread_sync.dt = dt;
469 
470  // Update frame counter
471  thread_sync.d_frame++;
472 
473  // Loop through all particles and build vertex arrays.
474  particle_count = 0;
475  vptr = vertex_array;
476  pptr = particles;
477 
478  for (i = 0; i < MAX_PARTICLES; i++)
479  {
480  if (pptr->active)
481  {
482  // Calculate particle intensity (we set it to max during 75%
483  // of its life, then it fades out)
484  alpha = 4.f * pptr->life;
485  if (alpha > 1.f)
486  alpha = 1.f;
487 
488  // Convert color from float to 8-bit (store it in a 32-bit
489  // integer using endian independent type casting)
490  ((GLubyte*) &rgba)[0] = (GLubyte)(pptr->r * 255.f);
491  ((GLubyte*) &rgba)[1] = (GLubyte)(pptr->g * 255.f);
492  ((GLubyte*) &rgba)[2] = (GLubyte)(pptr->b * 255.f);
493  ((GLubyte*) &rgba)[3] = (GLubyte)(alpha * 255.f);
494 
495  // 3) Translate the quad to the correct position in modelview
496  // space and store its parameters in vertex arrays (we also
497  // store texture coord and color information for each vertex).
498 
499  // Lower left corner
500  vptr->s = 0.f;
501  vptr->t = 0.f;
502  vptr->rgba = rgba;
503  vptr->x = pptr->x + quad_lower_left.x;
504  vptr->y = pptr->y + quad_lower_left.y;
505  vptr->z = pptr->z + quad_lower_left.z;
506  vptr ++;
507 
508  // Lower right corner
509  vptr->s = 1.f;
510  vptr->t = 0.f;
511  vptr->rgba = rgba;
512  vptr->x = pptr->x + quad_lower_right.x;
513  vptr->y = pptr->y + quad_lower_right.y;
514  vptr->z = pptr->z + quad_lower_right.z;
515  vptr ++;
516 
517  // Upper right corner
518  vptr->s = 1.f;
519  vptr->t = 1.f;
520  vptr->rgba = rgba;
521  vptr->x = pptr->x - quad_lower_left.x;
522  vptr->y = pptr->y - quad_lower_left.y;
523  vptr->z = pptr->z - quad_lower_left.z;
524  vptr ++;
525 
526  // Upper left corner
527  vptr->s = 0.f;
528  vptr->t = 1.f;
529  vptr->rgba = rgba;
530  vptr->x = pptr->x - quad_lower_right.x;
531  vptr->y = pptr->y - quad_lower_right.y;
532  vptr->z = pptr->z - quad_lower_right.z;
533  vptr ++;
534 
535  // Increase count of drawable particles
536  particle_count ++;
537  }
538 
539  // If we have filled up one batch of particles, draw it as a set
540  // of quads using glDrawArrays.
541  if (particle_count >= BATCH_PARTICLES)
542  {
543  // The first argument tells which primitive type we use (QUAD)
544  // The second argument tells the index of the first vertex (0)
545  // The last argument is the vertex count
546  glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count);
547  particle_count = 0;
548  vptr = vertex_array;
549  }
550 
551  // Next particle
552  pptr++;
553  }
554 
555  // We are done with the particle data
556  mtx_unlock(&thread_sync.particles_lock);
557  cnd_signal(&thread_sync.d_done);
558 
559  // Draw final batch of particles (if any)
560  glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count);
561 
562  // Disable vertex arrays (Note: glInterleavedArrays implicitly called
563  // glEnableClientState for vertex, texture coord and color arrays)
567 
570 
572 }
573 
574 
575 //========================================================================
576 // Fountain geometry specification
577 //========================================================================
578 
579 #define FOUNTAIN_SIDE_POINTS 14
580 #define FOUNTAIN_SWEEP_STEPS 32
581 
582 static const float fountain_side[FOUNTAIN_SIDE_POINTS * 2] =
583 {
584  1.2f, 0.f, 1.f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f,
585  0.4f, 1.95f, 0.41f, 2.f, 0.8f, 2.2f, 1.2f, 2.4f,
586  1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.f, 1.f, 3.f,
587  0.5f, 3.f, 0.f, 3.f
588 };
589 
590 static const float fountain_normal[FOUNTAIN_SIDE_POINTS * 2] =
591 {
592  1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f,
593  1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f,
594  0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f,
595  0.0000f,1.00000f, 0.0000f,1.00000f
596 };
597 
598 
599 //========================================================================
600 // Draw a fountain
601 //========================================================================
602 
603 static void draw_fountain(void)
604 {
605  static GLuint fountain_list = 0;
606  double angle;
607  float x, y;
608  int m, n;
609 
610  // The first time, we build the fountain display list
611  if (!fountain_list)
612  {
613  fountain_list = glGenLists(1);
614  glNewList(fountain_list, GL_COMPILE_AND_EXECUTE);
615 
619 
620  // Build fountain using triangle strips
621  for (n = 0; n < FOUNTAIN_SIDE_POINTS - 1; n++)
622  {
624  for (m = 0; m <= FOUNTAIN_SWEEP_STEPS; m++)
625  {
626  angle = (double) m * (2.0 * M_PI / (double) FOUNTAIN_SWEEP_STEPS);
627  x = (float) cos(angle);
628  y = (float) sin(angle);
629 
630  // Draw triangle strip
631  glNormal3f(x * fountain_normal[n * 2 + 2],
632  y * fountain_normal[n * 2 + 2],
633  fountain_normal[n * 2 + 3]);
634  glVertex3f(x * fountain_side[n * 2 + 2],
635  y * fountain_side[n * 2 + 2],
636  fountain_side[n * 2 +3 ]);
637  glNormal3f(x * fountain_normal[n * 2],
638  y * fountain_normal[n * 2],
639  fountain_normal[n * 2 + 1]);
640  glVertex3f(x * fountain_side[n * 2],
641  y * fountain_side[n * 2],
642  fountain_side[n * 2 + 1]);
643  }
644 
645  glEnd();
646  }
647 
648  glEndList();
649  }
650  else
651  glCallList(fountain_list);
652 }
653 
654 
655 //========================================================================
656 // Recursive function for building variable tesselated floor
657 //========================================================================
658 
659 static void tessellate_floor(float x1, float y1, float x2, float y2, int depth)
660 {
661  float delta, x, y;
662 
663  // Last recursion?
664  if (depth >= 5)
665  delta = 999999.f;
666  else
667  {
668  x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2));
669  y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2));
670  delta = x*x + y*y;
671  }
672 
673  // Recurse further?
674  if (delta < 0.1f)
675  {
676  x = (x1 + x2) * 0.5f;
677  y = (y1 + y2) * 0.5f;
678  tessellate_floor(x1, y1, x, y, depth + 1);
679  tessellate_floor(x, y1, x2, y, depth + 1);
680  tessellate_floor(x1, y, x, y2, depth + 1);
681  tessellate_floor(x, y, x2, y2, depth + 1);
682  }
683  else
684  {
685  glTexCoord2f(x1 * 30.f, y1 * 30.f);
686  glVertex3f( x1 * 80.f, y1 * 80.f, 0.f);
687  glTexCoord2f(x2 * 30.f, y1 * 30.f);
688  glVertex3f( x2 * 80.f, y1 * 80.f, 0.f);
689  glTexCoord2f(x2 * 30.f, y2 * 30.f);
690  glVertex3f( x2 * 80.f, y2 * 80.f, 0.f);
691  glTexCoord2f(x1 * 30.f, y2 * 30.f);
692  glVertex3f( x1 * 80.f, y2 * 80.f, 0.f);
693  }
694 }
695 
696 
697 //========================================================================
698 // Draw floor. We build the floor recursively and let the tessellation in the
699 // center (near x,y=0,0) be high, while the tessellation around the edges be
700 // low.
701 //========================================================================
702 
703 static void draw_floor(void)
704 {
705  static GLuint floor_list = 0;
706 
707  if (!wireframe)
708  {
711  }
712 
713  // The first time, we build the floor display list
714  if (!floor_list)
715  {
716  floor_list = glGenLists(1);
717  glNewList(floor_list, GL_COMPILE_AND_EXECUTE);
718 
722 
723  // Draw floor as a bunch of triangle strips (high tesselation
724  // improves lighting)
725  glNormal3f(0.f, 0.f, 1.f);
726  glBegin(GL_QUADS);
727  tessellate_floor(-1.f, -1.f, 0.f, 0.f, 0);
728  tessellate_floor( 0.f, -1.f, 1.f, 0.f, 0);
729  tessellate_floor( 0.f, 0.f, 1.f, 1.f, 0);
730  tessellate_floor(-1.f, 0.f, 0.f, 1.f, 0);
731  glEnd();
732 
733  glEndList();
734  }
735  else
736  glCallList(floor_list);
737 
739 
740 }
741 
742 
743 //========================================================================
744 // Position and configure light sources
745 //========================================================================
746 
747 static void setup_lights(void)
748 {
749  float l1pos[4], l1amb[4], l1dif[4], l1spec[4];
750  float l2pos[4], l2amb[4], l2dif[4], l2spec[4];
751 
752  // Set light source 1 parameters
753  l1pos[0] = 0.f; l1pos[1] = -9.f; l1pos[2] = 8.f; l1pos[3] = 1.f;
754  l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.f;
755  l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.f;
756  l1spec[0] = 1.f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.f;
757 
758  // Set light source 2 parameters
759  l2pos[0] = -15.f; l2pos[1] = 12.f; l2pos[2] = 1.5f; l2pos[3] = 1.f;
760  l2amb[0] = 0.f; l2amb[1] = 0.f; l2amb[2] = 0.f; l2amb[3] = 1.f;
761  l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.f;
762  l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.f; l2spec[3] = 0.f;
763 
765  glLightfv(GL_LIGHT1, GL_AMBIENT, l1amb);
766  glLightfv(GL_LIGHT1, GL_DIFFUSE, l1dif);
767  glLightfv(GL_LIGHT1, GL_SPECULAR, l1spec);
769  glLightfv(GL_LIGHT2, GL_AMBIENT, l2amb);
770  glLightfv(GL_LIGHT2, GL_DIFFUSE, l2dif);
771  glLightfv(GL_LIGHT2, GL_SPECULAR, l2spec);
775 
779 }
780 
781 
782 //========================================================================
783 // Main rendering function
784 //========================================================================
785 
786 static void draw_scene(GLFWwindow* window, double t)
787 {
788  double xpos, ypos, zpos, angle_x, angle_y, angle_z;
789  static double t_old = 0.0;
790  float dt;
791  mat4x4 projection;
792 
793  // Calculate frame-to-frame delta time
794  dt = (float) (t - t_old);
795  t_old = t;
796 
797  mat4x4_perspective(projection,
798  65.f * (float) M_PI / 180.f,
799  aspect_ratio,
800  1.0, 60.0);
801 
802  glClearColor(0.1f, 0.1f, 0.1f, 1.f);
804 
806  glLoadMatrixf((const GLfloat*) projection);
807 
808  // Setup camera
810  glLoadIdentity();
811 
812  // Rotate camera
813  angle_x = 90.0 - 10.0;
814  angle_y = 10.0 * sin(0.3 * t);
815  angle_z = 10.0 * t;
816  glRotated(-angle_x, 1.0, 0.0, 0.0);
817  glRotated(-angle_y, 0.0, 1.0, 0.0);
818  glRotated(-angle_z, 0.0, 0.0, 1.0);
819 
820  // Translate camera
821  xpos = 15.0 * sin((M_PI / 180.0) * angle_z) +
822  2.0 * sin((M_PI / 180.0) * 3.1 * t);
823  ypos = -15.0 * cos((M_PI / 180.0) * angle_z) +
824  2.0 * cos((M_PI / 180.0) * 2.9 * t);
825  zpos = 4.0 + 2.0 * cos((M_PI / 180.0) * 4.9 * t);
826  glTranslated(-xpos, -ypos, -zpos);
827 
831 
832  setup_lights();
834 
835  glEnable(GL_FOG);
837  glFogf(GL_FOG_DENSITY, 0.05f);
839 
840  draw_floor();
841 
845 
846  draw_fountain();
847 
849  glDisable(GL_FOG);
850 
851  // Particles must be drawn after all solid objects have been drawn
852  draw_particles(window, t, dt);
853 
854  // Z-buffer not needed anymore
856 }
857 
858 
859 //========================================================================
860 // Window resize callback function
861 //========================================================================
862 
864 {
865  glViewport(0, 0, width, height);
866  aspect_ratio = height ? width / (float) height : 1.f;
867 }
868 
869 
870 //========================================================================
871 // Key callback functions
872 //========================================================================
873 
874 static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
875 {
876  if (action == GLFW_PRESS)
877  {
878  switch (key)
879  {
880  case GLFW_KEY_ESCAPE:
882  break;
883  case GLFW_KEY_W:
884  wireframe = !wireframe;
887  break;
888  default:
889  break;
890  }
891  }
892 }
893 
894 
895 //========================================================================
896 // Thread for updating particle physics
897 //========================================================================
898 
899 static int physics_thread_main(void* arg)
900 {
901  GLFWwindow* window = arg;
902 
903  for (;;)
904  {
905  mtx_lock(&thread_sync.particles_lock);
906 
907  // Wait for particle drawing to be done
908  while (!glfwWindowShouldClose(window) &&
909  thread_sync.p_frame > thread_sync.d_frame)
910  {
911  struct timespec ts;
912  clock_gettime(CLOCK_REALTIME, &ts);
913  ts.tv_nsec += 100 * 1000 * 1000;
914  ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
915  ts.tv_nsec %= 1000 * 1000 * 1000;
916  cnd_timedwait(&thread_sync.d_done, &thread_sync.particles_lock, &ts);
917  }
918 
919  if (glfwWindowShouldClose(window))
920  break;
921 
922  // Update particles
924 
925  // Update frame counter
926  thread_sync.p_frame++;
927 
928  // Unlock mutex and signal drawing thread
929  mtx_unlock(&thread_sync.particles_lock);
930  cnd_signal(&thread_sync.p_done);
931  }
932 
933  return 0;
934 }
935 
936 
937 //========================================================================
938 // main
939 //========================================================================
940 
941 int main(int argc, char** argv)
942 {
943  int ch, width, height;
944  thrd_t physics_thread = 0;
946  GLFWmonitor* monitor = NULL;
947 
948  if (!glfwInit())
949  {
950  fprintf(stderr, "Failed to initialize GLFW\n");
951  exit(EXIT_FAILURE);
952  }
953 
954  while ((ch = getopt(argc, argv, "fh")) != -1)
955  {
956  switch (ch)
957  {
958  case 'f':
959  monitor = glfwGetPrimaryMonitor();
960  break;
961  case 'h':
962  usage();
963  exit(EXIT_SUCCESS);
964  }
965  }
966 
967  if (monitor)
968  {
969  const GLFWvidmode* mode = glfwGetVideoMode(monitor);
970 
975 
976  width = mode->width;
977  height = mode->height;
978  }
979  else
980  {
981  width = 640;
982  height = 480;
983  }
984 
985  window = glfwCreateWindow(width, height, "Particle Engine", monitor, NULL);
986  if (!window)
987  {
988  fprintf(stderr, "Failed to create GLFW window\n");
989  glfwTerminate();
990  exit(EXIT_FAILURE);
991  }
992 
993  if (monitor)
995 
996  glfwMakeContextCurrent(window);
998  glfwSwapInterval(1);
999 
1002 
1003  // Set initial aspect ratio
1004  glfwGetFramebufferSize(window, &width, &height);
1005  resize_callback(window, width, height);
1006 
1007  // Upload particle texture
1017 
1018  // Upload floor texture
1028 
1029  if (glfwExtensionSupported("GL_EXT_separate_specular_color"))
1030  {
1033  }
1034 
1035  // Set filled polygon mode as default (not wireframe)
1037  wireframe = 0;
1038 
1039  // Set initial times
1040  thread_sync.t = 0.0;
1041  thread_sync.dt = 0.001f;
1042  thread_sync.p_frame = 0;
1043  thread_sync.d_frame = 0;
1044 
1045  mtx_init(&thread_sync.particles_lock, mtx_timed);
1046  cnd_init(&thread_sync.p_done);
1047  cnd_init(&thread_sync.d_done);
1048 
1049  if (thrd_create(&physics_thread, physics_thread_main, window) != thrd_success)
1050  {
1051  glfwTerminate();
1052  exit(EXIT_FAILURE);
1053  }
1054 
1055  glfwSetTime(0.0);
1056 
1057  while (!glfwWindowShouldClose(window))
1058  {
1059  draw_scene(window, glfwGetTime());
1060 
1061  glfwSwapBuffers(window);
1062  glfwPollEvents();
1063  }
1064 
1065  thrd_join(physics_thread, NULL);
1066 
1067  glfwDestroyWindow(window);
1068  glfwTerminate();
1069 
1070  exit(EXIT_SUCCESS);
1071 }
1072 
int redBits
Definition: glfw3.h:1535
#define glDisableClientState
GLFWAPI void glfwSetInputMode(GLFWwindow *window, int mode, int value)
Sets an input option for the specified window.
Definition: input.c:484
#define GL_TEXTURE_MAG_FILTER
static float glow_pos[4]
Definition: particles.c:205
static int physics_thread_main(void *arg)
Definition: particles.c:899
#define glLightfv
#define GL_LEQUAL
int height
Definition: glfw3.h:1532
GLboolean GLboolean GLboolean b
GLboolean GLboolean g
GLint y
#define GL_SHININESS
GLfloat t
Definition: particles.c:71
vec4 mat4x4[4]
Definition: linmath.h:83
khronos_float_t GLfloat
int blueBits
Definition: glfw3.h:1541
cnd_t d_done
Definition: particles.c:94
#define GL_VERTEX_ARRAY
int wireframe
Definition: particles.c:85
The header of the GLFW 3 API.
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Definition: tinycthread.c:294
float y
Definition: particles.c:59
GLFWAPI GLFWglproc glfwGetProcAddress(const char *procname)
Returns the address of the specified function for the current context.
Definition: context.c:741
#define GL_ONE
GLdouble s
#define GL_TEXTURE_2D
#define P_TEX_HEIGHT
Definition: particles.c:105
#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT
Definition: particles.c:47
#define glFogfv
const GLfloat floor_shininess
Definition: particles.c:217
#define glDepthFunc
GLfloat x
Definition: particles.c:73
#define GL_TRIANGLE_STRIP
#define glBegin
GLfloat GLfloat p
Definition: glext.h:12687
int mtx_init(mtx_t *mtx, int type)
Definition: tinycthread.c:56
void *(* GLADloadproc)(const char *name)
const GLfloat * m
Definition: glext.h:6814
float vx
Definition: particles.c:188
static GLFWwindow * window
Definition: joysticks.c:55
#define F_TEX_HEIGHT
Definition: particles.c:107
#define GL_UNSIGNED_BYTE
GLfloat y
Definition: particles.c:73
#define glDepthMask
pthread_cond_t cnd_t
Definition: tinycthread.h:252
#define PARTICLE_VERTS
Definition: particles.c:391
GLdouble GLdouble GLdouble y2
mtx_t particles_lock
Definition: particles.c:95
static void init_particle(PARTICLE *p, double t)
Definition: particles.c:243
double vy[GRIDW][GRIDH]
Definition: wave.c:110
int width
Definition: glfw3.h:1529
#define P_TEX_WIDTH
Definition: particles.c:104
#define glMaterialfv
static void particle_engine(double t, float dt)
Definition: particles.c:345
#define GL_LINE
#define GL_PROJECTION
#define glFrontFace
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Definition: tinycthread.c:361
GLFWAPI const GLFWvidmode * glfwGetVideoMode(GLFWmonitor *monitor)
Returns the current mode of the specified monitor.
Definition: monitor.c:417
#define GL_BACK
#define GLFW_CURSOR
Definition: glfw3.h:1001
#define glDrawArrays
struct GLFWmonitor GLFWmonitor
#define FOUNTAIN_HEIGHT
Definition: particles.c:172
float b
Definition: particles.c:189
#define BATCH_PARTICLES
Definition: particles.c:388
#define glCullFace
#define GLFW_REFRESH_RATE
Monitor refresh rate hint.
Definition: glfw3.h:903
#define glFogf
GLfloat angle
Definition: glext.h:6819
static void resize_callback(GLFWwindow *window, int width, int height)
Definition: particles.c:863
GLint GLint GLsizei GLsizei GLsizei depth
int refreshRate
Definition: glfw3.h:1544
const GLfloat fountain_diffuse[4]
Definition: particles.c:212
GLuint particle_tex_id
Definition: particles.c:110
#define BIRTH_INTERVAL
Definition: particles.c:157
GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow *window, GLFWframebuffersizefun cbfun)
Sets the framebuffer resize callback for the specified window.
Definition: window.c:1050
#define GL_BLEND
#define GL_LINEAR
#define glPolygonMode
#define glLoadIdentity
Definition: arg_fwd.hpp:23
#define GL_LIGHT3
#define glLightModeli
int getopt(int argc, char *const argv[], const char *optstring)
Definition: getopt.c:52
GLdouble n
Definition: glext.h:1966
#define glTexImage2D
#define GL_CLAMP
#define glVertex3f
#define GL_SRC_ALPHA
#define FOUNTAIN_SIDE_POINTS
Definition: particles.c:579
float z
Definition: particles.c:59
#define glEnable
static void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
Definition: linmath.h:357
#define GL_LUMINANCE
#define glGetFloatv
#define GL_FOG_COLOR
static void draw_scene(GLFWwindow *window, double t)
Definition: particles.c:786
#define GL_TEXTURE_WRAP_T
static void usage(void)
Definition: particles.c:225
float x
Definition: particles.c:59
khronos_uint8_t GLubyte
#define PARTICLE_SIZE
Definition: particles.c:160
Definition: particles.c:57
int greenBits
Definition: glfw3.h:1538
static const float fountain_normal[FOUNTAIN_SIDE_POINTS *2]
Definition: particles.c:590
GLdouble t
float y
Definition: particles.c:187
GLuint64 key
Definition: glext.h:8966
#define GL_LIGHTING
#define GLFW_CURSOR_DISABLED
Definition: glfw3.h:1008
int main(int argc, char **argv)
Definition: particles.c:941
#define GL_FOG_DENSITY
float z
Definition: particles.c:187
GLFWAPI int glfwInit(void)
Initializes the GLFW library.
Definition: init.c:198
GLdouble f
#define glInterleavedArrays
#define GLFW_RED_BITS
Framebuffer bit depth hint.
Definition: glfw3.h:833
static void draw_fountain(void)
Definition: particles.c:603
GLenum mode
#define GL_SPECULAR
int active
Definition: particles.c:191
GLfloat GLfloat GLfloat alpha
static void tessellate_floor(float x1, float y1, float x2, float y2, int depth)
Definition: particles.c:659
#define glGenTextures
int mtx_unlock(mtx_t *mtx)
Definition: tinycthread.c:124
#define glEndList
cnd_t p_done
Definition: particles.c:93
#define GL_COLOR_BUFFER_BIT
#define glTexParameteri
#define GL_DIFFUSE
#define GL_FRONT_AND_BACK
#define GRAVITY
Definition: particles.c:163
int cnd_init(cnd_t *cond)
Definition: tinycthread.c:140
#define GL_FOG_MODE
static const float fountain_side[FOUNTAIN_SIDE_POINTS *2]
Definition: particles.c:582
GLdouble x
#define GL_LIGHT1
GLFWAPI void glfwSwapInterval(int interval)
Sets the swap interval for the current context.
Definition: context.c:658
GLdouble GLdouble x2
#define GL_SEPARATE_SPECULAR_COLOR_EXT
Definition: particles.c:49
#define glLoadMatrixf
#define GL_UNPACK_ALIGNMENT
#define GLFW_KEY_ESCAPE
Definition: glfw3.h:412
#define glPixelStorei
#define glClear
GLint GLsizei GLsizei height
#define LIFE_SPAN
Definition: particles.c:154
float vz
Definition: particles.c:188
GLFWAPI void glfwSwapBuffers(GLFWwindow *window)
Swaps the front and back buffers of the specified window.
Definition: context.c:641
GLFWAPI void glfwMakeContextCurrent(GLFWwindow *window)
Makes the context of the specified window current for the calling thread.
Definition: context.c:611
#define GL_REPEAT
#define GL_TEXTURE_MIN_FILTER
#define GLFW_KEY_W
Definition: glfw3.h:400
#define GL_QUADS
static float min_age
Definition: particles.c:199
#define glTranslated
#define glNormal3f
const GLfloat fog_color[4]
Definition: particles.c:218
#define glEnd
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
Definition: particles.c:874
#define FOUNTAIN_R2
Definition: particles.c:291
static void draw_particles(GLFWwindow *window, double t, float dt)
Definition: particles.c:393
int thrd_join(thrd_t thr, int *res)
Definition: tinycthread.c:432
#define glGenLists
#define GLFW_GREEN_BITS
Framebuffer bit depth hint.
Definition: glfw3.h:838
#define GL_FILL
#define GL_TRUE
const GLfloat floor_specular[4]
Definition: particles.c:216
#define GL_FRONT
action
Definition: enums.py:62
GLAPI int gladLoadGLLoader(GLADloadproc)
Definition: glad/glad.c:1697
#define glViewport
#define GL_POSITION
#define GL_DEPTH_BUFFER_BIT
#define glTexCoord2f
#define GL_MODELVIEW
static const textual_icon exit
Definition: model-views.h:254
GLfloat z
Definition: particles.c:73
int d_frame
Definition: particles.c:92
GLFWAPI void glfwSetWindowShouldClose(GLFWwindow *window, int value)
Sets the close flag of the specified window.
Definition: window.c:486
float g
Definition: particles.c:189
#define FOUNTAIN_SWEEP_STEPS
Definition: particles.c:580
GLFWAPI void glfwSetTime(double time)
Sets the GLFW timer.
Definition: input.c:1282
GLFWAPI GLFWwindow * glfwCreateWindow(int width, int height, const char *title, GLFWmonitor *monitor, GLFWwindow *share)
Creates a window and its associated context.
Definition: window.c:151
float x
Definition: particles.c:187
pthread_mutex_t mtx_t
Definition: tinycthread.h:191
#define GLFW_TRUE
One.
Definition: glfw3.h:279
const unsigned char floor_texture[F_TEX_WIDTH *F_TEX_HEIGHT]
Definition: particles.c:125
#define GL_FALSE
#define GL_EXP
GLuint GLfloat GLfloat GLfloat x1
Definition: glext.h:9721
static void setup_lights(void)
Definition: particles.c:747
#define VELOCITY
Definition: particles.c:166
#define GL_CULL_FACE
GLFWAPI double glfwGetTime(void)
Returns the value of the GLFW timer.
Definition: input.c:1275
#define GL_COMPILE_AND_EXECUTE
Video mode type.
Definition: glfw3.h:1525
unsigned int GLuint
#define GL_AMBIENT
GLuint floor_tex_id
Definition: particles.c:110
double t_old
Definition: boing.c:105
int cnd_signal(cnd_t *cond)
Definition: tinycthread.c:186
double t
Definition: particles.c:89
static double xpos
Definition: splitview.c:33
GLFWAPI GLFWmonitor * glfwGetPrimaryMonitor(void)
Returns the primary monitor.
Definition: monitor.c:308
GLFWAPI void glfwDestroyWindow(GLFWwindow *window)
Destroys the specified window and its context.
Definition: window.c:444
GLFWAPI void glfwGetFramebufferSize(GLFWwindow *window, int *width, int *height)
Retrieves the size of the framebuffer of the specified window.
Definition: window.c:647
#define FRICTION
Definition: particles.c:169
#define glBindTexture
const unsigned char particle_texture[P_TEX_WIDTH *P_TEX_HEIGHT]
Definition: particles.c:113
const GLfloat fountain_shininess
Definition: particles.c:214
GLfloat s
Definition: particles.c:71
GLFWAPI void glfwTerminate(void)
Terminates the GLFW library.
Definition: init.c:243
float dt
Definition: particles.c:90
#define GL_COLOR_ARRAY
#define glFogi
#define GL_MODELVIEW_MATRIX
#define glClearColor
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow *window, GLFWkeyfun cbfun)
Sets the key callback.
Definition: input.c:791
GLFWAPI void glfwPollEvents(void)
Processes all pending events.
Definition: window.c:1072
pthread_t thrd_t
Definition: tinycthread.h:317
#define MIN_DELTA_T
Definition: particles.c:178
#define glCallList
double vx[GRIDW][GRIDH]
Definition: wave.c:110
#define GLFW_BLUE_BITS
Framebuffer bit depth hint.
Definition: glfw3.h:843
#define NULL
Definition: tinycthread.c:47
#define glNewList
float aspect_ratio
Definition: particles.c:82
#define glMaterialf
int i
#define glRotated
#define F_TEX_WIDTH
Definition: particles.c:106
GLFWAPI int glfwExtensionSupported(const char *extension)
Returns whether the specified extension is available.
Definition: context.c:675
#define MAX_PARTICLES
Definition: particles.c:151
#define GL_LIGHT2
static void draw_floor(void)
Definition: particles.c:703
int p_frame
Definition: particles.c:91
#define GL_CCW
#define glBlendFunc
static void update_particle(PARTICLE *p, float dt)
Definition: particles.c:293
int mtx_lock(mtx_t *mtx)
Definition: tinycthread.c:86
const GLfloat floor_diffuse[4]
Definition: particles.c:215
#define GL_TEXTURE_COORD_ARRAY
#define mtx_timed
Definition: tinycthread.h:179
#define GLFW_PRESS
The key or mouse button was pressed.
Definition: glfw3.h:304
const GLfloat fountain_specular[4]
Definition: particles.c:213
GLuint rgba
Definition: particles.c:72
#define GL_TEXTURE_WRAP_S
static float glow_color[4]
Definition: particles.c:202
#define thrd_success
Definition: tinycthread.h:172
GLdouble y1
#define glMatrixMode
float r
Definition: particles.c:189
struct GLFWwindow GLFWwindow
GLFWAPI void glfwWindowHint(int hint, int value)
Sets the specified window hint to the desired value.
Definition: window.c:291
static PARTICLE particles[MAX_PARTICLES]
Definition: particles.c:196
GLint GLsizei width
#define GL_DEPTH_TEST
static double ypos
Definition: splitview.c:33
#define GL_FOG
float vy
Definition: particles.c:188
#define glDisable
float life
Definition: particles.c:190
GLFWAPI int glfwWindowShouldClose(GLFWwindow *window)
Checks the close flag of the specified window.
Definition: window.c:477
#define GL_T2F_C4UB_V3F
struct @19 thread_sync


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:39