diff XCodeiPhoneOS/Demos/src/fireworks.c @ 2417:ac26bd83db1f gsoc2008_iphone

Cleaned up code, added comments, added randomized colors, added check for extension GL_POINT_SIZE_ARRAY_OES, which not all OpenGL ES systems have.
author Holmes Futrell <hfutrell@umail.ucsb.edu>
date Wed, 13 Aug 2008 23:10:51 +0000
parents 36bcf13ccb48
children
line wrap: on
line diff
--- a/XCodeiPhoneOS/Demos/src/fireworks.c	Wed Aug 13 20:56:21 2008 +0000
+++ b/XCodeiPhoneOS/Demos/src/fireworks.c	Wed Aug 13 23:10:51 2008 +0000
@@ -5,135 +5,100 @@
  */
 
 #include "SDL.h"
-#include "math.h"
+#include "SDL_opengles.h"
 #include "common.h"
 #include <math.h>
 #include <time.h>
-#include <OpenGLES/ES1/gl.h>
 
 #define MILLESECONDS_PER_FRAME 16	/* about 60 frames per second */
-#define ACCEL 0.0001f
-#define WIND_RESISTANCE 0.00005f
-#define MAX_PARTICLES 2000
-#define VEL_BEFORE_EXPLODE 0.0f
+#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 */
 
-SDL_TextureID flashTextureID;
-
-
+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 */
 
-struct glformat {
-	int SDL_GL_RED_SIZE;
-	int SDL_GL_GREEN_SIZE;
-	int SDL_GL_BLUE_SIZE;
-	int SDL_GL_ALPHA_SIZE;
-	int SDL_GL_BUFFER_SIZE;
-	int SDL_GL_DOUBLEBUFFER;
-	int SDL_GL_DEPTH_SIZE;
-	int SDL_GL_STENCIL_SIZE;
-	int SDL_GL_ACCUM_RED_SIZE;
-	int SDL_GL_ACCUM_GREEN_SIZE;
-	int SDL_GL_ACCUM_BLUE_SIZE;
-	int SDL_GL_ACCUM_ALPHA_SIZE;
-	int SDL_GL_STEREO;
-	int SDL_GL_MULTISAMPLEBUFFERS;
-	int SDL_GL_MULTISAMPLESAMPLES;
-	int SDL_GL_ACCELERATED_VISUAL;
-	int SDL_GL_RETAINED_BACKING;
-};
-
-struct particle {
-
-	GLfloat x;
-	GLfloat y;
-	GLubyte color[4];
-	GLfloat size;
-	GLfloat xvel;
-	GLfloat yvel;
-	int isActive;
-	enum particleType type;
-	int framesSinceEmission;
-} particles[MAX_PARTICLES];
-
-void spawnParticleFromEmitter(struct particle *emitter);
-void explodeEmitter(struct particle *emitter);
-
-static int num_active_particles;
+static int num_active_particles; /* how many members of the particle array are actually being drawn / animated? */
 
