Index: graphics-pipeline_opengl.cpp
===================================================================
--- graphics-pipeline_opengl.cpp	(revision 83b5b4b93a32c66f32c2c36b7246de60b70c32ad)
+++ graphics-pipeline_opengl.cpp	(revision 0b1b52d45fd68804c3782b003e6516134b5d1e7f)
@@ -6,5 +6,6 @@
 using namespace std;
 
-GraphicsPipeline_OpenGL::GraphicsPipeline_OpenGL() {
+GraphicsPipeline_OpenGL::GraphicsPipeline_OpenGL(Viewport viewport) {
+   this->viewport = viewport;
 }
 
@@ -12,9 +13,48 @@
 }
 
+void GraphicsPipeline_OpenGL::addVaryingAttribute(VaryingAttribType attribType, GLint size, GLenum type,
+      size_t fieldOffset) {
+   // TODO: Throw an exception instead
+   if (type != GL_FLOAT && type != GL_UNSIGNED_INT) {
+      cout << "Unknown shader program attribute type: " << type << endl;
+      return;
+   }
+
+   VaryingAttribInfo attributeDesc;
+
+   attributeDesc.attribType = attribType;
+   attributeDesc.index = this->varyingAttribs.size();
+   attributeDesc.size = size;
+   attributeDesc.type = type;
+   attributeDesc.fieldOffset = fieldOffset;
+
+   this->varyingAttribs.push_back(attributeDesc);
+}
+
 void GraphicsPipeline_OpenGL::createPipeline(string vertShaderFile, string fragShaderFile) {
    shaderProgram = loadShaderProgram(vertShaderFile, fragShaderFile);
 
-   glGenVertexArrays(1, &vao);
-   numPoints = 0;
+   this->numPoints = 0;
+   glGenVertexArrays(1, &this->vao);
+   glBindVertexArray(this->vao);
+
+   vector<VaryingAttribInfo>::iterator it;
+   for (it = this->varyingAttribs.begin(); it != this->varyingAttribs.end(); it++) {
+      glEnableVertexAttribArray(it->index);
+
+      glGenBuffers(1, &it->buffer);
+      glBindBuffer(GL_ARRAY_BUFFER, it->buffer);
+
+      switch (it->type) {
+         case GL_FLOAT: {
+            glVertexAttribPointer(it->index, it->size, it->type, GL_FALSE, 0, NULL);
+            break;
+         }
+         case GL_UNSIGNED_INT: {
+            glVertexAttribIPointer(it->index, it->size, it->type, 0, NULL);
+            break;
+         }
+      }
+   }
 }
 
Index: graphics-pipeline_opengl.hpp
===================================================================
--- graphics-pipeline_opengl.hpp	(revision 83b5b4b93a32c66f32c2c36b7246de60b70c32ad)
+++ graphics-pipeline_opengl.hpp	(revision 0b1b52d45fd68804c3782b003e6516134b5d1e7f)
@@ -2,13 +2,33 @@
 #define _GRAPHICS_PIPELINE_OPENGL_H
 
+#include "graphics-pipeline.hpp"
+
+#include <vector>
+
 #include <GL/glew.h>
 
-#include "graphics-pipeline.hpp"
+enum VaryingAttribType {
+   ATTRIB_OBJECT_VARYING,
+   ATTRIB_POINT_VARYING,
+};
+
+// TODO: Might be better to create a different struct for uniform attributes
+struct VaryingAttribInfo {
+   VaryingAttribType attribType;
+   GLuint index;
+   GLint size;
+   GLenum type;
+   // UniformType uniType;
+   GLuint buffer; // For uniforms, this is the uniform location
+   size_t fieldOffset;
+   // GLfloat* data; // pointer to data source for uniform attributes
+};
 
 class GraphicsPipeline_OpenGL : public GraphicsPipeline {
    public:
-      GraphicsPipeline_OpenGL();
+      GraphicsPipeline_OpenGL(Viewport viewport);
       ~GraphicsPipeline_OpenGL();
 
+      void addVaryingAttribute(VaryingAttribType attribType, GLint size, GLenum type, size_t fieldOffset);
       void createPipeline(string vertShaderFile, string fragShaderFile);
 
@@ -18,4 +38,6 @@
       unsigned int numPoints;
 
+      vector<VaryingAttribInfo> varyingAttribs;
+
       GLuint loadShaderProgram(string vertShaderFile, string fragShaderFile);
       GLuint loadShader(GLenum type, string file);
Index: opengl-game.cpp
===================================================================
--- opengl-game.cpp	(revision 83b5b4b93a32c66f32c2c36b7246de60b70c32ad)
+++ opengl-game.cpp	(revision 0b1b52d45fd68804c3782b003e6516134b5d1e7f)
@@ -108,14 +108,50 @@
    ((GameGui_GLFW*)gui)->bindEventHandlers();
 
-   graphicsPipelines.push_back(GraphicsPipeline_OpenGL());
+   graphicsPipelines.push_back(GraphicsPipeline_OpenGL(viewport));
+
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::points));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::colors));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::normals));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_OBJECT_VARYING, 1, GL_UNSIGNED_INT,
+      offset_of(&SceneObject::ubo_offset));
+
    graphicsPipelines.back().createPipeline("gl-shaders/ship.vert", "gl-shaders/ship.frag");
 
-   graphicsPipelines.push_back(GraphicsPipeline_OpenGL());
+   graphicsPipelines.push_back(GraphicsPipeline_OpenGL(viewport));
+
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::points));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::colors));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::normals));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_OBJECT_VARYING, 1, GL_UNSIGNED_INT,
+      offset_of(&SceneObject::ubo_offset));
+
    graphicsPipelines.back().createPipeline("gl-shaders/asteroid.vert", "gl-shaders/asteroid.frag");
 
-   graphicsPipelines.push_back(GraphicsPipeline_OpenGL());
+   graphicsPipelines.push_back(GraphicsPipeline_OpenGL(viewport));
+
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&SceneObject::points));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 2, GL_FLOAT,
+      offset_of(&SceneObject::texcoords));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_OBJECT_VARYING, 1, GL_UNSIGNED_INT,
+      offset_of(&SceneObject::ubo_offset));
+
    graphicsPipelines.back().createPipeline("gl-shaders/laser.vert", "gl-shaders/laser.frag");
 
-   graphicsPipelines.push_back(GraphicsPipeline_OpenGL());
+   graphicsPipelines.push_back(GraphicsPipeline_OpenGL(viewport));
+
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 3, GL_FLOAT,
+      offset_of(&ParticleEffect::particleVelocities));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_POINT_VARYING, 1, GL_FLOAT,
+      offset_of(&ParticleEffect::particleTimes));
+   graphicsPipelines.back().addVaryingAttribute(ATTRIB_OBJECT_VARYING, 1, GL_UNSIGNED_INT,
+      offset_of(&ParticleEffect::ubo_offset));
+
    graphicsPipelines.back().createPipeline("gl-shaders/explosion.vert", "gl-shaders/explosion.frag");
 
Index: opengl-game.hpp
===================================================================
--- opengl-game.hpp	(revision 83b5b4b93a32c66f32c2c36b7246de60b70c32ad)
+++ opengl-game.hpp	(revision 0b1b52d45fd68804c3782b003e6516134b5d1e7f)
@@ -9,4 +9,43 @@
 #include "game-gui-glfw.hpp"
 #include "graphics-pipeline_opengl.hpp"
+
+// TODO: Figure out if these structs should be defined in the OpenGLGame class
+
+enum ObjectType {
+   TYPE_SHIP,
+   TYPE_ASTEROID,
+   TYPE_LASER,
+   TYPE_EXPLOSION,
+};
+
+struct SceneObject {
+   unsigned int id;
+   ObjectType type;
+   bool deleted;
+
+   // Currently, model_transform should only have translate, and rotation and scale need to be done in model_base since
+   // they need to be done when the object is at the origin. I should change this to have separate scale, rotate, and translate
+   // matrices for each object that can be updated independently and then applied to the object in that order.
+   // TODO: Actually, to make this as generic as possible, each object should have a matrix stack to support,
+   // for instance, applying a rotate, then a translate, then another rotate. Think about and implement the best approach.
+   glm::mat4 model_mat, model_base, model_transform;
+   glm::mat4 translate_mat; // beginning of doing what's mentioned above
+   unsigned int num_points;
+   GLuint vertex_vbo_offset;
+   GLuint ubo_offset;
+   vector<GLfloat> points;
+   vector<GLfloat> colors;
+   vector<GLfloat> texcoords;
+   vector<GLfloat> normals;
+   glm::vec3 bounding_center;
+   GLfloat bounding_radius;
+};
+
+struct ParticleEffect : SceneObject {
+   vector<GLfloat> particleVelocities;
+   vector<GLfloat> particleTimes;
+   GLfloat startTime;
+   GLfloat duration;
+};
 
 class OpenGLGame {
