Skip to content

Instantly share code, notes, and snippets.

@DanielOaks
Last active December 18, 2015 02:48
Show Gist options
  • Save DanielOaks/5713561 to your computer and use it in GitHub Desktop.
Save DanielOaks/5713561 to your computer and use it in GitHub Desktop.
OpenGL 2/3d particle test. First time doing anything in C/C++ for years, beware
// First (proper) try at OpenGL programming, and first bit of C-like stuff
// for years, besides a quick dabble in C# ; caveat emptor
//
// Daniel Oaks 2013, public domain etc
//
// g++ -Wall -L/usr/lib -lGL -lGLU -lglut --std=c++11 particles.cpp -o particles
#include <stdio.h>
#include <stdlib.h>
#include <random>
#include <functional>
#include <list>
#include <GL/glut.h>
using namespace std;
#define GRAVITY_STRENGTH (-0.2)
#define NUMBER_OF_PARTICLES (30)
#define PARTICLE_AGE (60)
// Holds X, Y, and Z values, of either direction or forces
//
class Xyz
{
private:
float x, y, z;
public:
float getX();
void setX(float value);
void affectX(float value);
float getY();
void setY(float value);
void affectY(float value);
float getZ();
void setZ(float value);
void affectZ(float value);
};
// X
float Xyz::getX()
{
return x;
}
void Xyz::setX(float value)
{
x = value;
}
void Xyz::affectX(float value)
{
setX(getX() + value);
}
// Y
float Xyz::getY()
{
return y;
}
void Xyz::setY(float value)
{
y = value;
}
void Xyz::affectY(float value)
{
setY(getY() + value);
}
// Z
float Xyz::getZ()
{
return z;
}
void Xyz::setZ(float value)
{
z = value;
}
void Xyz::affectZ(float value)
{
setZ(getZ() + value);
}
// Holds a point, the forces affecting it, and allows simple affecting of it
//
class Point {
private:
Xyz forces;
void initialize(float position_x, float position_y, float position_z);
public:
Xyz location;
long age;
Point(float position_x, float position_y, float position_z);
void affect_by_forces(float force_on_x, float force_on_y, float force_on_z);
void affect_by_gravity();
void tick();
void draw();
};
Point::Point(float position_x, float position_y, float position_z)
{
initialize(position_x, position_y, position_z);
}
void Point::initialize(float position_x, float position_y, float position_z)
{
location.setX(position_x);
location.setY(position_y);
location.setZ(position_z);
forces.setX(0.0);
forces.setY(0.0);
forces.setZ(0.0);
age = PARTICLE_AGE;
}
void Point::affect_by_forces(float force_on_x, float force_on_y, float force_on_z)
{
forces.affectX(force_on_x);
forces.affectY(force_on_y);
forces.affectZ(force_on_z);
}
void Point::affect_by_gravity()
{
forces.affectY(GRAVITY_STRENGTH);
}
void Point::tick()
{
age--;
if (age < 0){
age = 0;
}
location.affectX(forces.getX());
location.affectY(forces.getY());
location.affectZ(forces.getZ());
}
void Point::draw()
{
glBegin(GL_POINTS);
glColor4f (1.0, (age / (float) PARTICLE_AGE), ((age / 2.3) / (float) PARTICLE_AGE), 1.0);
glVertex3f(location.getX(), location.getY(), location.getZ());
glEnd();
}
// Main program
//
// our particles
list<Point> particle_list;
// random!
std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(-7.0, 7.0);
auto random_force = std::bind(distribution, generator);
std::default_random_engine grav_generator;
std::uniform_real_distribution<double> grav_distribution(3.5, 10.0);
auto random_grav_force = std::bind(grav_distribution, grav_generator);
// this makes a gradient background, but that seems to slooooooooow
// particles down a whole bunch
void drawBackground()
{
glBegin(GL_QUADS);
//red color
glColor4f(0.05,0.0,0.2,1.0);
glVertex3f(-1000.0, 1000.0,-1050.0);
glVertex3f(-1000.0,-1000.0,-1050.0);
//blue color
glColor4f(0.05,0.0,0.1,1.0);
glVertex3f(1000.0,-1000.0,-1050.0);
glVertex3f(1000.0, 1000.0,-1050.0);
glEnd();
}
void changeSize(int w, int h)
{
// prevent divide-by-zero, when window height of zero
if(h == 0) {
h = 1;
}
float ratio = (1.0 * w) / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45, ratio, 1, 1060);
glMatrixMode(GL_MODELVIEW);
}
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw current particles
list<Point>::iterator i;
for(i=particle_list.begin(); i != particle_list.end(); ++i) {
i->affect_by_gravity();
i->tick();
i->draw();
}
// add new particle
for(int j = 0; j < NUMBER_OF_PARTICLES; j++) {
particle_list.push_back(Point(0.0, -30.0, -1000.0));
particle_list.back().affect_by_forces((float) random_force(), (float) random_force() + (float) random_grav_force(), 0.0);
}
// remove front particle if possible
while (particle_list.front().age == 0) {
particle_list.pop_front();
}
glutSwapBuffers();
}
// ticks drawing function, keeps time in sync and all
// so yeah, this doesn't do anything yet... shh, I'll fix it later
long milliseconds = 0;
void idleTick(void)
{
renderScene();
}
// actually do all our stuff
int main(int argc, char **argv)
{
// initialize glut
glutInit(&argc, argv);
glutInitWindowPosition(30, 30);
glutInitWindowSize(500, 500);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("So yeah...");
glClearColor(0.06, 0.0, 0.13, 1.0);
// callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(idleTick);
// loop
glutMainLoop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment