Cleaned up code, added comments, added randomized colors, added check for extension GL_POINT_SIZE_ARRAY_OES, which not all OpenGL ES systems have. gsoc2008_iphone
authorHolmes Futrell <hfutrell@umail.ucsb.edu>
Wed, 13 Aug 2008 23:10:51 +0000
branchgsoc2008_iphone
changeset 2417ac26bd83db1f
parent 2416 d92493ff1b51
child 2418 9aac7992ed85
Cleaned up code, added comments, added randomized colors, added check for extension GL_POINT_SIZE_ARRAY_OES, which not all OpenGL ES systems have.
XCodeiPhoneOS/Demos/src/fireworks.c
     1.1 --- a/XCodeiPhoneOS/Demos/src/fireworks.c	Wed Aug 13 20:56:21 2008 +0000
     1.2 +++ b/XCodeiPhoneOS/Demos/src/fireworks.c	Wed Aug 13 23:10:51 2008 +0000
     1.3 @@ -5,135 +5,100 @@
     1.4   */
     1.5  
     1.6  #include "SDL.h"
     1.7 -#include "math.h"
     1.8 +#include "SDL_opengles.h"
     1.9  #include "common.h"
    1.10  #include <math.h>
    1.11  #include <time.h>
    1.12 -#include <OpenGLES/ES1/gl.h>
    1.13  
    1.14  #define MILLESECONDS_PER_FRAME 16	/* about 60 frames per second */
    1.15 -#define ACCEL 0.0001f
    1.16 -#define WIND_RESISTANCE 0.00005f
    1.17 -#define MAX_PARTICLES 2000
    1.18 -#define VEL_BEFORE_EXPLODE 0.0f
    1.19 +#define ACCEL 0.0001f				/* acceleration due to gravity, units in pixels per millesecond squared */
    1.20 +#define WIND_RESISTANCE 0.00005f	/* acceleration per unit velocity due to wind resistance */
    1.21 +#define MAX_PARTICLES 2000			/* maximum number of particles displayed at once */
    1.22  
    1.23 -SDL_TextureID flashTextureID;
    1.24 -
    1.25 -
    1.26 +static GLuint particleTextureID;	/* OpenGL particle texture id */
    1.27 +static SDL_bool pointSizeExtensionSupported; /* is GL_OES_point_size_array supported ? */
    1.28 +/* 
    1.29 +	used to describe what type of particle a given struct particle is.
    1.30 +	emitter - this particle flies up, shooting off trail particles, then finally explodes into dust particles.
    1.31 +	trail	- shoots off, following emitter particle
    1.32 +	dust	- radiates outwards from emitter explosion
    1.33 +*/
    1.34  enum particleType {
    1.35  	emitter = 0,
    1.36  	trail,
    1.37  	dust
    1.38  };
    1.39 +/*
    1.40 +	struct particle is used to describe each particle displayed on screen
    1.41 +*/
    1.42 +struct particle {
    1.43 +	GLfloat x;					/* x position of particle */
    1.44 +	GLfloat y;					/* y position of particle */
    1.45 +	GLubyte color[4];			/* rgba color of particle */
    1.46 +	GLfloat size;				/* size of particle in pixels */
    1.47 +	GLfloat xvel;				/* x velocity of particle in pixels per milesecond */
    1.48 +	GLfloat yvel;				/* y velocity of particle in pixels per millescond */
    1.49 +	int isActive;				/* if not active, then particle is overwritten */
    1.50 +	enum particleType type;		/* see enum particleType */
    1.51 +} particles[MAX_PARTICLES];		/* this array holds all our particles */
    1.52  
    1.53 -struct glformat {
    1.54 -	int SDL_GL_RED_SIZE;
    1.55 -	int SDL_GL_GREEN_SIZE;
    1.56 -	int SDL_GL_BLUE_SIZE;
    1.57 -	int SDL_GL_ALPHA_SIZE;
    1.58 -	int SDL_GL_BUFFER_SIZE;
    1.59 -	int SDL_GL_DOUBLEBUFFER;
    1.60 -	int SDL_GL_DEPTH_SIZE;
    1.61 -	int SDL_GL_STENCIL_SIZE;
    1.62 -	int SDL_GL_ACCUM_RED_SIZE;
    1.63 -	int SDL_GL_ACCUM_GREEN_SIZE;
    1.64 -	int SDL_GL_ACCUM_BLUE_SIZE;
    1.65 -	int SDL_GL_ACCUM_ALPHA_SIZE;
    1.66 -	int SDL_GL_STEREO;
    1.67 -	int SDL_GL_MULTISAMPLEBUFFERS;
    1.68 -	int SDL_GL_MULTISAMPLESAMPLES;
    1.69 -	int SDL_GL_ACCELERATED_VISUAL;
    1.70 -	int SDL_GL_RETAINED_BACKING;
    1.71 -};
    1.72 +static int num_active_particles; /* how many members of the particle array are actually being drawn / animated? */
    1.73  
    1.74 -struct particle {
    1.75 +/* function declarations */
    1.76 +void spawnTrailFromEmitter(struct particle *emitter);
    1.77 +void spawnEmitterParticle(GLfloat x, GLfloat y);
    1.78 +void explodeEmitter(struct particle *emitter);
    1.79 +void initializeParticles(void);
    1.80 +void initializeTexture();
    1.81 +int	nextPowerOfTwo(int x);
    1.82 +void drawParticles();
    1.83 +void stepParticles(void);
    1.84  
    1.85 -	GLfloat x;
    1.86 -	GLfloat y;
    1.87 -	GLubyte color[4];
    1.88 -	GLfloat size;
    1.89 -	GLfloat xvel;
    1.90 -	GLfloat yvel;
    1.91 -	int isActive;
    1.92 -	enum particleType type;
    1.93 -	int framesSinceEmission;
    1.94 -} particles[MAX_PARTICLES];
    1.95 -
    1.96 -void spawnParticleFromEmitter(struct particle *emitter);
    1.97 -void explodeEmitter(struct particle *emitter);
    1.98 -
    1.99 -static int num_active_particles;
   1.100 -
   1.101 -static void getError(const char *prefix)
   1.102 -{
   1.103 -    const char *error;
   1.104 -	
   1.105 -	GLenum result = glGetError();
   1.106 -	if (result == GL_NO_ERROR)
   1.107 -		return;
   1.108 -	
   1.109 -    switch (result) {
   1.110 -		case GL_NO_ERROR:
   1.111 -			error = "GL_NO_ERROR";
   1.112 -			break;
   1.113 -		case GL_INVALID_ENUM:
   1.114 -			error = "GL_INVALID_ENUM";
   1.115 -			break;
   1.116 -		case GL_INVALID_VALUE:
   1.117 -			error = "GL_INVALID_VALUE";
   1.118 -			break;
   1.119 -		case GL_INVALID_OPERATION:
   1.120 -			error = "GL_INVALID_OPERATION";
   1.121 -			break;
   1.122 -		case GL_STACK_OVERFLOW:
   1.123 -			error = "GL_STACK_OVERFLOW";
   1.124 -			break;
   1.125 -		case GL_STACK_UNDERFLOW:
   1.126 -			error = "GL_STACK_UNDERFLOW";
   1.127 -			break;
   1.128 -		case GL_OUT_OF_MEMORY:
   1.129 -			error = "GL_OUT_OF_MEMORY";
   1.130 -			break;
   1.131 -		default:
   1.132 -			error = "UNKNOWN";
   1.133 -			break;
   1.134 -    }
   1.135 -    printf("%s: %s\n", prefix, error);
   1.136 +/*	helper function (used in texture loading)
   1.137 +	returns next power of two greater than or equal to x
   1.138 +*/
   1.139 +int nextPowerOfTwo(int x) {
   1.140 +	int val=1;
   1.141 +	while (val < x) {
   1.142 +		val *= 2;
   1.143 +	}
   1.144 +	return val;
   1.145  }
   1.146 -
   1.147 -void render(void) {
   1.148 -		
   1.149 -	/* draw the background */
   1.150 -	glClear(GL_COLOR_BUFFER_BIT);
   1.151 -	
   1.152 +/*	
   1.153 +	steps each active particle by timestep MILLESECONDS_PER_FRAME
   1.154 +*/
   1.155 +void stepParticles(void) {
   1.156 +	int i;
   1.157  	struct particle *slot = particles;
   1.158  	struct particle *curr = particles;
   1.159 -	int i;
   1.160  	for (i=0; i<num_active_particles; i++) {
   1.161 +		/* is the particle actually active, or is it marked for deletion? */
   1.162  		if (curr->isActive) {
   1.163 -			
   1.164 +			/* is the particle off the screen? */
   1.165  			if (curr->y > SCREEN_HEIGHT) curr->isActive = 0;
   1.166 -			if (curr->y < 0) curr->isActive = 0;
   1.167 +			else if (curr->y < 0) curr->isActive = 0;
   1.168  			if (curr->x > SCREEN_WIDTH) curr->isActive = 0;
   1.169 -			if (curr->x < 0) curr->isActive = 0;
   1.170 +			else if (curr->x < 0) curr->isActive = 0;
   1.171  
   1.172 +			/* step velocity, then step position */
   1.173  			curr->yvel += ACCEL * MILLESECONDS_PER_FRAME;
   1.174  			curr->xvel += 0.0f;
   1.175  			curr->y += curr->yvel * MILLESECONDS_PER_FRAME;
   1.176  			curr->x += curr->xvel * MILLESECONDS_PER_FRAME;
   1.177  			
   1.178 +			/* particle behavior */
   1.179  			if (curr->type == emitter) {
   1.180 -				spawnParticleFromEmitter(curr);
   1.181 -				curr->framesSinceEmission = 0;
   1.182 -				if (curr->yvel > -VEL_BEFORE_EXPLODE) {
   1.183 +				/* if we're an emitter, spawn a trail */
   1.184 +				spawnTrailFromEmitter(curr);
   1.185 +				/* if we've reached our peak, explode */
   1.186 +				if (curr->yvel > 0.0) {
   1.187  					explodeEmitter(curr);
   1.188  				}
   1.189 -				curr->framesSinceEmission++;
   1.190  			}
   1.191  			else {
   1.192 -				
   1.193  				float speed = sqrt(curr->xvel*curr->xvel + curr->yvel*curr->yvel);
   1.194 -				
   1.195 +				/*	if wind resistance is not powerful enough to stop us completely,
   1.196 +					then apply winde resistance, otherwise just stop us completely */
   1.197  				if (WIND_RESISTANCE * MILLESECONDS_PER_FRAME < speed) {
   1.198  					float normx = curr->xvel / speed;
   1.199  					float normy = curr->yvel / speed;
   1.200 @@ -141,260 +106,285 @@
   1.201  					curr->yvel -= normy * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
   1.202  				}
   1.203  				else {
   1.204 -					curr->xvel = 0;
   1.205 -					curr->yvel = 0;
   1.206 +					curr->xvel = curr->yvel = 0; /* stop particle */
   1.207  				}
   1.208  				
   1.209 -				if (curr->color[3] <= MILLESECONDS_PER_FRAME * 0.0005f * 255) {
   1.210 +				if (curr->color[3] <= MILLESECONDS_PER_FRAME * 0.1275f) {
   1.211 +					/* if this next step will cause us to fade out completely
   1.212 +					 then just mark for deletion */
   1.213  					curr->isActive = 0;
   1.214 -
   1.215  				}
   1.216  				else {
   1.217 -					curr->color[3] -= MILLESECONDS_PER_FRAME * 0.0005f * 255;
   1.218 +					/* otherwise, let's fade a bit more */
   1.219 +					curr->color[3] -= MILLESECONDS_PER_FRAME * 0.1275f;
   1.220  				}
   1.221  				
   1.222 +				/* if we're a dust particle, shrink our size */
   1.223  				if (curr->type == dust)
   1.224  					curr->size -= MILLESECONDS_PER_FRAME * 0.010f;
   1.225  				
   1.226  			}
   1.227  			
   1.228 -			*(slot++) = *curr;
   1.229 -		}
   1.230 +			/* if we're still active, pack ourselves in the array next
   1.231 +			   to the last active guy (pack the array tightly) */
   1.232 +			if (curr->isActive)
   1.233 +				*(slot++) = *curr;
   1.234 +		} /* endif (curr->isActive) */
   1.235  		curr++;
   1.236  	}
   1.237 +	/* the number of active particles is computed as the difference between
   1.238 +	   old number of active particles, where slot points, and the 
   1.239 +	   new size of the array, where particles points */
   1.240  	num_active_particles = slot - particles;
   1.241 +}
   1.242 +/*
   1.243 +	This draws all the particles shown on screen
   1.244 +*/
   1.245 +void drawParticles() {
   1.246  	
   1.247 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1.248 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1.249 -	glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
   1.250 -
   1.251 -	glEnableClientState(GL_VERTEX_ARRAY);
   1.252 -	glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles + 0);
   1.253 -	getError("vertices");
   1.254 +	/* draw the background */
   1.255 +	glClear(GL_COLOR_BUFFER_BIT);
   1.256  	
   1.257 -	glEnableClientState(GL_COLOR_ARRAY);
   1.258 +	/* set up the position and color pointers */
   1.259 +	glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles);
   1.260  	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct particle), particles[0].color);
   1.261 -	getError("colors");
   1.262 -
   1.263 -	glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
   1.264 -	getError("enable client state");
   1.265 -	glPointSizePointerOES(GL_FLOAT, sizeof(struct particle), &(particles[0].size));	
   1.266 -	getError("point size");
   1.267 -
   1.268 -	glEnable(GL_POINT_SPRITE_OES);
   1.269 +	
   1.270 +	if (pointSizeExtensionSupported) {
   1.271 +		/* pass in our array of point sizes */
   1.272 +		glPointSizePointerOES(GL_FLOAT, sizeof(struct particle), &(particles[0].size));
   1.273 +	}
   1.274 +	
   1.275 +	/* draw our particles! */
   1.276  	glDrawArrays(GL_POINTS, 0, num_active_particles);	
   1.277 -	getError("glDrawArrays");
   1.278 -
   1.279 -		
   1.280 +	
   1.281  	/* update screen */
   1.282 -	SDL_RenderPresent();
   1.283 +	SDL_RenderPresent();	
   1.284  	
   1.285  }
   1.286 -
   1.287 -void printOpenGLAttributes(struct glformat *format) {
   1.288 -	printf("\tSDL_GL_RED_SIZE = %d\n", format->SDL_GL_RED_SIZE);
   1.289 -	printf("\tSDL_GL_GREEN_SIZE = %d\n", format->SDL_GL_GREEN_SIZE);
   1.290 -	printf("\tSDL_GL_BLUE_SIZE = %d\n", format->SDL_GL_BLUE_SIZE);
   1.291 -	printf("\tSDL_GL_ALPHA_SIZE = %d\n", format->SDL_GL_ALPHA_SIZE);
   1.292 -	printf("\tSDL_GL_BUFFER_SIZE = %d\n", format->SDL_GL_BUFFER_SIZE);
   1.293 -	printf("\tSDL_GL_DOUBLEBUFFER = %d\n", format->SDL_GL_DOUBLEBUFFER);
   1.294 -	printf("\tSDL_GL_DEPTH_SIZE = %d\n", format->SDL_GL_DEPTH_SIZE);
   1.295 -	printf("\tSDL_GL_STENCIL_SIZE = %d\n", format->SDL_GL_STENCIL_SIZE);
   1.296 -	printf("\tSDL_GL_ACCUM_RED_SIZE = %d\n", format->SDL_GL_ACCUM_RED_SIZE);
   1.297 -	printf("\tSDL_GL_ACCUM_GREEN_SIZE = %d\n", format->SDL_GL_ACCUM_GREEN_SIZE);
   1.298 -	printf("\tSDL_GL_ACCUM_BLUE_SIZE = %d\n", format->SDL_GL_ACCUM_BLUE_SIZE);
   1.299 -	printf("\tSDL_GL_ACCUM_ALPHA_SIZE = %d\n", format->SDL_GL_ACCUM_ALPHA_SIZE);
   1.300 -	printf("\tSDL_GL_STEREO = %d\n", format->SDL_GL_STEREO);
   1.301 -	printf("\tSDL_GL_MULTISAMPLEBUFFERS = %d\n", format->SDL_GL_MULTISAMPLEBUFFERS);
   1.302 -	printf("\tSDL_GL_MULTISAMPLESAMPLES = %d\n", format->SDL_GL_MULTISAMPLESAMPLES);
   1.303 -	printf("\tSDL_GL_ACCELERATED_VISUAL = %d\n", format->SDL_GL_ACCELERATED_VISUAL);
   1.304 -	printf("\tSDL_GL_RETAINED_BACKING = %d\n", format->SDL_GL_RETAINED_BACKING);	
   1.305 -}
   1.306 -
   1.307 -void setOpenGLAttributes(struct glformat *format) {
   1.308 -	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, format->SDL_GL_RED_SIZE);
   1.309 -	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, format->SDL_GL_GREEN_SIZE);
   1.310 -	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, format->SDL_GL_BLUE_SIZE);
   1.311 -	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, format->SDL_GL_ALPHA_SIZE);
   1.312 -	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, format->SDL_GL_BUFFER_SIZE);
   1.313 -	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, format->SDL_GL_DOUBLEBUFFER);
   1.314 -	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, format->SDL_GL_DEPTH_SIZE);
   1.315 -	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, format->SDL_GL_STENCIL_SIZE);
   1.316 -	SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, format->SDL_GL_ACCUM_RED_SIZE);
   1.317 -	SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, format->SDL_GL_ACCUM_GREEN_SIZE);
   1.318 -	SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, format->SDL_GL_ACCUM_BLUE_SIZE);
   1.319 -	SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, format->SDL_GL_ACCUM_ALPHA_SIZE);
   1.320 -	SDL_GL_SetAttribute(SDL_GL_STEREO, format->SDL_GL_STEREO);
   1.321 -	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, format->SDL_GL_MULTISAMPLEBUFFERS);
   1.322 -	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, format->SDL_GL_MULTISAMPLESAMPLES);
   1.323 -	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, format->SDL_GL_ACCELERATED_VISUAL);
   1.324 -	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, format->SDL_GL_RETAINED_BACKING);
   1.325 -}
   1.326 -
   1.327 -void getOpenGLAttributes(struct glformat *format) {
   1.328 -		
   1.329 -	SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &(format->SDL_GL_RED_SIZE));
   1.330 -	SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &(format->SDL_GL_GREEN_SIZE));
   1.331 -	SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &(format->SDL_GL_BLUE_SIZE));
   1.332 -	SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &(format->SDL_GL_ALPHA_SIZE));
   1.333 -	SDL_GL_GetAttribute(SDL_GL_BUFFER_SIZE, &(format->SDL_GL_BUFFER_SIZE));
   1.334 -	SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &(format->SDL_GL_DOUBLEBUFFER));
   1.335 -	SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &(format->SDL_GL_DEPTH_SIZE));
   1.336 -	SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &(format->SDL_GL_STENCIL_SIZE));
   1.337 -	SDL_GL_GetAttribute(SDL_GL_ACCUM_RED_SIZE, &(format->SDL_GL_ACCUM_RED_SIZE));
   1.338 -	SDL_GL_GetAttribute(SDL_GL_ACCUM_GREEN_SIZE, &(format->SDL_GL_ACCUM_GREEN_SIZE));
   1.339 -	SDL_GL_GetAttribute(SDL_GL_ACCUM_BLUE_SIZE, &(format->SDL_GL_ACCUM_BLUE_SIZE));
   1.340 -	SDL_GL_GetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, &(format->SDL_GL_ACCUM_ALPHA_SIZE));
   1.341 -	SDL_GL_GetAttribute(SDL_GL_STEREO, &(format->SDL_GL_STEREO));
   1.342 -	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &(format->SDL_GL_MULTISAMPLEBUFFERS));
   1.343 -	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &(format->SDL_GL_MULTISAMPLESAMPLES));
   1.344 -	SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &(format->SDL_GL_ACCELERATED_VISUAL));
   1.345 -	SDL_GL_GetAttribute(SDL_GL_RETAINED_BACKING, &(format->SDL_GL_RETAINED_BACKING));
   1.346 -}
   1.347 -
   1.348 +/*
   1.349 +	This causes an emitter to explode in a circular bloom of dust particles
   1.350 +*/
   1.351  void explodeEmitter(struct particle *emitter) {
   1.352 -
   1.353 +	/* first off, we're done with this particle, so turn active off */
   1.354  	emitter->isActive = 0;
   1.355 -	
   1.356  	int i;
   1.357  	for (i=0; i<200; i++) {
   1.358  		
   1.359 -		if (num_active_particles >= MAX_PARTICLES) return;
   1.360 +		if (num_active_particles >= MAX_PARTICLES)
   1.361 +			return;
   1.362  		
   1.363 +		/* come up with a random angle and speed for new particle */
   1.364  		float theta = randomFloat(0, 2.0f * 3.141592);
   1.365 -		float max = 3.0f;
   1.366 -		float speed = randomFloat(0.00, powf(0.17, max));
   1.367 -		speed = powf(speed, 1.0f / max);
   1.368 +		float exponent = 3.0f;
   1.369 +		float speed = randomFloat(0.00, powf(0.17, exponent));
   1.370 +		speed = powf(speed, 1.0f / exponent);
   1.371  		
   1.372 +		/*select the particle at the end of our array */
   1.373  		struct particle *p = &particles[num_active_particles];
   1.374 +		
   1.375 +		/* set the particles properties */
   1.376  		p->xvel = speed * cos(theta);
   1.377  		p->yvel = speed * sin(theta);
   1.378  		p->x = emitter->x + emitter->xvel;
   1.379  		p->y = emitter->y + emitter->yvel;
   1.380  		p->isActive = 1;
   1.381  		p->type = dust;
   1.382 +		p->size = 15;
   1.383 +		/* inherit emitter's color */
   1.384  		p->color[0] = emitter->color[0];
   1.385  		p->color[1] = emitter->color[1];
   1.386  		p->color[2] = emitter->color[2];
   1.387  		p->color[3] = 255;
   1.388 -
   1.389 -		p->size = 15;
   1.390 -		
   1.391 +		/* our array has expanded at the end */
   1.392  		num_active_particles++;
   1.393 -		
   1.394  	}
   1.395  	
   1.396  }
   1.397 -
   1.398 -void spawnParticleFromEmitter(struct particle *emitter) {
   1.399 +/*
   1.400 +	This spawns a trail particle from an emitter
   1.401 +*/
   1.402 +void spawnTrailFromEmitter(struct particle *emitter) {
   1.403  	
   1.404 -	if (num_active_particles >= MAX_PARTICLES) return;
   1.405 +	if (num_active_particles >= MAX_PARTICLES)
   1.406 +		return;
   1.407 +		
   1.408 +	/* select the particle at the slot at the end of our array */
   1.409 +	struct particle *p = &particles[num_active_particles];
   1.410  	
   1.411 -	struct particle *p = &particles[num_active_particles];
   1.412 +	/* set position and velocity to roughly that of the emitter */
   1.413  	p->x = emitter->x + randomFloat(-3.0, 3.0);
   1.414  	p->y = emitter->y + emitter->size / 2.0f;
   1.415  	p->xvel = emitter->xvel + randomFloat(-0.005, 0.005);
   1.416  	p->yvel = emitter->yvel + 0.1;
   1.417 +	
   1.418 +	/* set the color to a random-ish orangy type color */
   1.419  	p->color[0] = (0.8f + randomFloat(-0.1, 0.0)) * 255;
   1.420  	p->color[1] = (0.4f + randomFloat(-0.1, 0.1)) * 255;
   1.421  	p->color[2] = (0.0f + randomFloat(0.0, 0.2)) * 255;
   1.422  	p->color[3] = (0.7f) * 255;
   1.423 +	
   1.424 +	/* set other attributes */
   1.425  	p->size = 10;
   1.426  	p->type = trail;
   1.427  	p->isActive = 1;
   1.428 +	
   1.429 +	/* our array has expanded at the end */
   1.430  	num_active_particles++;
   1.431  	
   1.432  }
   1.433 +/*
   1.434 +	spawns a new emitter particle at the bottom of the screen
   1.435 +    destined for the point (x,y).
   1.436 +*/
   1.437 +void spawnEmitterParticle(GLfloat x, GLfloat y) {
   1.438 +
   1.439 +	if (num_active_particles >= MAX_PARTICLES)
   1.440 +		return;
   1.441  	
   1.442 -void spawnEmitterParticle(int x, int y) {
   1.443 -
   1.444 -	if (num_active_particles >= MAX_PARTICLES) return;
   1.445 +	/* find particle at endpoint of array */
   1.446 +	struct particle *p = &particles[num_active_particles];
   1.447  	
   1.448 -	struct particle *p = &particles[num_active_particles];
   1.449 +	/* set the color randomly */
   1.450 +	switch(rand() % 4) {
   1.451 +		case 0:
   1.452 +			p->color[0] = 255;
   1.453 +			p->color[1] = 100;
   1.454 +			p->color[2] = 100;
   1.455 +			break;
   1.456 +		case 1:
   1.457 +			p->color[0] = 100;
   1.458 +			p->color[1] = 255;
   1.459 +			p->color[2] = 100;
   1.460 +			break;
   1.461 +		case 2:
   1.462 +			p->color[0] = 100;
   1.463 +			p->color[1] = 100;
   1.464 +			p->color[2] = 255;
   1.465 +			break;
   1.466 +		case 3:
   1.467 +			p->color[0] = 255;
   1.468 +			p->color[1] = 150;
   1.469 +			p->color[2] = 50;
   1.470 +			break;						
   1.471 +	}	
   1.472 +	p->color[3] = 255;
   1.473 +	/* set position to (x, SCREEN_HEIGHT) */
   1.474  	p->x = x;
   1.475  	p->y = SCREEN_HEIGHT;
   1.476 +	/* set velocity so that terminal point is (x,y) */
   1.477  	p->xvel = 0;
   1.478 -	p->yvel = -sqrt(2*ACCEL*(SCREEN_HEIGHT-y) + VEL_BEFORE_EXPLODE * VEL_BEFORE_EXPLODE);
   1.479 -	p->color[0] = 1.0 * 255;
   1.480 -	p->color[1] = 0.4 * 255;
   1.481 -	p->color[2] = 0.4 * 255;
   1.482 -	p->color[3] = 1.0f * 255;
   1.483 +	p->yvel = -sqrt(2*ACCEL*(SCREEN_HEIGHT-y));
   1.484 +	/* set other attributes */
   1.485  	p->size = 10;
   1.486  	p->type = emitter;
   1.487 -	p->framesSinceEmission = 0;
   1.488  	p->isActive = 1;
   1.489 +	/* our array has expanded at the end */
   1.490  	num_active_particles++;
   1.491  }
   1.492  
   1.493 +/* just sets the endpoint of the particle array to element zero */
   1.494  void initializeParticles(void) {
   1.495 -	
   1.496  	num_active_particles = 0;
   1.497 -	
   1.498  }
   1.499  
   1.500  /*
   1.501 - loads the brush texture
   1.502 +	loads the particle texture
   1.503   */
   1.504  void initializeTexture() {
   1.505 -	SDL_Surface *bmp_surface;
   1.506 +	
   1.507 +	int bpp;								/* texture bits per pixel */
   1.508 +	Uint32 Rmask, Gmask, Bmask, Amask;		/* masks for pixel format passed into OpenGL */
   1.509 +	SDL_Surface *bmp_surface;				/* the bmp is loaded here */
   1.510 +	SDL_Surface *bmp_surface_rgba8888;		/* this serves as a destination to convert the BMP
   1.511 +											to format passed into OpenGL */
   1.512 +	
   1.513  	bmp_surface = SDL_LoadBMP("stroke.bmp");
   1.514  	if (bmp_surface == NULL) {
   1.515  		fatalError("could not load stroke.bmp");
   1.516  	}
   1.517 -	flashTextureID = SDL_CreateTextureFromSurface(SDL_PIXELFORMAT_ABGR8888, bmp_surface);
   1.518 +
   1.519 +	/* Grab info about format that will be passed into OpenGL */
   1.520 +	SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
   1.521 +	/* Create surface that will hold pixels passed into OpenGL */
   1.522 +	bmp_surface_rgba8888 = SDL_CreateRGBSurface(0, bmp_surface->w, bmp_surface->h, bpp, Rmask, Gmask, Bmask, Amask);	
   1.523 +	/* Blit to this surface, effectively converting the format */
   1.524 +	SDL_BlitSurface(bmp_surface, NULL, bmp_surface_rgba8888, NULL);
   1.525 +	
   1.526 +	glGenTextures(1, &particleTextureID);
   1.527 +	glBindTexture(GL_TEXTURE_2D, particleTextureID);
   1.528 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,\
   1.529 +		nextPowerOfTwo(bmp_surface->w),\
   1.530 +		nextPowerOfTwo(bmp_surface->h),\
   1.531 +		0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   1.532 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1.533 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1.534 +	/* this is where we actually pass in the pixel data */
   1.535 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bmp_surface->w, bmp_surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmp_surface_rgba8888->pixels);
   1.536 +	
   1.537 +	/* free bmp surface and converted bmp surface */
   1.538  	SDL_FreeSurface(bmp_surface);
   1.539 -	if (flashTextureID == 0) {
   1.540 -		fatalError("could not create brush texture");
   1.541 -	}
   1.542 -	glEnable(GL_TEXTURE_2D);
   1.543 -	glEnable(GL_BLEND);
   1.544 -	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   1.545 +	SDL_FreeSurface(bmp_surface_rgba8888);
   1.546 +
   1.547  }
   1.548  
   1.549  int main(int argc, char *argv[]) {
   1.550  	
   1.551 -	SDL_WindowID windowID;	/* ID of main window */
   1.552 -	Uint32 startFrame;		/* time frame began to process */
   1.553 -	Uint32 endFrame;		/* time frame ended processing */
   1.554 -	Uint32 delay;			/* time to pause waiting to draw next frame */
   1.555 -	int done;				/* should we clean up and exit? */
   1.556 -	
   1.557 -	struct glformat requested, obtained;
   1.558 +	SDL_WindowID windowID;		/* ID of main window */
   1.559 +	Uint32 startFrame;			/* time frame began to process */
   1.560 +	Uint32 endFrame;			/* time frame ended processing */
   1.561 +	Uint32 delay;				/* time to pause waiting to draw next frame */
   1.562 +	int done;					/* should we clean up and exit? */
   1.563  	
   1.564  	/* initialize SDL */
   1.565  	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
   1.566  		fatalError("Could not initialize SDL");
   1.567  	}
   1.568 -	
   1.569 +	/* seed the random number generator */
   1.570  	srand(time(NULL));
   1.571 -	
   1.572 -	SDL_GL_LoadLibrary(NULL);
   1.573 -		
   1.574 -	SDL_memset(&requested, 0, sizeof(requested));
   1.575 -	requested.SDL_GL_RED_SIZE = 5;
   1.576 -	requested.SDL_GL_GREEN_SIZE = 6; 
   1.577 -	requested.SDL_GL_BLUE_SIZE = 5;
   1.578 -	requested.SDL_GL_ALPHA_SIZE = 0;
   1.579 -	requested.SDL_GL_DEPTH_SIZE = 0;
   1.580 -	requested.SDL_GL_RETAINED_BACKING = 0;
   1.581 -	requested.SDL_GL_ACCELERATED_VISUAL = 1;	
   1.582 -	
   1.583 -	setOpenGLAttributes(&requested);
   1.584 -	
   1.585 +	/*	
   1.586 +		request some OpenGL parameters
   1.587 +		that may speed drawing
   1.588 +	*/
   1.589 +	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
   1.590 +	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
   1.591 +	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
   1.592 +	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
   1.593 +	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
   1.594 +	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
   1.595 +	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
   1.596 +
   1.597  	/* create main window and renderer */
   1.598  	windowID = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,\
   1.599  								SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_BORDERLESS);
   1.600  	SDL_CreateRenderer(windowID, 0, 0);		
   1.601  	
   1.602 -	printf("Requested:\n");
   1.603 -	printOpenGLAttributes(&requested);
   1.604 -	
   1.605 -	printf("obtained:\n");
   1.606 -	getOpenGLAttributes(&obtained);
   1.607 -	printOpenGLAttributes(&obtained);	
   1.608 -	
   1.609 +	/* load the particle texture */
   1.610  	initializeTexture();
   1.611  
   1.612 +	/*	check if GL_POINT_SIZE_ARRAY_OES is supported
   1.613 +		this is used to give each particle its own size
   1.614 +	*/
   1.615 +	pointSizeExtensionSupported = SDL_GL_ExtensionSupported("GL_OES_point_size_array");
   1.616 +	
   1.617 +	/* set up some OpenGL state */
   1.618 +	glEnable(GL_TEXTURE_2D);
   1.619 +	glEnable(GL_BLEND);
   1.620 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   1.621 +	glEnableClientState(GL_VERTEX_ARRAY);	
   1.622 +	glEnableClientState(GL_COLOR_ARRAY);
   1.623 +	
   1.624 +	glEnable(GL_POINT_SPRITE_OES);
   1.625 +	glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
   1.626 +	
   1.627 +	if (pointSizeExtensionSupported) {
   1.628 +		/* we use this to set the sizes of all the particles */
   1.629 +		glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
   1.630 +	}
   1.631 +	else {
   1.632 +		/* if extension not available then all particles have size 10 */
   1.633 +		glPointSize(10);
   1.634 +	}
   1.635 +	
   1.636  	done = 0;
   1.637  	/* enter main loop */
   1.638  	while(!done) {
   1.639 @@ -405,7 +395,6 @@
   1.640  				done = 1;
   1.641              }
   1.642  			if (event.type == SDL_MOUSEBUTTONDOWN) {
   1.643 -				printf("mouse down\n");
   1.644  				int which = event.button.which;
   1.645  				int x, y;
   1.646  				SDL_SelectMouse(which);
   1.647 @@ -413,7 +402,8 @@
   1.648  				spawnEmitterParticle(x, y);
   1.649  			}
   1.650          }
   1.651 -		render();
   1.652 +		stepParticles();
   1.653 +		drawParticles();
   1.654  		endFrame = SDL_GetTicks();
   1.655  		
   1.656  		/* figure out how much time we have left, and then sleep */
   1.657 @@ -424,15 +414,12 @@
   1.658  		if (delay > 0) {
   1.659  			SDL_Delay(delay);
   1.660  		}
   1.661 -			
   1.662 -		//SDL_Delay(delay);
   1.663  	}
   1.664  	
   1.665  	/* delete textures */
   1.666 -	
   1.667 +	glDeleteTextures(1, &particleTextureID);
   1.668  	/* shutdown SDL */
   1.669  	SDL_Quit();
   1.670  	
   1.671  	return 0;
   1.672 -	
   1.673  }
   1.674 \ No newline at end of file