Skip to content

Instantly share code, notes, and snippets.

@alansley
Created February 21, 2016 03:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alansley/e5210b33966fbbdc8c37 to your computer and use it in GitHub Desktop.
Save alansley/e5210b33966fbbdc8c37 to your computer and use it in GitHub Desktop.
Fixed SDL2 Fireworks (missing orthographic projection matrix setup)
#include <iostream>
#include <SDL.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#pragma comment(lib, "opengl32.lib")
//#pragma comment(lib, "glu32.lib")
using std::cout;
using std::endl;
using namespace std;
// Define our initial screen width, height, and colour depth
GLint SCREEN_WIDTH = 800;
GLint SCREEN_HEIGHT = 600;
GLint SCREEN_BPP = 32;
// Define our SDL surface
SDL_Surface *surface;
const int FIREWORKS = 15; // Number of fireworks
const int FIREWORK_PARTICLES = 50; // Number of particles per firework
class Firework
{
public:
GLfloat x[FIREWORK_PARTICLES];
GLfloat y[FIREWORK_PARTICLES];
GLfloat xSpeed[FIREWORK_PARTICLES];
GLfloat ySpeed[FIREWORK_PARTICLES];
GLfloat red;
GLfloat blue;
GLfloat green;
GLfloat alpha;
GLint framesUntilLaunch;
GLfloat particleSize;
GLboolean hasExploded;
static const GLfloat baselineYSpeed;
static const GLfloat maxYSpeed;
static const GLfloat GRAVITY;
Firework(); // Constructor declaration
void initialise();
void move();
void explode();
};
const GLfloat Firework::GRAVITY = 0.05f;
const GLfloat Firework::baselineYSpeed = -4.0f;
const GLfloat Firework::maxYSpeed = -4.0f;
// Constructor implementation
Firework::Firework()
{
initialise();
}
void Firework::initialise()
{
// Pick an initial x location and random x/y speeds
float xLoc = (rand() / (float)RAND_MAX) * SCREEN_WIDTH;
float xSpeedVal = -2 + (rand() / (float)RAND_MAX) * 4.0f;
float ySpeedVal = baselineYSpeed + ((float)rand() / (float)RAND_MAX) * maxYSpeed;
// Set initial x/y location and speeds
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
{
x[loop] = xLoc;
y[loop] = SCREEN_HEIGHT + 10.0f; // Push the particle location down off the bottom of the screen
xSpeed[loop] = xSpeedVal;
ySpeed[loop] = ySpeedVal;
}
// Assign a random colour and full alpha (i.e. particle is completely opaque)
red = (rand() / (float)RAND_MAX);
green = (rand() / (float)RAND_MAX);
blue = (rand() / (float)RAND_MAX);
alpha = 1.0f;
// Firework will launch after a random amount of frames between 0 and 400
framesUntilLaunch = ((int)rand() % 400);
// Size of the particle (as thrown to glPointSize) - range is 1.0f to 4.0f
particleSize = 1.0f + ((float)rand() / (float)RAND_MAX) * 3.0f;
// Flag to keep trackof whether the firework has exploded or not
hasExploded = false;
cout << "Initialised a firework." << endl;
}
void Firework::move()
{
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
{
// Once the firework is ready to launch start moving the particles
if (framesUntilLaunch <= 0)
{
x[loop] += xSpeed[loop];
y[loop] += ySpeed[loop];
ySpeed[loop] += Firework::GRAVITY;
}
}
framesUntilLaunch--;
// Once a fireworks speed turns positive (i.e. at top of arc) - blow it up!
if (ySpeed[0] > 0.0f)
{
for (int loop2 = 0; loop2 < FIREWORK_PARTICLES; loop2++)
{
// Set a random x and y speed beteen -4 and + 4
xSpeed[loop2] = -4 + (rand() / (float)RAND_MAX) * 8;
ySpeed[loop2] = -4 + (rand() / (float)RAND_MAX) * 8;
}
cout << "Boom!" << endl;
hasExploded = true;
}
}
void Firework::explode()
{
for (int loop = 0; loop < FIREWORK_PARTICLES; loop++)
{
// Dampen the horizontal speed by 1% per frame
xSpeed[loop] *= 0.99;
// Move the particle
x[loop] += xSpeed[loop];
y[loop] += ySpeed[loop];
// Apply gravity to the particle's speed
ySpeed[loop] += Firework::GRAVITY;
}
// Fade out the particles (alpha is stored per firework, not per particle)
if (alpha > 0.0f)
{
alpha -= 0.01f;
}
else // Once the alpha hits zero reset the firework
{
initialise();
}
}
// Create our array of fireworks
Firework fw[FIREWORKS];
// Function to release/destroy our resources and exit
int quit(int returnCode)
{
// Clean up the window
SDL_Quit();
// Exit appropriately
exit(returnCode);
}
// Function to set some initial OpenGL state-machine properties
int initGL()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, -1); // Parameters: left, right, bottom, top, near, far
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Enable smooth shading (i.e. gouraud shading)
glShadeModel(GL_SMOOTH);
// Set our clear colour to black with full opacity. Syntax is (r, g, b, alpha).
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
// Disable depth testing (because we're working in 2D!)
glDisable(GL_DEPTH_TEST);
// Enable blending (we need this to be able to use an alpha component)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set the accumulation buffer clearing colour to black at 0,0f alpha
glClearAccum(0.0f, 0.0f, 0.0f, 1.0f);
glPointSize(5.0f);
return 0;
}
// Function to draw our OpenGL scene
int drawScene()
{
// Set our clear mode to clear the screen -only-
glClear(GL_COLOR_BUFFER_BIT);
// Take the contents of the current accumulation buffer and copy it to the colour buffer with each pixel multiplied by a factor
// i.e. we clear the screen, draw the last frame again (which we saved in the accumulation buffer), then draw our stuff at its new location on top of that
glAccum(GL_RETURN, 0.95f);
// Clear the accumulation buffer (don't worry, we re-grab the screen into the accumulation buffer after drawing our current frame!)
glClear(GL_ACCUM_BUFFER_BIT);
// Set ModelView matrix mode and reset to the default identity matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Displacement trick for exact pixelisation
glTranslatef(0.375, 0.375, 0);
// Draw fireworks
//cout << "Firework count is: " << Firework::fireworkCount << endl;
for (int loop = 0; loop < FIREWORKS; loop++)
{
for (int particleLoop = 0; particleLoop < FIREWORK_PARTICLES; particleLoop++)
{
// Set the point size of the firework particles (this needs to be called BEFORE opening the glBegin(GL_POINTS) section!)
glPointSize(fw[loop].particleSize);
glBegin(GL_POINTS);
// Set colour to yellow on way up, then whatever colour firework should be when exploded
if (fw[loop].hasExploded == false)
{
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
}
else
{
glColor4f(fw[loop].red, fw[loop].green, fw[loop].blue, fw[loop].alpha);
}
// Draw the point
glVertex2f(fw[loop].x[particleLoop], fw[loop].y[particleLoop]);
glEnd();
}
// Move the firework appropriately depending on its explosion state
if (fw[loop].hasExploded == false)
{
fw[loop].move();
}
else
{
fw[loop].explode();
}
}
return 0;
} // End of drawScene function
int main(int argc, char *argv[])
{
SDL_Window *window = 0;
SDL_Surface *windowSurface = 0;
SDL_Surface *imageSurface = 0;
int video_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
window = SDL_CreateWindow("SDL2 Fireworks", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, video_flags);
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
if (window == NULL) {
cout << "Failed to create window." << endl;
exit(1);
}
initGL();
bool isRunning = true;
SDL_Event ev;
while (isRunning) {
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
drawScene();
glFlush();
SDL_GL_SwapWindow(window);
glAccum(GL_ACCUM, 0.9f);
}
SDL_FreeSurface(imageSurface);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
@alansley
Copy link
Author

Actually - swap the order of lines 299 and 300 so it goes:

glAccum(GL_ACCUM, 0.9f);
SDL_GL_SwapWindow(window);

This gets rid of the missing frames when drawing (so it doesn't look all point-gap-point-gap-point-gap etc.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment