Atlas - fireworks.c

Home / ext / SDL2 / Xcode-iOS / Demos / src Lines: 1 | Size: 15454 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
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 17static GLuint particleTextureID; /* OpenGL particle texture id */ 18static SDL_bool pointSizeExtensionSupported; /* is GL_OES_point_size_array supported ? */ 19static 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*/ 26enum particleType 27{ 28 emitter = 0, 29 trail, 30 dust 31}; 32/* 33 struct particle is used to describe each particle displayed on screen 34*/ 35struct 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 47static int num_active_particles; /* how many members of the particle array are actually being drawn / animated? */ 48static int screen_w, screen_h; 49 50/* function declarations */ 51void spawnTrailFromEmitter(struct particle *emitter); 52void spawnEmitterParticle(GLfloat x, GLfloat y); 53void explodeEmitter(struct particle *emitter); 54void initializeParticles(void); 55void initializeTexture(); 56int nextPowerOfTwo(int x); 57void drawParticles(); 58void stepParticles(double deltaTime); 59 60/* helper function (used in texture loading) 61 returns next power of two greater than or equal to x 62*/ 63int 64nextPowerOfTwo(int x) 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*/ 76void 77stepParticles(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*/ 157void 158drawParticles() 159{ 160 161 /* draw the background */ 162 glClear(GL_COLOR_BUFFER_BIT); 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 169 if (pointSizeExtensionSupported) { 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! */ 176 glDrawArrays(GL_POINTS, 0, num_active_particles); 177 178} 179 180/* 181 This causes an emitter to explode in a circular bloom of dust particles 182*/ 183void 184explodeEmitter(struct particle *emitter) 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 191 if (num_active_particles >= MAX_PARTICLES) 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 */ 201 struct particle *p = &particles[num_active_particles]; 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 */ 217 num_active_particles++; 218 } 219 220} 221 222/* 223 This spawns a trail particle from an emitter 224*/ 225void 226spawnTrailFromEmitter(struct particle *emitter) 227{ 228 229 if (num_active_particles >= MAX_PARTICLES) 230 return; 231 232 /* select the particle at the slot at the end of our array */ 233 struct particle *p = &particles[num_active_particles]; 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 */ 253 num_active_particles++; 254 255} 256 257/* 258 spawns a new emitter particle at the bottom of the screen 259 destined for the point (x,y). 260*/ 261void 262spawnEmitterParticle(GLfloat x, GLfloat y) 263{ 264 265 if (num_active_particles >= MAX_PARTICLES) 266 return; 267 268 /* find particle at endpoint of array */ 269 struct particle *p = &particles[num_active_particles]; 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 */ 306 num_active_particles++; 307} 308 309/* just sets the endpoint of the particle array to element zero */ 310void 311initializeParticles(void) 312{ 313 num_active_particles = 0; 314} 315 316/* 317 loads the particle texture 318 */ 319void 320initializeTexture() 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 */ 335 SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &Rmask, &Gmask, 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 344 glGenTextures(1, &particleTextureID); 345 glBindTexture(GL_TEXTURE_2D, particleTextureID); 346 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 347 nextPowerOfTwo(bmp_surface->w), 348 nextPowerOfTwo(bmp_surface->h), 349 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 351 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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 362int 363main(int argc, char *argv[]) 364{ 365 SDL_Window *window; /* main window */ 366 SDL_GLContext context; 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 */ 380 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 381 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); 382 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 383 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); 384 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); 385 SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); 386 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); 387 388 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); 389 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); 390 391 /* create main window and renderer */ 392 window = SDL_CreateWindow(NULL, 0, 0, 320, 480, 393 SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI); 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 */ 406 initializeTexture(); 407 408 /* check if GL_POINT_SIZE_ARRAY_OES is supported 409 this is used to give each particle its own size 410 */ 411 pointSizeExtensionSupported = 412 SDL_GL_ExtensionSupported("GL_OES_point_size_array"); 413 414 /* set up some OpenGL state */ 415 glDisable(GL_DEPTH_TEST); 416 glDisable(GL_CULL_FACE); 417 418 glMatrixMode(GL_MODELVIEW); 419 glLoadIdentity(); 420 421 glViewport(0, 0, drawableW, drawableH); 422 423 glMatrixMode(GL_PROJECTION); 424 glLoadIdentity(); 425 glOrthof((GLfloat) 0, 426 (GLfloat) screen_w, 427 (GLfloat) screen_h, 428 (GLfloat) 0, 0.0, 1.0); 429 430 glEnable(GL_TEXTURE_2D); 431 glEnable(GL_BLEND); 432 glBlendFunc(GL_SRC_ALPHA, GL_ONE); 433 glEnableClientState(GL_VERTEX_ARRAY); 434 glEnableClientState(GL_COLOR_ARRAY); 435 436 glEnable(GL_POINT_SPRITE_OES); 437 glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1); 438 439 if (pointSizeExtensionSupported) { 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 */ 444 glPointSize(10 * pointSizeScale); 445 } 446 447 done = 0; 448 /* enter main loop */ 449 while (!done) { 450 SDL_Event event; 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 */ 469 glDeleteTextures(1, &particleTextureID); 470 /* shutdown SDL */ 471 SDL_Quit(); 472 473 return 0; 474} 475
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.