-static void getError(const char *prefix)
-{
-    const char *error;
-	
-	GLenum result = glGetError();
-	if (result == GL_NO_ERROR)
-		return;
-	
-    switch (result) {
-		case GL_NO_ERROR:
-			error = "GL_NO_ERROR";
-			break;
-		case GL_INVALID_ENUM:
-			error = "GL_INVALID_ENUM";
-			break;
-		case GL_INVALID_VALUE:
-			error = "GL_INVALID_VALUE";
-			break;
-		case GL_INVALID_OPERATION:
-			error = "GL_INVALID_OPERATION";
-			break;
-		case GL_STACK_OVERFLOW:
-			error = "GL_STACK_OVERFLOW";
-			break;
-		case GL_STACK_UNDERFLOW:
-			error = "GL_STACK_UNDERFLOW";
-			break;
-		case GL_OUT_OF_MEMORY:
-			error = "GL_OUT_OF_MEMORY";
-			break;
-		default:
-			error = "UNKNOWN";
-			break;
-    }
-    printf("%s: %s\n", prefix, error);
+/* 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;
 }
-
-void render(void) {
-		
-	/* draw the background */
-	glClear(GL_COLOR_BUFFER_BIT);
-	
+/*	
+	steps each active particle by timestep MILLESECONDS_PER_FRAME
+*/
+void stepParticles(void) {
+	int i;
 	struct particle *slot = particles;
 	struct particle *curr = particles;
-	int i;
 	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_HEIGHT) curr->isActive = 0;
-			if (curr->y < 0) curr->isActive = 0;
+			else if (curr->y < 0) curr->isActive = 0;
 			if (curr->x > SCREEN_WIDTH) curr->isActive = 0;
-			if (curr->x < 0) 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) {
-				spawnParticleFromEmitter(curr);
-				curr->framesSinceEmission = 0;
-				if (curr->yvel > -VEL_BEFORE_EXPLODE) {
+				/* if we're an emitter, spawn a trail */
+				spawnTrailFromEmitter(curr);
+				/* if we've reached our peak, explode */
+				if (curr->yvel > 0.0) {
 					explodeEmitter(curr);
 				}
-				curr->framesSinceEmission++;
 			}
 			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;
@@ -141,260 +106,285 @@
 					curr->yvel -= normy * WIND_RESISTANCE * MILLESECONDS_PER_FRAME;
 				}
 				else {
-					curr->xvel = 0;
-					curr->yvel = 0;
+					curr->xvel = curr->yvel = 0; /* stop particle */
 				}
 				
