comparison Xcode-iPhoneOS/Demos/src/fireworks.c @ 3277:20326ba2bda2

This name inconsistency has been bugging me for a while...
author Sam Lantinga <slouken@libsdl.org>
date Sat, 19 Sep 2009 07:32:36 +0000
parents
children 64ce267332c6
comparison
equal deleted inserted replaced
3276:720d176be107 3277:20326ba2bda2
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 MILLESECONDS_PER_FRAME 16 /* about 60 frames per second */
14 #define ACCEL 0.0001f /* acceleration due to gravity, units in pixels per millesecond squared */
15 #define WIND_RESISTANCE 0.00005f /* acceleration per unit velocity due to wind resistance */
16 #define MAX_PARTICLES 2000 /* maximum number of particles displayed at once */
17
18 static GLuint particleTextureID; /* OpenGL particle texture id */
19 static SDL_bool pointSizeExtensionSupported; /* is GL_OES_point_size_array supported ? */
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 */
26 enum particleType
27 {
28 emitter = 0,
29 trail,
30 dust
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
49 /* function declarations */
50 void spawnTrailFromEmitter(struct particle *emitter);
51 void spawnEmitterParticle(GLfloat x, GLfloat y);
52 void explodeEmitter(struct particle *emitter);
53 void initializeParticles(void);
54 void initializeTexture();
55 int nextPowerOfTwo(int x);
56 void drawParticles();
57 void stepParticles(void);
58
59 /* helper function (used in texture loading)
60 returns next power of two greater than or equal to x
61 */
62 int
63 nextPowerOfTwo(int x)
64 {
65 int val = 1;
66 while (val < x) {
67 val *= 2;
68 }
69 return val;
70 }
71
72 /*
73 steps each active particle by timestep MILLESECONDS_PER_FRAME
74 */
75 void
76 stepParticles(void)
77 {
78 int i;
79 struct particle *slot = particles;
80 struct particle *curr = particles;
81 for (i = 0; i < num_active_particles; i++) {
82 /* is the particle actually active, or is it marked for deletion? */
83 if (curr->isActive) {
84 /* is the particle off the screen? */
85 if (curr->y > SCREEN_HEIGHT)
86 curr->isActive = 0;
87 else if (curr->y < 0)
88 curr->isActive = 0;
89 if (curr->x > SCREEN_WIDTH)
90 curr->isActive = 0;
91 else if (curr->x < 0)
92 curr->isActive = 0;
93
94 /* step velocity, then step position */
95 curr->yvel += ACCEL * MILLESECONDS_PER_FRAME;
96 curr->xvel += 0.0f;
97 curr->y += curr->yvel * MILLESECONDS_PER_FRAME;
98 curr->x += curr->xvel * MILLESECONDS_PER_FRAME;
99
100 /* particle behavior */
101 if (curr->type == emitter) {
102 /* if we're an emitter, spawn a trail */
103 spawnTrailFromEmitter(curr);
104 /* if we've reached our peak, explode */
105 if (curr->yvel > 0.0) {
106 explodeEmitter(curr);
107 }
108 } else {
109 float speed =
110 sqrt(curr->xvel * curr->xvel + curr->yvel * curr->yvel);
111 /* if wind resistance is not powerful enough to stop us completely,
112 then apply winde resistance, otherwise just stop us completely */
113 if (WIND_RESISTANCE * MILLESECONDS_PER_FRAME < speed) {
114 float normx = curr->xvel / speed;
115 float normy = curr->yvel / speed;
116 curr->xvel -=
117 normx * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
118 curr->yvel -=
119 normy * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
120 } else {
121 curr->xvel = curr->yvel = 0; /* stop particle */
122 }
123
124 if (curr->color[3] <= MILLESECONDS_PER_FRAME * 0.1275f) {
125 /* if this next step will cause us to fade out completely
126 then just mark for deletion */
127 curr->isActive = 0;
128 } else {
129 /* otherwise, let's fade a bit more */
130 curr->color[3] -= MILLESECONDS_PER_FRAME * 0.1275f;
131 }
132
133 /* if we're a dust particle, shrink our size */
134 if (curr->type == dust)
135 curr->size -= MILLESECONDS_PER_FRAME * 0.010f;
136
137 }
138
139 /* if we're still active, pack ourselves in the array next
140 to the last active guy (pack the array tightly) */
141 if (curr->isActive)
142 *(slot++) = *curr;
143 } /* endif (curr->isActive) */
144 curr++;
145 }
146 /* the number of active particles is computed as the difference between
147 old number of active particles, where slot points, and the
148 new size of the array, where particles points */
149 num_active_particles = slot - particles;
150 }
151
152 /*
153 This draws all the particles shown on screen
154 */
155 void
156 drawParticles()
157 {
158
159 /* draw the background */
160 glClear(GL_COLOR_BUFFER_BIT);
161
162 /* set up the position and color pointers */
163 glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles);
164 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct particle),
165 particles[0].color);
166
167 if (pointSizeExtensionSupported) {
168 /* pass in our array of point sizes */
169 glPointSizePointerOES(GL_FLOAT, sizeof(struct particle),
170 &(particles[0].size));
171 }
172
173 /* draw our particles! */
174 glDrawArrays(GL_POINTS, 0, num_active_particles);
175
176 /* update screen */
177 SDL_RenderPresent();
178
179 }
180
181 /*
182 This causes an emitter to explode in a circular bloom of dust particles
183 */
184 void
185 explodeEmitter(struct particle *emitter)
186 {
187 /* first off, we're done with this particle, so turn active off */
188 emitter->isActive = 0;
189 int i;
190 for (i = 0; i < 200; i++) {
191
192 if (num_active_particles >= MAX_PARTICLES)
193 return;
194
195 /* come up with a random angle and speed for new particle */
196 float theta = randomFloat(0, 2.0f * 3.141592);
197 float exponent = 3.0f;
198 float speed = randomFloat(0.00, powf(0.17, exponent));
199 speed = powf(speed, 1.0f / exponent);
200
201 /*select the particle at the end of our array */
202 struct particle *p = &particles[num_active_particles];
203
204 /* set the particles properties */
205 p->xvel = speed * cos(theta);
206 p->yvel = speed * sin(theta);
207 p->x = emitter->x + emitter->xvel;
208 p->y = emitter->y + emitter->yvel;
209 p->isActive = 1;
210 p->type = dust;
211 p->size = 15;
212 /* inherit emitter's color */
213 p->color[0] = emitter->color[0];
214 p->color[1] = emitter->color[1];
215 p->color[2] = emitter->color[2];
216 p->color[3] = 255;
217 /* our array has expanded at the end */
218 num_active_particles++;
219 }
220
221 }
222
223 /*
224 This spawns a trail particle from an emitter
225 */
226 void
227 spawnTrailFromEmitter(struct particle *emitter)
228 {
229
230 if (num_active_particles >= MAX_PARTICLES)
231 return;
232
233 /* select the particle at the slot at the end of our array */
234 struct particle *p = &particles[num_active_particles];
235
236 /* set position and velocity to roughly that of the emitter */
237 p->x = emitter->x + randomFloat(-3.0, 3.0);
238 p->y = emitter->y + emitter->size / 2.0f;
239 p->xvel = emitter->xvel + randomFloat(-0.005, 0.005);
240 p->yvel = emitter->yvel + 0.1;
241
242 /* set the color to a random-ish orangy type color */
243 p->color[0] = (0.8f + randomFloat(-0.1, 0.0)) * 255;
244 p->color[1] = (0.4f + randomFloat(-0.1, 0.1)) * 255;
245 p->color[2] = (0.0f + randomFloat(0.0, 0.2)) * 255;
246 p->color[3] = (0.7f) * 255;
247
248 /* set other attributes */
249 p->size = 10;
250 p->type = trail;
251 p->isActive = 1;
252
253 /* our array has expanded at the end */
254 num_active_particles++;
255
256 }
257
258 /*
259 spawns a new emitter particle at the bottom of the screen
260 destined for the point (x,y).
261 */
262 void
263 spawnEmitterParticle(GLfloat x, GLfloat y)
264 {
265
266 if (num_active_particles >= MAX_PARTICLES)
267 return;
268
269 /* find particle at endpoint of array */
270 struct particle *p = &particles[num_active_particles];
271
272 /* set the color randomly */
273 switch (rand() % 4) {
274 case 0:
275 p->color[0] = 255;
276 p->color[1] = 100;
277 p->color[2] = 100;
278 break;
279 case 1:
280 p->color[0] = 100;
281 p->color[1] = 255;
282 p->color[2] = 100;
283 break;
284 case 2:
285 p->color[0] = 100;
286 p->color[1] = 100;
287 p->color[2] = 255;
288 break;
289 case 3:
290 p->color[0] = 255;
291 p->color[1] = 150;
292 p->color[2] = 50;
293 break;
294 }
295 p->color[3] = 255;
296 /* set position to (x, SCREEN_HEIGHT) */
297 p->x = x;
298 p->y = SCREEN_HEIGHT;
299 /* set velocity so that terminal point is (x,y) */
300 p->xvel = 0;
301 p->yvel = -sqrt(2 * ACCEL * (SCREEN_HEIGHT - y));
302 /* set other attributes */
303 p->size = 10;
304 p->type = emitter;
305 p->isActive = 1;
306 /* our array has expanded at the end */
307 num_active_particles++;
308 }
309
310 /* just sets the endpoint of the particle array to element zero */
311 void
312 initializeParticles(void)
313 {
314 num_active_particles = 0;
315 }
316
317 /*
318 loads the particle texture
319 */
320 void
321 initializeTexture()
322 {
323
324 int bpp; /* texture bits per pixel */
325 Uint32 Rmask, Gmask, Bmask, Amask; /* masks for pixel format passed into OpenGL */
326 SDL_Surface *bmp_surface; /* the bmp is loaded here */
327 SDL_Surface *bmp_surface_rgba8888; /* this serves as a destination to convert the BMP
328 to format passed into OpenGL */
329
330 bmp_surface = SDL_LoadBMP("stroke.bmp");
331 if (bmp_surface == NULL) {
332 fatalError("could not load stroke.bmp");
333 }
334
335 /* Grab info about format that will be passed into OpenGL */
336 SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &Rmask, &Gmask,
337 &Bmask, &Amask);
338 /* Create surface that will hold pixels passed into OpenGL */
339 bmp_surface_rgba8888 =
340 SDL_CreateRGBSurface(0, bmp_surface->w, bmp_surface->h, bpp, Rmask,
341 Gmask, Bmask, Amask);
342 /* Blit to this surface, effectively converting the format */
343 SDL_BlitSurface(bmp_surface, NULL, bmp_surface_rgba8888, NULL);
344
345 glGenTextures(1, &particleTextureID);
346 glBindTexture(GL_TEXTURE_2D, particleTextureID);
347 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
348 nextPowerOfTwo(bmp_surface->w),
349 nextPowerOfTwo(bmp_surface->h),
350 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
351 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
352 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
353 /* this is where we actually pass in the pixel data */
354 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmp_surface->w, bmp_surface->h, 0,
355 GL_RGBA, GL_UNSIGNED_BYTE, bmp_surface_rgba8888->pixels);
356
357 /* free bmp surface and converted bmp surface */
358 SDL_FreeSurface(bmp_surface);
359 SDL_FreeSurface(bmp_surface_rgba8888);
360
361 }
362
363 int
364 main(int argc, char *argv[])
365 {
366
367 SDL_WindowID windowID; /* ID of main window */
368 Uint32 startFrame; /* time frame began to process */
369 Uint32 endFrame; /* time frame ended processing */
370 Uint32 delay; /* time to pause waiting to draw next frame */
371 int done; /* should we clean up and exit? */
372
373 /* initialize SDL */
374 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
375 fatalError("Could not initialize SDL");
376 }
377 /* seed the random number generator */
378 srand(time(NULL));
379 /*
380 request some OpenGL parameters
381 that may speed drawing
382 */
383 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
384 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
385 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
386 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
387 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
388 SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
389 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
390
391 /* create main window and renderer */
392 windowID = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
393 SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN |
394 SDL_WINDOW_BORDERLESS);
395 SDL_CreateRenderer(windowID, 0, 0);
396
397 /* load the particle texture */
398 initializeTexture();
399
400 /* check if GL_POINT_SIZE_ARRAY_OES is supported
401 this is used to give each particle its own size
402 */
403 pointSizeExtensionSupported =
404 SDL_GL_ExtensionSupported("GL_OES_point_size_array");
405
406 /* set up some OpenGL state */
407 glEnable(GL_TEXTURE_2D);
408 glEnable(GL_BLEND);
409 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
410 glEnableClientState(GL_VERTEX_ARRAY);
411 glEnableClientState(GL_COLOR_ARRAY);
412
413 glEnable(GL_POINT_SPRITE_OES);
414 glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
415
416 if (pointSizeExtensionSupported) {
417 /* we use this to set the sizes of all the particles */
418 glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
419 } else {
420 /* if extension not available then all particles have size 10 */
421 glPointSize(10);
422 }
423
424 done = 0;
425 /* enter main loop */
426 while (!done) {
427 startFrame = SDL_GetTicks();
428 SDL_Event event;
429 while (SDL_PollEvent(&event)) {
430 if (event.type == SDL_QUIT) {
431 done = 1;
432 }
433 if (event.type == SDL_MOUSEBUTTONDOWN) {
434 int which = event.button.which;
435 int x, y;
436 SDL_SelectMouse(which);
437 SDL_GetMouseState(&x, &y);
438 spawnEmitterParticle(x, y);
439 }
440 }
441 stepParticles();
442 drawParticles();
443 endFrame = SDL_GetTicks();
444
445 /* figure out how much time we have left, and then sleep */
446 delay = MILLESECONDS_PER_FRAME - (endFrame - startFrame);
447 if (delay > MILLESECONDS_PER_FRAME) {
448 delay = MILLESECONDS_PER_FRAME;
449 }
450 if (delay > 0) {
451 SDL_Delay(delay);
452 }
453 }
454
455 /* delete textures */
456 glDeleteTextures(1, &particleTextureID);
457 /* shutdown SDL */
458 SDL_Quit();
459
460 return 0;
461 }