SDL  2.0
fireworks.c
Go to the documentation of this file.
1 /*
2  * fireworks.c
3  * written by Holmes Futrell
4  * use however you want
5  */
6 
7 #include "SDL.h"
8 #include "SDL_opengles.h"
9 #include "common.h"
10 #include <math.h>
11 #include <time.h>
12 
13 #define ACCEL 0.0001f /* acceleration due to gravity, units in pixels per millesecond squared */
14 #define WIND_RESISTANCE 0.00005f /* acceleration per unit velocity due to wind resistance */
15 #define MAX_PARTICLES 2000 /* maximum number of particles displayed at once */
16 
17 static GLuint particleTextureID; /* OpenGL particle texture id */
18 static SDL_bool pointSizeExtensionSupported; /* is GL_OES_point_size_array supported ? */
19 static float pointSizeScale;
20 /*
21  used to describe what type of particle a given struct particle is.
22  emitter - this particle flies up, shooting off trail particles, then finally explodes into dust particles.
23  trail - shoots off, following emitter particle
24  dust - radiates outwards from emitter explosion
25 */
27 {
28  emitter = 0,
31 };
32 /*
33  struct particle is used to describe each particle displayed on screen
34 */
35 struct particle
36 {
37  GLfloat x; /* x position of particle */
38  GLfloat y; /* y position of particle */
39  GLubyte color[4]; /* rgba color of particle */
40  GLfloat size; /* size of particle in pixels */
41  GLfloat xvel; /* x velocity of particle in pixels per milesecond */
42  GLfloat yvel; /* y velocity of particle in pixels per millescond */
43  int isActive; /* if not active, then particle is overwritten */
44  enum particleType type; /* see enum particleType */
45 } particles[MAX_PARTICLES]; /* this array holds all our particles */
46 
47 static int num_active_particles; /* how many members of the particle array are actually being drawn / animated? */
48 static int screen_w, screen_h;
49 
50 /* function declarations */
53 void explodeEmitter(struct particle *emitter);
54 void initializeParticles(void);
55 void initializeTexture();
56 int nextPowerOfTwo(int x);
57 void drawParticles();
58 void stepParticles(double deltaTime);
59 
60 /* helper function (used in texture loading)
61  returns next power of two greater than or equal to x
62 */
63 int
65 {
66  int val = 1;
67  while (val < x) {
68  val *= 2;
69  }
70  return val;
71 }
72 
73 /*
74  steps each active particle by timestep deltaTime
75 */
76 void
77 stepParticles(double deltaTime)
78 {
79  float deltaMilliseconds = deltaTime * 1000;
80  int i;
81  struct particle *slot = particles;
82  struct particle *curr = particles;
83  for (i = 0; i < num_active_particles; i++) {
84  /* is the particle actually active, or is it marked for deletion? */
85  if (curr->isActive) {
86  /* is the particle off the screen? */
87  if (curr->y > screen_h)
88  curr->isActive = 0;
89  else if (curr->y < 0)
90  curr->isActive = 0;
91  if (curr->x > screen_w)
92  curr->isActive = 0;
93  else if (curr->x < 0)
94  curr->isActive = 0;
95 
96  /* step velocity, then step position */
97  curr->yvel += ACCEL * deltaMilliseconds;
98  curr->xvel += 0.0f;
99  curr->y += curr->yvel * deltaMilliseconds;
100  curr->x += curr->xvel * deltaMilliseconds;
101 
102  /* particle behavior */
103  if (curr->type == emitter) {
104  /* if we're an emitter, spawn a trail */
105  spawnTrailFromEmitter(curr);
106  /* if we've reached our peak, explode */
107  if (curr->yvel > 0.0) {
108  explodeEmitter(curr);
109  }
110  } else {
111  float speed =
112  sqrt(curr->xvel * curr->xvel + curr->yvel * curr->yvel);
113  /* if wind resistance is not powerful enough to stop us completely,
114  then apply winde resistance, otherwise just stop us completely */
115  if (WIND_RESISTANCE * deltaMilliseconds < speed) {
116  float normx = curr->xvel / speed;
117  float normy = curr->yvel / speed;
118  curr->xvel -=
119  normx * WIND_RESISTANCE * deltaMilliseconds;
120  curr->yvel -=
121  normy * WIND_RESISTANCE * deltaMilliseconds;
122  } else {
123  curr->xvel = curr->yvel = 0; /* stop particle */
124  }
125 
126  if (curr->color[3] <= deltaMilliseconds * 0.1275f) {
127  /* if this next step will cause us to fade out completely
128  then just mark for deletion */
129  curr->isActive = 0;
130  } else {
131  /* otherwise, let's fade a bit more */
132  curr->color[3] -= deltaMilliseconds * 0.1275f;
133  }
134 
135  /* if we're a dust particle, shrink our size */
136  if (curr->type == dust)
137  curr->size -= deltaMilliseconds * 0.010f;
138 
139  }
140 
141  /* if we're still active, pack ourselves in the array next
142  to the last active guy (pack the array tightly) */
143  if (curr->isActive)
144  *(slot++) = *curr;
145  } /* endif (curr->isActive) */
146  curr++;
147  }
148  /* the number of active particles is computed as the difference between
149  old number of active particles, where slot points, and the
150  new size of the array, where particles points */
151  num_active_particles = (int) (slot - particles);
152 }
153 
154 /*
155  This draws all the particles shown on screen
156 */
157 void
159 {
160 
161  /* draw the background */
163 
164  /* set up the position and color pointers */
165  glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles);
166  glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct particle),
167  particles[0].color);
168 
170  /* pass in our array of point sizes */
171  glPointSizePointerOES(GL_FLOAT, sizeof(struct particle),
172  &(particles[0].size));
173  }
174 
175  /* draw our particles! */
177 
178 }
179 
180 /*
181  This causes an emitter to explode in a circular bloom of dust particles
182 */
183 void
185 {
186  /* first off, we're done with this particle, so turn active off */
187  emitter->isActive = 0;
188  int i;
189  for (i = 0; i < 200; i++) {
190 
192  return;
193 
194  /* come up with a random angle and speed for new particle */
195  float theta = randomFloat(0, 2.0f * 3.141592);
196  float exponent = 3.0f;
197  float speed = randomFloat(0.00, powf(0.17, exponent));
198  speed = powf(speed, 1.0f / exponent);
199 
200  /* select the particle at the end of our array */
202 
203  /* set the particles properties */
204  p->xvel = speed * cos(theta);
205  p->yvel = speed * sin(theta);
206  p->x = emitter->x + emitter->xvel;
207  p->y = emitter->y + emitter->yvel;
208  p->isActive = 1;
209  p->type = dust;
210  p->size = 15 * pointSizeScale;
211  /* inherit emitter's color */
212  p->color[0] = emitter->color[0];
213  p->color[1] = emitter->color[1];
214  p->color[2] = emitter->color[2];
215  p->color[3] = 255;
216  /* our array has expanded at the end */
218  }
219 
220 }
221 
222 /*
223  This spawns a trail particle from an emitter
224 */
225 void
227 {
228 
230  return;
231 
232  /* select the particle at the slot at the end of our array */
234 
235  /* set position and velocity to roughly that of the emitter */
236  p->x = emitter->x + randomFloat(-3.0, 3.0);
237  p->y = emitter->y + emitter->size / 2.0f;
238  p->xvel = emitter->xvel + randomFloat(-0.005, 0.005);
239  p->yvel = emitter->yvel + 0.1;
240 
241  /* set the color to a random-ish orangy type color */
242  p->color[0] = (0.8f + randomFloat(-0.1, 0.0)) * 255;
243  p->color[1] = (0.4f + randomFloat(-0.1, 0.1)) * 255;
244  p->color[2] = (0.0f + randomFloat(0.0, 0.2)) * 255;
245  p->color[3] = (0.7f) * 255;
246 
247  /* set other attributes */
248  p->size = 10 * pointSizeScale;
249  p->type = trail;
250  p->isActive = 1;
251 
252  /* our array has expanded at the end */
254 
255 }
256 
257 /*
258  spawns a new emitter particle at the bottom of the screen
259  destined for the point (x,y).
260 */
261 void
263 {
264 
266  return;
267 
268  /* find particle at endpoint of array */
270 
271  /* set the color randomly */
272  switch (rand() % 4) {
273  case 0:
274  p->color[0] = 255;
275  p->color[1] = 100;
276  p->color[2] = 100;
277  break;
278  case 1:
279  p->color[0] = 100;
280  p->color[1] = 255;
281  p->color[2] = 100;
282  break;
283  case 2:
284  p->color[0] = 100;
285  p->color[1] = 100;
286  p->color[2] = 255;
287  break;
288  case 3:
289  p->color[0] = 255;
290  p->color[1] = 150;
291  p->color[2] = 50;
292  break;
293  }
294  p->color[3] = 255;
295  /* set position to (x, screen_h) */
296  p->x = x;
297  p->y = screen_h;
298  /* set velocity so that terminal point is (x,y) */
299  p->xvel = 0;
300  p->yvel = -sqrt(2 * ACCEL * (screen_h - y));
301  /* set other attributes */
302  p->size = 10 * pointSizeScale;
303  p->type = emitter;
304  p->isActive = 1;
305  /* our array has expanded at the end */
307 }
308 
309 /* just sets the endpoint of the particle array to element zero */
310 void
312 {
314 }
315 
316 /*
317  loads the particle texture
318  */
319 void
321 {
322 
323  int bpp; /* texture bits per pixel */
324  Uint32 Rmask, Gmask, Bmask, Amask; /* masks for pixel format passed into OpenGL */
325  SDL_Surface *bmp_surface; /* the bmp is loaded here */
326  SDL_Surface *bmp_surface_rgba8888; /* this serves as a destination to convert the BMP
327  to format passed into OpenGL */
328 
329  bmp_surface = SDL_LoadBMP("stroke.bmp");
330  if (bmp_surface == NULL) {
331  fatalError("could not load stroke.bmp");
332  }
333 
334  /* Grab info about format that will be passed into OpenGL */
336  &Bmask, &Amask);
337  /* Create surface that will hold pixels passed into OpenGL */
338  bmp_surface_rgba8888 =
339  SDL_CreateRGBSurface(0, bmp_surface->w, bmp_surface->h, bpp, Rmask,
340  Gmask, Bmask, Amask);
341  /* Blit to this surface, effectively converting the format */
342  SDL_BlitSurface(bmp_surface, NULL, bmp_surface_rgba8888, NULL);
343 
347  nextPowerOfTwo(bmp_surface->w),
348  nextPowerOfTwo(bmp_surface->h),
352  /* this is where we actually pass in the pixel data */
353  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmp_surface->w, bmp_surface->h, 0,
354  GL_RGBA, GL_UNSIGNED_BYTE, bmp_surface_rgba8888->pixels);
355 
356  /* free bmp surface and converted bmp surface */
357  SDL_FreeSurface(bmp_surface);
358  SDL_FreeSurface(bmp_surface_rgba8888);
359 
360 }
361 
362 int
363 main(int argc, char *argv[])
364 {
365  SDL_Window *window; /* main window */
367  int drawableW, drawableH;
368  int done; /* should we clean up and exit? */
369 
370  /* initialize SDL */
371  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
372  fatalError("Could not initialize SDL");
373  }
374  /* seed the random number generator */
375  srand(time(NULL));
376  /*
377  request some OpenGL parameters
378  that may speed drawing
379  */
387 
390 
391  /* create main window and renderer */
392  window = SDL_CreateWindow(NULL, 0, 0, 320, 480,
394  context = SDL_GL_CreateContext(window);
395 
396  /* The window size and drawable size may be different when highdpi is enabled,
397  * due to the increased pixel density of the drawable. */
398  SDL_GetWindowSize(window, &screen_w, &screen_h);
399  SDL_GL_GetDrawableSize(window, &drawableW, &drawableH);
400 
401  /* In OpenGL, point sizes are always in pixels. We don't want them looking
402  * tiny on a retina screen. */
403  pointSizeScale = (float) drawableH / (float) screen_h;
404 
405  /* load the particle texture */
407 
408  /* check if GL_POINT_SIZE_ARRAY_OES is supported
409  this is used to give each particle its own size
410  */
412  SDL_GL_ExtensionSupported("GL_OES_point_size_array");
413 
414  /* set up some OpenGL state */
417 
419  glLoadIdentity();
420 
421  glViewport(0, 0, drawableW, drawableH);
422 
424  glLoadIdentity();
425  glOrthof((GLfloat) 0,
426  (GLfloat) screen_w,
427  (GLfloat) screen_h,
428  (GLfloat) 0, 0.0, 1.0);
429 
435 
436  glEnable(GL_POINT_SPRITE_OES);
437  glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
438 
440  /* we use this to set the sizes of all the particles */
441  glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
442  } else {
443  /* if extension not available then all particles have size 10 */
445  }
446 
447  done = 0;
448  /* enter main loop */
449  while (!done) {
451  double deltaTime = updateDeltaTime();
452  while (SDL_PollEvent(&event)) {
453  if (event.type == SDL_QUIT) {
454  done = 1;
455  }
456  if (event.type == SDL_MOUSEBUTTONDOWN) {
457  int x, y;
458  SDL_GetMouseState(&x, &y);
459  spawnEmitterParticle(x, y);
460  }
461  }
462  stepParticles(deltaTime);
463  drawParticles();
464  SDL_GL_SwapWindow(window);
465  SDL_Delay(1);
466  }
467 
468  /* delete textures */
470  /* shutdown SDL */
471  SDL_Quit();
472 
473  return 0;
474 }
#define GL_ONE
Definition: SDL_opengl.h:401
GLAPI void GLAPIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
#define SDL_GL_ExtensionSupported
#define SDL_PollEvent
double updateDeltaTime(void)
Definition: common.c:42
EGLSurface EGLnsecsANDROID time
Definition: eglext.h:518
int nextPowerOfTwo(int x)
Definition: fireworks.c:64
#define SDL_GL_CreateContext
#define SDL_LoadBMP(file)
Definition: SDL_surface.h:200
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLfloat yvel
Definition: fireworks.c:42
void fatalError(const char *string)
Definition: common.c:32
#define WIND_RESISTANCE
Definition: fireworks.c:14
#define GL_PROJECTION
Definition: SDL_opengl.h:272
GLAPI void GLAPIENTRY glDisable(GLenum cap)
#define GL_LINEAR
Definition: SDL_opengl.h:447
GLAPI void GLAPIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
GLfloat GLfloat p
GLAPI void GLAPIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
#define GL_RGBA
Definition: SDL_opengl.h:529
static screen_context_t context
Definition: video.c:25
#define SDL_BlitSurface
Definition: SDL_surface.h:483
GLfloat f
GLAPI void GLAPIENTRY glDeleteTextures(GLsizei n, const GLuint *textures)
GLAPI void GLAPIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param)
#define GL_TEXTURE_MAG_FILTER
Definition: SDL_opengl.h:674
void stepParticles(double deltaTime)
Definition: fireworks.c:77
GLAPI void GLAPIENTRY glEnableClientState(GLenum cap)
#define SDL_CreateWindow
static int num_active_particles
Definition: fireworks.c:47
float GLfloat
Definition: SDL_opengl.h:187
static SDL_bool pointSizeExtensionSupported
Definition: fireworks.c:18
struct particle particles[MAX_PARTICLES]
void initializeParticles(void)
Definition: fireworks.c:311
GLAPI void GLAPIENTRY glEnable(GLenum cap)
static int screen_w
Definition: fireworks.c:48
#define GL_BLEND
Definition: SDL_opengl.h:397
static int screen_h
Definition: fireworks.c:48
void explodeEmitter(struct particle *emitter)
Definition: fireworks.c:184
Definition: fireworks.c:30
float randomFloat(float min, float max)
Definition: common.c:26
#define SDL_GL_SetAttribute
#define SDL_GetWindowSize
GLAPI void GLAPIENTRY glBindTexture(GLenum target, GLuint texture)
void drawParticles()
Definition: fireworks.c:158
particleType
Definition: fireworks.c:26
#define SDL_GL_GetDrawableSize
void * SDL_GLContext
An opaque handle to an OpenGL context.
Definition: SDL_video.h:193
GLuint GLfloat * val
static GLuint particleTextureID
Definition: fireworks.c:17
#define GL_COLOR_ARRAY
Definition: SDL_opengl.h:230
GLAPI void GLAPIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count)
void * pixels
Definition: SDL_surface.h:75
#define SDL_FreeSurface
struct _cl_event * event
#define SDL_Quit
int done
Definition: checkkeys.c:28
GLAPI void GLAPIENTRY glGenTextures(GLsizei n, GLuint *textures)
#define GL_FLOAT
Definition: SDL_opengl.h:209
#define GL_TEXTURE_2D
Definition: SDL_opengl.h:671
#define GL_UNSIGNED_BYTE
Definition: SDL_opengl.h:204
GLAPI void GLAPIENTRY glClear(GLbitfield mask)
#define ACCEL
Definition: fireworks.c:13
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
void initializeTexture()
Definition: fireworks.c:320
int main(int argc, char *argv[])
Definition: fireworks.c:363
#define SDL_PixelFormatEnumToMasks
#define GL_COLOR_BUFFER_BIT
Definition: SDL_opengl.h:742
unsigned char GLubyte
Definition: SDL_opengl.h:183
GLsizeiptr size
#define SDL_Delay
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
double sin(double x)
Definition: s_sin.c:46
GLfloat x
Definition: fireworks.c:37
#define GL_POINTS
Definition: SDL_opengl.h:216
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:161
#define GL_CULL_FACE
Definition: SDL_opengl.h:302
#define GL_MODELVIEW
Definition: SDL_opengl.h:271
#define MAX_PARTICLES
Definition: fireworks.c:15
unsigned int GLuint
Definition: SDL_opengl.h:185
GLAPI void GLAPIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
GLAPI void GLAPIENTRY glLoadIdentity(void)
#define SDL_CreateRGBSurface
GLint * exponent
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
GLAPI void GLAPIENTRY glMatrixMode(GLenum mode)
#define GL_VERTEX_ARRAY
Definition: SDL_opengl.h:228
The type used to identify a window.
Definition: SDL_sysvideo.h:73
uint32_t Uint32
Definition: SDL_stdinc.h:203
GLuint color
#define GL_SRC_ALPHA
Definition: SDL_opengl.h:404
GLubyte color[4]
Definition: fireworks.c:39
GLAPI void GLAPIENTRY glPointSize(GLfloat size)
void spawnEmitterParticle(GLfloat x, GLfloat y)
Definition: fireworks.c:262
GLAPI void GLAPIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param)
#define SDL_Init
General event structure.
Definition: SDL_events.h:557
#define GL_DEPTH_TEST
Definition: SDL_opengl.h:327
static float pointSizeScale
Definition: fireworks.c:19
int isActive
Definition: fireworks.c:43
void spawnTrailFromEmitter(struct particle *emitter)
Definition: fireworks.c:226
#define GL_TEXTURE_MIN_FILTER
Definition: SDL_opengl.h:675
double cos(double x)
Definition: s_cos.c:46
GLfloat y
Definition: fireworks.c:38
GLfloat size
Definition: fireworks.c:40
#define SDL_GetMouseState
#define SDL_GL_SwapWindow
GLfloat xvel
Definition: fireworks.c:41
#define SDL_INIT_VIDEO
Definition: SDL.h:79
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint GLint GLint GLint j2 GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLfloat *params GLenum GLint GLenum GLenum GLvoid *pixels GLenum GLint GLenum GLint *params GLenum GLenum GLint *params GLenum GLsizei const GLvoid *pointer GLenum GLenum const GLint *params GLenum GLfloat GLfloat GLint GLint const GLfloat *points GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat *points GLint GLfloat GLfloat GLint GLfloat GLfloat v2 GLenum GLenum const GLint *params GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum GLsizei const GLuint *values GLsizei const GLuint const GLclampf *priorities GLfloat GLfloat GLfloat GLfloat w GLint GLint GLsizei GLsizei GLenum GLenum GLvoid *pixels GLfloat GLfloat GLfloat GLfloat y2 GLdouble GLdouble GLdouble GLdouble z GLdouble GLdouble GLdouble GLdouble q GLshort GLshort GLshort GLshort q GLenum GLenum const GLfloat *params GLenum GLenum const GLdouble *params GLenum GLenum const GLint *params glTexImage2D
Definition: SDL_glfuncs.h:426
Uint32 type
Definition: SDL_events.h:559
enum particleType type
Definition: fireworks.c:44