-				if (curr->color[3] <= MILLESECONDS_PER_FRAME * 0.0005f * 255) {
+				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 {
-					curr->color[3] -= MILLESECONDS_PER_FRAME * 0.0005f * 255;
+					/* 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;
 				
 			}
 			
-			*(slot++) = *curr;
-		}
+			/* 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() {
 	
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, 1);
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glVertexPointer(2, GL_FLOAT, sizeof(struct particle), particles + 0);
-	getError("vertices");
+	/* draw the background */
+	glClear(GL_COLOR_BUFFER_BIT);
 	
-	glEnableClientState(GL_COLOR_ARRAY);
+	/* 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);
-	getError("colors");
-
-	glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
-	getError("enable client state");
-	glPointSizePointerOES(GL_FLOAT, sizeof(struct particle), &(particles[0].size));	
-	getError("point size");
-
-	glEnable(GL_POINT_SPRITE_OES);
+	
+	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);	
-	getError("glDrawArrays");
-
-		
+	
 	/* update screen */
-	SDL_RenderPresent();
+	SDL_RenderPresent();	
 	
 }
-
-void printOpenGLAttributes(struct glformat *format) {
-	printf("\tSDL_GL_RED_SIZE = %d\n", format->SDL_GL_RED_SIZE);
-	printf("\tSDL_GL_GREEN_SIZE = %d\n", format->SDL_GL_GREEN_SIZE);
-	printf("\tSDL_GL_BLUE_SIZE = %d\n", format->SDL_GL_BLUE_SIZE);
-	printf("\tSDL_GL_ALPHA_SIZE = %d\n", format->SDL_GL_ALPHA_SIZE);
-	printf("\tSDL_GL_BUFFER_SIZE = %d\n", format->SDL_GL_BUFFER_SIZE);
-	printf("\tSDL_GL_DOUBLEBUFFER = %d\n", format->SDL_GL_DOUBLEBUFFER);
-	printf("\tSDL_GL_DEPTH_SIZE = %d\n", format->SDL_GL_DEPTH_SIZE);
-	printf("\tSDL_GL_STENCIL_SIZE = %d\n", format->SDL_GL_STENCIL_SIZE);
-	printf("\tSDL_GL_ACCUM_RED_SIZE = %d\n", format->SDL_GL_ACCUM_RED_SIZE);
-	printf("\tSDL_GL_ACCUM_GREEN_SIZE = %d\n", format->SDL_GL_ACCUM_GREEN_SIZE);
-	printf("\tSDL_GL_ACCUM_BLUE_SIZE = %d\n", format->SDL_GL_ACCUM_BLUE_SIZE);
-	printf("\tSDL_GL_ACCUM_ALPHA_SIZE = %d\n", format->SDL_GL_ACCUM_ALPHA_SIZE);
-	printf("\tSDL_GL_STEREO = %d\n", format->SDL_GL_STEREO);
-	printf("\tSDL_GL_MULTISAMPLEBUFFERS = %d\n", format->SDL_GL_MULTISAMPLEBUFFERS);
-	printf("\tSDL_GL_MULTISAMPLESAMPLES = %d\n", format->SDL_GL_MULTISAMPLESAMPLES);
-	printf("\tSDL_GL_ACCELERATED_VISUAL = %d\n", format->SDL_GL_ACCELERATED_VISUAL);
-	printf("\tSDL_GL_RETAINED_BACKING = %d\n", format->SDL_GL_RETAINED_BACKING);	
-}
-
-void setOpenGLAttributes(struct glformat *format) {
-	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, format->SDL_GL_RED_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, format->SDL_GL_GREEN_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, format->SDL_GL_BLUE_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, format->SDL_GL_ALPHA_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, format->SDL_GL_BUFFER_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, format->SDL_GL_DOUBLEBUFFER);
-	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, format->SDL_GL_DEPTH_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, format->SDL_GL_STENCIL_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, format->SDL_GL_ACCUM_RED_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, format->SDL_GL_ACCUM_GREEN_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, format->SDL_GL_ACCUM_BLUE_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, format->SDL_GL_ACCUM_ALPHA_SIZE);
-	SDL_GL_SetAttribute(SDL_GL_STEREO, format->SDL_GL_STEREO);
-	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, format->SDL_GL_MULTISAMPLEBUFFERS);
-	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, format->SDL_GL_MULTISAMPLESAMPLES);
-	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, format->SDL_GL_ACCELERATED_VISUAL);
-	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, format->SDL_GL_RETAINED_BACKING);
-}
-
-void getOpenGLAttributes(struct glformat *format) {
-		
-	SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &(format->SDL_GL_RED_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &(format->SDL_GL_GREEN_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &(format->SDL_GL_BLUE_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &(format->SDL_GL_ALPHA_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_BUFFER_SIZE, &(format->SDL_GL_BUFFER_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &(format->SDL_GL_DOUBLEBUFFER));
-	SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &(format->SDL_GL_DEPTH_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &(format->SDL_GL_STENCIL_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_ACCUM_RED_SIZE, &(format->SDL_GL_ACCUM_RED_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_ACCUM_GREEN_SIZE, &(format->SDL_GL_ACCUM_GREEN_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_ACCUM_BLUE_SIZE, &(format->SDL_GL_ACCUM_BLUE_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, &(format->SDL_GL_ACCUM_ALPHA_SIZE));
-	SDL_GL_GetAttribute(SDL_GL_STEREO, &(format->SDL_GL_STEREO));
-	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &(format->SDL_GL_MULTISAMPLEBUFFERS));
-	SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &(format->SDL_GL_MULTISAMPLESAMPLES));
-	SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &(format->SDL_GL_ACCELERATED_VISUAL));
-	SDL_GL_GetAttribute(SDL_GL_RETAINED_BACKING, &(format->SDL_GL_RETAINED_BACKING));
-}
-
+/*
+	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;
+		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 max = 3.0f;
-		float speed = randomFloat(0.00, powf(0.17, max));
-		speed = powf(speed, 1.0f / max);
+		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;
-
-		p->size = 15;
-		
+		/* our array has expanded at the end */
 		num_active_particles++;
-		
 	}
 	
 }
-
-void spawnParticleFromEmitter(struct particle *emitter) {
+/*
+	This spawns a trail particle from an emitter
+*/
+void spawnTrailFromEmitter(struct particle *emitter) {
 	
-	if (num_active_particles >= MAX_PARTICLES) return;
+	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];
 	
-	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++;
 	
 }
-	
-void spawnEmitterParticle(int x, int y) {
+/*
+	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;
+	if (num_active_particles >= MAX_PARTICLES)
+		return;
+	
+	/* find particle at endpoint of array */
+	struct particle *p = &particles[num_active_particles];
 	
-	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_HEIGHT) */
 	p->x = x;
 	p->y = SCREEN_HEIGHT;
+	/* set velocity so that terminal point is (x,y) */
 	p->xvel = 0;
-	p->yvel = -sqrt(2*ACCEL*(SCREEN_HEIGHT-y) + VEL_BEFORE_EXPLODE * VEL_BEFORE_EXPLODE);
-	p->color[0] = 1.0 * 255;
-	p->color[1] = 0.4 * 255;
-	p->color[2] = 0.4 * 255;
-	p->color[3] = 1.0f * 255;
+	p->yvel = -sqrt(2*ACCEL*(SCREEN_HEIGHT-y));
+	/* set other attributes */
 	p->size = 10;
 	p->type = emitter;
-	p->framesSinceEmission = 0;
 	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 brush texture
+	loads the particle texture
  */
 void initializeTexture() {
-	SDL_Surface *bmp_surface;
+	
+	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");
 	}
-	flashTextureID = SDL_CreateTextureFromSurface(SDL_PIXELFORMAT_ABGR8888, bmp_surface);
+
+	/* 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);
-	if (flashTextureID == 0) {
-		fatalError("could not create brush texture");
-	}
-	glEnable(GL_TEXTURE_2D);
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+	SDL_FreeSurface(bmp_surface_rgba8888);
+
 }
 
 int main(int argc, char *argv[]) {
 	
-	SDL_WindowID windowID;	/* ID of main window */
-	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? */
-	
-	struct glformat requested, obtained;
+	SDL_WindowID windowID;		/* ID of main window */
+	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));
-	
-	SDL_GL_LoadLibrary(NULL);
-		
-	SDL_memset(&requested, 0, sizeof(requested));
-	requested.SDL_GL_RED_SIZE = 5;
-	requested.SDL_GL_GREEN_SIZE = 6; 
-	requested.SDL_GL_BLUE_SIZE = 5;
-	requested.SDL_GL_ALPHA_SIZE = 0;
-	requested.SDL_GL_DEPTH_SIZE = 0;
-	requested.SDL_GL_RETAINED_BACKING = 0;
-	requested.SDL_GL_ACCELERATED_VISUAL = 1;	
-	
-	setOpenGLAttributes(&requested);
-	
+	/*	
+		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 */
 	windowID = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,\
 								SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_BORDERLESS);
 	SDL_CreateRenderer(windowID, 0, 0);		
 	
-	printf("Requested:\n");
-	printOpenGLAttributes(&requested);
-	
-	printf("obtained:\n");
-	getOpenGLAttributes(&obtained);
-	printOpenGLAttributes(&obtained);	
-	
+	/* 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 */
+	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) {
@@ -405,7 +395,6 @@
 				done = 1;
             }
 			if (event.type == SDL_MOUSEBUTTONDOWN) {
-				printf("mouse down\n");
 				int which = event.button.which;
 				int x, y;
 				SDL_SelectMouse(which);
@@ -413,7 +402,8 @@
 				spawnEmitterParticle(x, y);
 			}
         }
-		render();
+		stepParticles();
+		drawParticles();
 		endFrame = SDL_GetTicks();
 		
 		/* figure out how much time we have left, and then sleep */
@@ -424,15 +414,12 @@
 		if (delay > 0) {
 			SDL_Delay(delay);
 		}
-			
-		//SDL_Delay(delay);
 	}
 	
 	/* delete textures */
-	
+	glDeleteTextures(1, &particleTextureID);
 	/* shutdown SDL */
 	SDL_Quit();
 	
 	return 0;
-	
 }
\ No newline at end of file