-
-
Save alansley/e5210b33966fbbdc8c37 to your computer and use it in GitHub Desktop.
Fixed SDL2 Fireworks (missing orthographic projection matrix setup)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.).