Fixes #2022, do not resume on Android when surfaceChanged
If the app is in landscape mode and the user presses the power button, a pause is followed immediately by a surfaceChanged event because the lock screen is shown in portrait mode. This triggers a "false" resume. So, we just pause and resume following the onWindowFocusChanged events. Also, wait for SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND before blocking the event pump.
This commit is contained in:
commit
dad420670f
859 changed files with 310893 additions and 0 deletions
475
Xcode-iOS/Demos/src/fireworks.c
Normal file
475
Xcode-iOS/Demos/src/fireworks.c
Normal file
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* fireworks.c
|
||||
* written by Holmes Futrell
|
||||
* use however you want
|
||||
*/
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_opengles.h"
|
||||
#include "common.h"
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#define MILLESECONDS_PER_FRAME 16 /* about 60 frames per second */
|
||||
#define ACCEL 0.0001f /* acceleration due to gravity, units in pixels per millesecond squared */
|
||||
#define WIND_RESISTANCE 0.00005f /* acceleration per unit velocity due to wind resistance */
|
||||
#define MAX_PARTICLES 2000 /* maximum number of particles displayed at once */
|
||||
|
||||
static GLuint particleTextureID; /* OpenGL particle texture id */
|
||||
static SDL_bool pointSizeExtensionSupported; /* is GL_OES_point_size_array supported ? */
|
||||
/*
|
||||
used to describe what type of particle a given struct particle is.
|
||||
emitter - this particle flies up, shooting off trail particles, then finally explodes into dust particles.
|
||||
trail - shoots off, following emitter particle
|
||||
dust - radiates outwards from emitter explosion
|
||||
*/
|
||||
enum particleType
|
||||
{
|
||||
emitter = 0,
|
||||
trail,
|
||||
dust
|
||||
};
|
||||
/*
|
||||
struct particle is used to describe each particle displayed on screen
|
||||
*/
|
||||
struct particle
|
||||
{
|
||||
GLfloat x; /* x position of particle */
|
||||
GLfloat y; /* y position of particle */
|
||||
GLubyte color[4]; /* rgba color of particle */
|
||||
GLfloat size; /* size of particle in pixels */
|
||||
GLfloat xvel; /* x velocity of particle in pixels per milesecond */
|
||||
GLfloat yvel; /* y velocity of particle in pixels per millescond */
|
||||
int isActive; /* if not active, then particle is overwritten */
|
||||
enum particleType type; /* see enum particleType */
|
||||
} particles[MAX_PARTICLES]; /* this array holds all our particles */
|
||||
|
||||
static int num_active_particles; /* how many members of the particle array are actually being drawn / animated? */
|
||||
static int screen_w, screen_h;
|
||||
|
||||
/* function declarations */
|
||||
void spawnTrailFromEmitter(struct particle *emitter);
|
||||
void spawnEmitterParticle(GLfloat x, GLfloat y);
|
||||
void explodeEmitter(struct particle *emitter);
|
||||
void initializeParticles(void);
|
||||
void initializeTexture();
|
||||
int nextPowerOfTwo(int x);
|
||||
void drawParticles();
|
||||
void stepParticles(void);
|
||||
|
||||
/* helper function (used in texture loading)
|
||||
returns next power of two greater than or equal to x
|
||||
*/
|
||||
int
|
||||
nextPowerOfTwo(int x)
|
||||
{
|
||||
int val = 1;
|
||||
while (val < x) {
|
||||
val *= 2;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
steps each active particle by timestep MILLESECONDS_PER_FRAME
|
||||
*/
|
||||
void
|
||||
stepParticles(void)
|
||||
{
|
||||
int i;
|
||||
struct particle *slot = particles;
|
||||
struct particle *curr = particles;
|
||||
for (i = 0; i < num_active_particles; i++) {
|
||||
/* is the particle actually active, or is it marked for deletion? */
|
||||
if (curr->isActive) {
|
||||
/* is the particle off the screen? */
|
||||
if (curr->y > screen_h)
|
||||
curr->isActive = 0;
|
||||
else if (curr->y < 0)
|
||||
curr->isActive = 0;
|
||||
if (curr->x > screen_w)
|
||||
curr->isActive = 0;
|
||||
else if (curr->x < 0)
|
||||
curr->isActive = 0;
|
||||
|
||||
/* step velocity, then step position */
|
||||
curr->yvel += ACCEL * MILLESECONDS_PER_FRAME;
|
||||
curr->xvel += 0.0f;
|
||||
curr->y += curr->yvel * MILLESECONDS_PER_FRAME;
|
||||
curr->x += curr->xvel * MILLESECONDS_PER_FRAME;
|
||||
|
||||
/* particle behavior */
|
||||
if (curr->type == emitter) {
|
||||
/* if we're an emitter, spawn a trail */
|
||||
spawnTrailFromEmitter(curr);
|
||||
/* if we've reached our peak, explode */
|
||||
if (curr->yvel > 0.0) {
|
||||
explodeEmitter(curr);
|
||||
}
|
||||
} else {
|
||||
float speed =
|
||||
sqrt(curr->xvel * curr->xvel + curr->yvel * curr->yvel);
|
||||
/* if wind resistance is not powerful enough to stop us completely,
|
||||
then apply winde resistance, otherwise just stop us completely */
|
||||
if (WIND_RESISTANCE * MILLESECONDS_PER_FRAME < speed) {
|
||||
float normx = curr->xvel / speed;
|
||||
float normy = curr->yvel / speed;
|
||||
curr->xvel -=
|
||||
normx * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
|
||||
curr->yvel -=
|
||||
normy * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
|
||||
} else {
|
||||
curr->xvel = curr->yvel = 0; /* stop particle */
|
||||
}
|
||||
|
||||
if (curr->color[3] <= MILLESECONDS_PER_FRAME * 0.1275f) {
|
||||
/* if this next step will cause us to fade out completely
|
||||
then just mark for deletion */
|
||||
curr->isActive = 0;
|
||||
} else {
|
||||
/* otherwise, let's fade a bit more */
|
||||
curr->color[3] -= MILLESECONDS_PER_FRAME * 0.1275f;
|
||||
}
|
||||
|
||||
/* if we're a dust particle, shrink our size */
|
||||
if (curr->type == dust)
|
||||
curr->size -= MILLESECONDS_PER_FRAME * 0.010f;
|
||||
|
||||
}
|
||||
|
||||
/* if we're still active, pack ourselves in the array next
|
||||
to the last active guy (pack the array tightly) */
|
||||
if (curr->isActive)
|
||||
*(slot++) = *curr;
|
||||
} /* endif (curr->isActive) */
|
||||
curr++;
|
||||
}
|
||||
/* the number of active particles is computed as the difference between
|
||||
old number of active particles, where slot points, and the
|
||||
new size of the array, where particles points */
|
||||
num_active_particles = slot - particles;
|
||||
}
|
||||
|
||||
/*
|
||||
This draws all the particles shown on screen
|
||||
*/
|
||||
void
|
||||
drawParticles()
|
||||
{
|
||||
|
||||
/* draw the background */
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
/* set up the position and color pointers */
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct particle),
|
||||
particles[0].color);
|
||||
|
||||
if (pointSizeExtensionSupported) {
|
||||
/* pass in our array of point sizes */
|
||||
glPointSizePointerOES(GL_FLOAT, sizeof(struct particle),
|
||||
&(particles[0].size));
|
||||
}
|
||||
|
||||
/* draw our particles! */
|
||||
glDrawArrays(GL_POINTS, 0, num_active_particles);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This causes an emitter to explode in a circular bloom of dust particles
|
||||
*/
|
||||
void
|
||||
explodeEmitter(struct particle *emitter)
|
||||
{
|
||||
/* first off, we're done with this particle, so turn active off */
|
||||
emitter->isActive = 0;
|
||||
int i;
|
||||
for (i = 0; i < 200; i++) {
|
||||
|
||||
if (num_active_particles >= MAX_PARTICLES)
|
||||
return;
|
||||
|
||||
/* come up with a random angle and speed for new particle */
|
||||
float theta = randomFloat(0, 2.0f * 3.141592);
|
||||
float exponent = 3.0f;
|
||||
float speed = randomFloat(0.00, powf(0.17, exponent));
|
||||
speed = powf(speed, 1.0f / exponent);
|
||||
|
||||
/*select the particle at the end of our array */
|
||||
struct particle *p = &particles[num_active_particles];
|
||||
|
||||
/* set the particles properties */
|
||||
p->xvel = speed * cos(theta);
|
||||
p->yvel = speed * sin(theta);
|
||||
p->x = emitter->x + emitter->xvel;
|
||||
p->y = emitter->y + emitter->yvel;
|
||||
p->isActive = 1;
|
||||
p->type = dust;
|
||||
p->size = 15;
|
||||
/* inherit emitter's color */
|
||||
p->color[0] = emitter->color[0];
|
||||
p->color[1] = emitter->color[1];
|
||||
p->color[2] = emitter->color[2];
|
||||
p->color[3] = 255;
|
||||
/* our array has expanded at the end */
|
||||
num_active_particles++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This spawns a trail particle from an emitter
|
||||
*/
|
||||
void
|
||||
spawnTrailFromEmitter(struct particle *emitter)
|
||||
{
|
||||
|
||||
if (num_active_particles >= MAX_PARTICLES)
|
||||
return;
|
||||
|
||||
/* select the particle at the slot at the end of our array */
|
||||
struct particle *p = &particles[num_active_particles];
|
||||
|
||||
/* set position and velocity to roughly that of the emitter */
|
||||
p->x = emitter->x + randomFloat(-3.0, 3.0);
|
||||
p->y = emitter->y + emitter->size / 2.0f;
|
||||
p->xvel = emitter->xvel + randomFloat(-0.005, 0.005);
|
||||
p->yvel = emitter->yvel + 0.1;
|
||||
|
||||
/* set the color to a random-ish orangy type color */
|
||||
p->color[0] = (0.8f + randomFloat(-0.1, 0.0)) * 255;
|
||||
p->color[1] = (0.4f + randomFloat(-0.1, 0.1)) * 255;
|
||||
p->color[2] = (0.0f + randomFloat(0.0, 0.2)) * 255;
|
||||
p->color[3] = (0.7f) * 255;
|
||||
|
||||
/* set other attributes */
|
||||
p->size = 10;
|
||||
p->type = trail;
|
||||
p->isActive = 1;
|
||||
|
||||
/* our array has expanded at the end */
|
||||
num_active_particles++;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
spawns a new emitter particle at the bottom of the screen
|
||||
destined for the point (x,y).
|
||||
*/
|
||||
void
|
||||
spawnEmitterParticle(GLfloat x, GLfloat y)
|
||||
{
|
||||
|
||||
if (num_active_particles >= MAX_PARTICLES)
|
||||
return;
|
||||
|
||||
/* find particle at endpoint of array */
|
||||
struct particle *p = &particles[num_active_particles];
|
||||
|
||||
/* set the color randomly */
|
||||
switch (rand() % 4) {
|
||||
case 0:
|
||||
p->color[0] = 255;
|
||||
p->color[1] = 100;
|
||||
p->color[2] = 100;
|
||||
break;
|
||||
case 1:
|
||||
p->color[0] = 100;
|
||||
p->color[1] = 255;
|
||||
p->color[2] = 100;
|
||||
break;
|
||||
case 2:
|
||||
p->color[0] = 100;
|
||||
p->color[1] = 100;
|
||||
p->color[2] = 255;
|
||||
break;
|
||||
case 3:
|
||||
p->color[0] = 255;
|
||||
p->color[1] = 150;
|
||||
p->color[2] = 50;
|
||||
break;
|
||||
}
|
||||
p->color[3] = 255;
|
||||
/* set position to (x, screen_h) */
|
||||
p->x = x;
|
||||
p->y = screen_h;
|
||||
/* set velocity so that terminal point is (x,y) */
|
||||
p->xvel = 0;
|
||||
p->yvel = -sqrt(2 * ACCEL * (screen_h - y));
|
||||
/* set other attributes */
|
||||
p->size = 10;
|
||||
p->type = emitter;
|
||||
p->isActive = 1;
|
||||
/* our array has expanded at the end */
|
||||
num_active_particles++;
|
||||
}
|
||||
|
||||
/* just sets the endpoint of the particle array to element zero */
|
||||
void
|
||||
initializeParticles(void)
|
||||
{
|
||||
num_active_particles = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
loads the particle texture
|
||||
*/
|
||||
void
|
||||
initializeTexture()
|
||||
{
|
||||
|
||||
int bpp; /* texture bits per pixel */
|
||||
Uint32 Rmask, Gmask, Bmask, Amask; /* masks for pixel format passed into OpenGL */
|
||||
SDL_Surface *bmp_surface; /* the bmp is loaded here */
|
||||
SDL_Surface *bmp_surface_rgba8888; /* this serves as a destination to convert the BMP
|
||||
to format passed into OpenGL */
|
||||
|
||||
bmp_surface = SDL_LoadBMP("stroke.bmp");
|
||||
if (bmp_surface == NULL) {
|
||||
fatalError("could not load stroke.bmp");
|
||||
}
|
||||
|
||||
/* Grab info about format that will be passed into OpenGL */
|
||||
SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &Rmask, &Gmask,
|
||||
&Bmask, &Amask);
|
||||
/* Create surface that will hold pixels passed into OpenGL */
|
||||
bmp_surface_rgba8888 =
|
||||
SDL_CreateRGBSurface(0, bmp_surface->w, bmp_surface->h, bpp, Rmask,
|
||||
Gmask, Bmask, Amask);
|
||||
/* Blit to this surface, effectively converting the format */
|
||||
SDL_BlitSurface(bmp_surface, NULL, bmp_surface_rgba8888, NULL);
|
||||
|
||||
glGenTextures(1, &particleTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, particleTextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||||
nextPowerOfTwo(bmp_surface->w),
|
||||
nextPowerOfTwo(bmp_surface->h),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
/* this is where we actually pass in the pixel data */
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmp_surface->w, bmp_surface->h, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, bmp_surface_rgba8888->pixels);
|
||||
|
||||
/* free bmp surface and converted bmp surface */
|
||||
SDL_FreeSurface(bmp_surface);
|
||||
SDL_FreeSurface(bmp_surface_rgba8888);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
SDL_Window *window; /* main window */
|
||||
SDL_GLContext context;
|
||||
int w, h;
|
||||
Uint32 startFrame; /* time frame began to process */
|
||||
Uint32 endFrame; /* time frame ended processing */
|
||||
Uint32 delay; /* time to pause waiting to draw next frame */
|
||||
int done; /* should we clean up and exit? */
|
||||
|
||||
/* initialize SDL */
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
fatalError("Could not initialize SDL");
|
||||
}
|
||||
/* seed the random number generator */
|
||||
srand(time(NULL));
|
||||
/*
|
||||
request some OpenGL parameters
|
||||
that may speed drawing
|
||||
*/
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
|
||||
|
||||
/* create main window and renderer */
|
||||
window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
|
||||
SDL_WINDOW_OPENGL |
|
||||
SDL_WINDOW_BORDERLESS);
|
||||
context = SDL_GL_CreateContext(window);
|
||||
|
||||
/* load the particle texture */
|
||||
initializeTexture();
|
||||
|
||||
/* check if GL_POINT_SIZE_ARRAY_OES is supported
|
||||
this is used to give each particle its own size
|
||||
*/
|
||||
pointSizeExtensionSupported =
|
||||
SDL_GL_ExtensionSupported("GL_OES_point_size_array");
|
||||
|
||||
/* set up some OpenGL state */
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
SDL_GetWindowSize(window, &screen_w, &screen_h);
|
||||
glViewport(0, 0, screen_w, screen_h);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrthof((GLfloat) 0,
|
||||
(GLfloat) screen_w,
|
||||
(GLfloat) screen_h,
|
||||
(GLfloat) 0, 0.0, 1.0);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glEnable(GL_POINT_SPRITE_OES);
|
||||
glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
|
||||
|
||||
if (pointSizeExtensionSupported) {
|
||||
/* we use this to set the sizes of all the particles */
|
||||
glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
|
||||
} else {
|
||||
/* if extension not available then all particles have size 10 */
|
||||
glPointSize(10);
|
||||
}
|
||||
|
||||
done = 0;
|
||||
/* enter main loop */
|
||||
while (!done) {
|
||||
startFrame = SDL_GetTicks();
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
done = 1;
|
||||
}
|
||||
if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
int x, y;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
spawnEmitterParticle(x, y);
|
||||
}
|
||||
}
|
||||
stepParticles();
|
||||
drawParticles();
|
||||
SDL_GL_SwapWindow(window);
|
||||
endFrame = SDL_GetTicks();
|
||||
|
||||
/* figure out how much time we have left, and then sleep */
|
||||
delay = MILLESECONDS_PER_FRAME - (endFrame - startFrame);
|
||||
if (delay > MILLESECONDS_PER_FRAME) {
|
||||
delay = MILLESECONDS_PER_FRAME;
|
||||
}
|
||||
if (delay > 0) {
|
||||
SDL_Delay(delay);
|
||||
}
|
||||
}
|
||||
|
||||
/* delete textures */
|
||||
glDeleteTextures(1, &particleTextureID);
|
||||
/* shutdown SDL */
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue