Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision e9347b4781a33614fabee5ff0cae384ad1816004)
+++ new-game.cpp	(revision 1f3d32b77dc56955a20fc5b2563d790e385a51c8)
@@ -24,4 +24,5 @@
 #include <iostream>
 #include <fstream>
+#include <sstream>
 #include <cmath>
 #include <string>
@@ -74,4 +75,29 @@
 };
 
+struct Asteroid : SceneObject {
+   double hp;
+};
+
+struct Laser : SceneObject {
+   Asteroid* targetAsteroid;
+};
+
+struct EffectOverTime {
+   double& effectedValue;
+   double startValue;
+   double startTime;
+   double changePerSecond;
+   bool deleted;
+   SceneObject* effectedObject;
+
+   EffectOverTime(double& effectedValue, double changePerSecond, SceneObject* object)
+      : effectedValue(effectedValue), effectedObject(object) {
+      startValue = effectedValue;
+      startTime = glfwGetTime();
+      this->changePerSecond = changePerSecond;
+      deleted = false;
+   }
+};
+
 struct BufferInfo {
    unsigned int vbo_base;
@@ -98,6 +124,6 @@
 void print4DVector(string label, vec4& v);
 
-void initObject(SceneObject& obj);
-void addObjectToScene(SceneObject& obj,
+void initObject(SceneObject* obj);
+void addObjectToScene(SceneObject* obj,
                   map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint points_vbo,
@@ -110,7 +136,5 @@
 void removeObjectFromScene(SceneObject& obj, GLuint ubo);
 
-void calculateObjectBoundingBox(SceneObject& obj);
-
-SceneObject createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp);
+void calculateObjectBoundingBox(SceneObject* obj);
 
 void initializeBuffers(
@@ -123,5 +147,5 @@
                   GLuint* model_mat_idx_vbo);
 
-void populateBuffers(vector<SceneObject>& objects,
+void populateBuffers(vector<SceneObject*>& objects,
                   map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint points_vbo,
@@ -145,6 +169,10 @@
 void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
 
-void translateLaser(SceneObject& laser, const vec3& translation, GLuint ubo);
-void updateLaserTarget(SceneObject& laser, vector<SceneObject>& objects, GLuint points_vbo);
+SceneObject* createShip(GLuint shader);
+Asteroid* createAsteroid(vec3 pos, GLuint shader);
+Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp);
+
+void translateLaser(Laser* laser, const vec3& translation, GLuint ubo);
+void updateLaserTarget(Laser* laser, vector<SceneObject*>& objects, GLuint points_vbo);
 bool getLaserAndAsteroidIntersection(vec3& start, vec3& end, SceneObject& asteroid, vec3& intersection);
 
@@ -159,14 +187,4 @@
 void renderSceneGui();
 
-void spawnAsteroid(vec3 pos, GLuint shader,
-                  map<GLuint, BufferInfo>& shaderBufferInfo,
-                  GLuint points_vbo,
-                  GLuint colors_vbo,
-                  GLuint selected_colors_vbo,
-                  GLuint texcoords_vbo,
-                  GLuint normals_vbo,
-                  GLuint ubo,
-                  GLuint model_mat_idx_vbo);
-
 float getRandomNum(float low, float high);
 
@@ -176,6 +194,4 @@
 const int KEY_STATE_UNCHANGED = -1;
 const bool FULLSCREEN = false;
-const bool SHOW_FPS = false;
-const bool DISABLE_VSYNC = false; // disable vsync to see real framerate
 unsigned int MAX_UNIFORMS = 0; // Requires OpenGL constants only available at runtime, so it can't be const
 
@@ -193,7 +209,7 @@
 mat4 proj_mat;
 
-// TODO: Consider using a list instead since it will make element deletion more efficient
-vector<SceneObject> objects;
+vector<SceneObject*> objects;
 queue<Event> events;
+vector<EffectOverTime*> effects;
 
 SceneObject* clickedObject = NULL;
@@ -208,11 +224,9 @@
 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
 
-// TODO: Come up with a better way to keep references to specific objects,
-// which remain valid (or are recreated) when the object vector or VBOs are resized.
-// I could store SceneObject*, but I have to keep track of when the vector is about to
-// resize and re-init the pointers when that happens since they'll be invalidated
-// I would prefer the above apporach, but I should write some helper functions to make it less error-prone
-int leftLaserIdx = -1;
-int rightLaserIdx = -1;
+Laser* leftLaser = NULL;
+EffectOverTime* leftLaserEffect = NULL;
+
+Laser* rightLaser = NULL;
+EffectOverTime* rightLaserEffect = NULL;
 
 /*
@@ -404,388 +418,7 @@
    float cam_pitch = -50.0f * 2.0f * 3.14159f / 360.0f;
 
-   SceneObject obj;
-   mat4 T_model, R_model;
-
    // player ship
-   obj = SceneObject();
-   obj.type = TYPE_SHIP;
-   obj.shader_program = color_sp;
-   obj.points = {
-      //back
-      -0.5f,    0.3f,    0.0f,
-      -0.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-      -0.5f,    0.3f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-       0.5f,    0.3f,    0.0f,
-
-      // left back
-      -0.5f,    0.3f,   -2.0f,
-      -0.5f,    0.0f,   -2.0f,
-      -0.5f,    0.0f,    0.0f,
-      -0.5f,    0.3f,   -2.0f,
-      -0.5f,    0.0f,    0.0f,
-      -0.5f,    0.3f,    0.0f,
-
-      // right back
-       0.5f,    0.3f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,   -2.0f,
-       0.5f,    0.3f,    0.0f,
-       0.5f,    0.0f,   -2.0f,
-       0.5f,    0.3f,   -2.0f,
-
-      // left mid
-      -0.25f,   0.3f,   -3.0f,
-      -0.25f,   0.0f,   -3.0f,
-      -0.5f,    0.0f,   -2.0f,
-      -0.25f,   0.3f,   -3.0f,
-      -0.5f,    0.0f,   -2.0f,
-      -0.5f,    0.3f,   -2.0f,
-
-      // right mid
-       0.5f,    0.3f,   -2.0f,
-       0.5f,    0.0f,   -2.0f,
-       0.25f,   0.0f,   -3.0f,
-       0.5f,    0.3f,   -2.0f,
-       0.25f,   0.0f,   -3.0f,
-       0.25f,   0.3f,   -3.0f,
-
-      // left front
-       0.0f,    0.0f,   -3.5f,
-      -0.25f,   0.0f,   -3.0f,
-      -0.25f,   0.3f,   -3.0f,
-
-      // right front
-       0.25f,   0.3f,   -3.0f,
-       0.25f,   0.0f,   -3.0f,
-       0.0f,    0.0f,   -3.5f,
-
-      // top back
-      -0.5f,    0.3f,   -2.0f,
-      -0.5f,    0.3f,    0.0f,
-       0.5f,    0.3f,    0.0f,
-      -0.5f,    0.3f,   -2.0f,
-       0.5f,    0.3f,    0.0f,
-       0.5f,    0.3f,   -2.0f,
-
-      // bottom back
-      -0.5f,    0.0f,    0.0f,
-      -0.5f,    0.0f,   -2.0f,
-       0.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-      -0.5f,    0.0f,   -2.0f,
-       0.5f,    0.0f,   -2.0f,
-
-      // top mid
-      -0.25f,   0.3f,   -3.0f,
-      -0.5f,    0.3f,   -2.0f,
-       0.5f,    0.3f,   -2.0f,
-      -0.25f,   0.3f,   -3.0f,
-       0.5f,    0.3f,   -2.0f,
-       0.25f,   0.3f,   -3.0f,
-
-      // bottom mid
-      -0.5f,    0.0f,   -2.0f,
-      -0.25f,   0.0f,   -3.0f,
-       0.5f,    0.0f,   -2.0f,
-       0.5f,    0.0f,   -2.0f,
-      -0.25f,   0.0f,   -3.0f,
-       0.25f,   0.0f,   -3.0f,
-
-      // top front
-      -0.25f,   0.3f,   -3.0f,
-       0.25f,   0.3f,   -3.0f,
-       0.0f,    0.0f,   -3.5f,
-
-      // bottom front
-       0.25f,   0.0f,   -3.0f,
-      -0.25f,   0.0f,   -3.0f,
-       0.0f,    0.0f,   -3.5f,
-
-      // left wing start back
-      -1.5f,    0.3f,    0.0f,
-      -1.5f,    0.0f,    0.0f,
-      -0.5f,    0.0f,    0.0f,
-      -1.5f,    0.3f,    0.0f,
-      -0.5f,    0.0f,    0.0f,
-      -0.5f,    0.3f,    0.0f,
-
-      // left wing start top
-      -0.5f,    0.3f,   -0.3f,
-      -1.3f,    0.3f,   -0.3f,
-      -1.5f,    0.3f,    0.0f,
-      -0.5f,    0.3f,   -0.3f,
-      -1.5f,    0.3f,    0.0f,
-      -0.5f,    0.3f,    0.0f,
-
-      // left wing start front
-      -0.5f,    0.3f,   -0.3f,
-      -0.5f,    0.0f,   -0.3f,
-      -1.3f,    0.0f,   -0.3f,
-      -0.5f,    0.3f,   -0.3f,
-      -1.3f,    0.0f,   -0.3f,
-      -1.3f,    0.3f,   -0.3f,
-
-      // left wing start bottom
-      -0.5f,    0.0f,    0.0f,
-      -1.5f,    0.0f,    0.0f,
-      -1.3f,    0.0f,   -0.3f,
-      -0.5f,    0.0f,    0.0f,
-      -1.3f,    0.0f,   -0.3f,
-      -0.5f,    0.0f,   -0.3f,
-
-      // left wing end outside
-      -1.5f,    0.3f,    0.0f,
-      -2.2f,    0.15f,  -0.8f,
-      -1.5f,    0.0f,    0.0f,
-
-      // left wing end top
-      -1.3f,    0.3f,   -0.3f,
-      -2.2f,    0.15f,  -0.8f,
-      -1.5f,    0.3f,    0.0f,
-
-      // left wing end front
-      -1.3f,    0.0f,   -0.3f,
-      -2.2f,    0.15f,  -0.8f,
-      -1.3f,    0.3f,   -0.3f,
-
-      // left wing end bottom
-      -1.5f,    0.0f,    0.0f,
-      -2.2f,    0.15f,  -0.8f,
-      -1.3f,    0.0f,   -0.3f,
-
-      // right wing start back
-       1.5f,    0.0f,    0.0f,
-       1.5f,    0.3f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-       1.5f,    0.3f,    0.0f,
-       0.5f,    0.3f,    0.0f,
-
-      // right wing start top
-       1.3f,    0.3f,   -0.3f,
-       0.5f,    0.3f,   -0.3f,
-       1.5f,    0.3f,    0.0f,
-       1.5f,    0.3f,    0.0f,
-       0.5f,    0.3f,   -0.3f,
-       0.5f,    0.3f,    0.0f,
-
-      // right wing start front
-       0.5f,    0.0f,   -0.3f,
-       0.5f,    0.3f,   -0.3f,
-       1.3f,    0.0f,   -0.3f,
-       1.3f,    0.0f,   -0.3f,
-       0.5f,    0.3f,   -0.3f,
-       1.3f,    0.3f,   -0.3f,
-
-      // right wing start bottom
-       1.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,    0.0f,
-       1.3f,    0.0f,   -0.3f,
-       1.3f,    0.0f,   -0.3f,
-       0.5f,    0.0f,    0.0f,
-       0.5f,    0.0f,   -0.3f,
-
-      // right wing end outside
-       2.2f,    0.15f,  -0.8f,
-       1.5f,    0.3f,    0.0f,
-       1.5f,    0.0f,    0.0f,
-
-      // right wing end top
-       2.2f,    0.15f,  -0.8f,
-       1.3f,    0.3f,   -0.3f,
-       1.5f,    0.3f,    0.0f,
-
-      // right wing end front
-       2.2f,    0.15f,  -0.8f,
-       1.3f,    0.0f,   -0.3f,
-       1.3f,    0.3f,   -0.3f,
-
-      // right wing end bottom
-       2.2f,    0.15f,  -0.8f,
-       1.5f,    0.0f,    0.0f,
-       1.3f,    0.0f,   -0.3f,
-   };
-   obj.colors = {
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-      0.0f, 0.0f, 1.0f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-      0.0f, 0.0f, 0.3f,
-   };
-   obj.texcoords = { 0.0f };
-   obj.selected_colors = { 0.0f };
-
-   T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
-   //R_model = rotate(mat4(1.0f), 20.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 0.0f, 0.0f));
-   R_model = mat4(1.0f);
-   obj.model_base = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
-
-   obj.translate_mat = T_model;
-
-   initObject(obj);
-   objects.push_back(obj);
+   SceneObject* ship = createShip(color_sp);
+   objects.push_back(ship);
 
    vector<SceneObject>::iterator obj_it;
@@ -953,7 +586,6 @@
    //glPolygonMode(GL_FRONT, GL_LINE);
 
-   if (DISABLE_VSYNC && SHOW_FPS) {
-      glfwSwapInterval(0);
-   }
+   // disable vsync to see real framerate
+   //glfwSwapInterval(0);
 
    State curState = STATE_MAIN_MENU;
@@ -964,16 +596,13 @@
       previous_seconds = current_seconds;
 
-      if (SHOW_FPS) {
-         elapsed_seconds_fps += elapsed_seconds;
-         if (elapsed_seconds_fps > 0.25f) {
-            fps = (double)frame_count / elapsed_seconds_fps;
-            cout << "FPS: " << fps << endl;
-
-            frame_count = 0;
-            elapsed_seconds_fps = 0.0f;
-         }
-
-         frame_count++;
-      }
+      elapsed_seconds_fps += elapsed_seconds;
+      if (elapsed_seconds_fps > 0.25f) {
+         fps = (double)frame_count / elapsed_seconds_fps;
+
+         frame_count = 0;
+         elapsed_seconds_fps = 0.0f;
+      }
+
+      frame_count++;
 
       // Handle events
@@ -1008,7 +637,6 @@
          elapsed_seconds_spawn += elapsed_seconds;
          if (elapsed_seconds_spawn > 0.5f) {
-            //spawnAsteroid(vec3(getRandomNum(-1.3f, 1.3f), getRandomNum(-3.0f, -1.0f), getRandomNum(-5.5f, -4.5f)), color_sp,
-            spawnAsteroid(vec3(getRandomNum(-1.3f, 1.3f), -1.2f, getRandomNum(-5.5f, -4.5f)), color_sp,
-               shaderBufferInfo,
+            SceneObject* obj = createAsteroid(vec3(getRandomNum(-1.3f, 1.3f), -1.2f, getRandomNum(-5.5f, -4.5f)), color_sp);
+            addObjectToScene(obj, shaderBufferInfo,
                points_vbo,
                colors_vbo,
@@ -1044,31 +672,30 @@
 
          if (key_down[GLFW_KEY_RIGHT]) {
-            transformObject(objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
-
-            if (leftLaserIdx != -1 && !objects[leftLaserIdx].deleted) {
-               translateLaser(objects[leftLaserIdx], vec3(0.01f, 0.0f, 0.0f), ubo);
+            transformObject(*objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
+
+            if (leftLaser != NULL && !leftLaser->deleted) {
+               translateLaser(leftLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
             }
-            if (rightLaserIdx != -1 && !objects[rightLaserIdx].deleted) {
-               translateLaser(objects[rightLaserIdx], vec3(0.01f, 0.0f, 0.0f), ubo);
+            if (rightLaser != NULL && !rightLaser->deleted) {
+               translateLaser(rightLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
             }
          }
          if (key_down[GLFW_KEY_LEFT]) {
-            transformObject(objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
-
-            if (leftLaserIdx != -1 && !objects[leftLaserIdx].deleted) {
-               translateLaser(objects[leftLaserIdx], vec3(-0.01f, 0.0f, 0.0f), ubo);
+            transformObject(*objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
+
+            if (leftLaser != NULL && !leftLaser->deleted) {
+               translateLaser(leftLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
             }
-            if (rightLaserIdx != -1 && !objects[rightLaserIdx].deleted) {
-               translateLaser(objects[rightLaserIdx], vec3(-0.01f, 0.0f, 0.0f), ubo);
+            if (rightLaser != NULL && !rightLaser->deleted) {
+               translateLaser(rightLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
             }
          }
 
          if (key_state[GLFW_KEY_Z] == GLFW_PRESS) {
-            vec3 offset(objects[0].model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
-            leftLaserIdx = objects.size();
-
-            SceneObject obj = createLaser(vec3(-0.21f, -1.19f, 1.76f)+offset, vec3(-0.21f, -1.19f, -3.0f)+offset,
+            vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
+
+            leftLaser = createLaser(vec3(-0.21f, -1.19f, 1.76f)+offset, vec3(-0.21f, -1.19f, -3.0f)+offset,
                vec3(0.0f, 1.0f, 0.0f), 0.03f, laser_sp);
-            addObjectToScene(obj, shaderBufferInfo,
+            addObjectToScene(leftLaser, shaderBufferInfo,
                points_vbo,
                colors_vbo,
@@ -1079,14 +706,13 @@
                model_mat_idx_vbo);
          } else if (key_state[GLFW_KEY_Z] == GLFW_RELEASE) {
-            removeObjectFromScene(objects[leftLaserIdx], ubo);
+            removeObjectFromScene(*leftLaser, ubo);
          }
 
          if (key_state[GLFW_KEY_X] == GLFW_PRESS) {
-            vec3 offset(objects[0].model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
-            rightLaserIdx = objects.size();
-
-            SceneObject obj = createLaser(vec3(0.21f, -1.19f, 1.76f) + offset, vec3(0.21f, -1.19f, -3.0f) + offset,
+            vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
+
+            rightLaser = createLaser(vec3(0.21f, -1.19f, 1.76f) + offset, vec3(0.21f, -1.19f, -3.0f) + offset,
                vec3(0.0f, 1.0f, 0.0f), 0.03f, laser_sp);
-            addObjectToScene(obj, shaderBufferInfo,
+            addObjectToScene(rightLaser, shaderBufferInfo,
                points_vbo,
                colors_vbo,
@@ -1097,25 +723,37 @@
                model_mat_idx_vbo);
          } else if (key_state[GLFW_KEY_X] == GLFW_RELEASE) {
-            removeObjectFromScene(objects[rightLaserIdx], ubo);
+            removeObjectFromScene(*rightLaser, ubo);
          }
 
          // this code moves the asteroids
          for (int i = 0; i < objects.size(); i++) {
-            if (objects[i].type == TYPE_ASTEROID && !objects[i].deleted) {
-               transformObject(objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
-
-               vec3 obj_center = vec3(view_mat * vec4(objects[i].bounding_center, 1.0f));
-
-               if ((obj_center.z - objects[i].bounding_radius) > -NEAR_CLIP) {
-                  removeObjectFromScene(objects[i], ubo);
+            if (objects[i]->type == TYPE_ASTEROID && !objects[i]->deleted) {
+               transformObject(*objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
+
+               vec3 obj_center = vec3(view_mat * vec4(objects[i]->bounding_center, 1.0f));
+
+               if ((obj_center.z - objects[i]->bounding_radius) > -NEAR_CLIP) {
+                  removeObjectFromScene(*objects[i], ubo);
                }
             }
          }
 
-         if (leftLaserIdx != -1 && !objects[leftLaserIdx].deleted) {
-            updateLaserTarget(objects[leftLaserIdx], objects, points_vbo);
+         if (leftLaser != NULL && !leftLaser->deleted) {
+            updateLaserTarget(leftLaser, objects, points_vbo);
          }
-         if (rightLaserIdx != -1 && !objects[rightLaserIdx].deleted) {
-            updateLaserTarget(objects[rightLaserIdx], objects, points_vbo);
+         if (rightLaser != NULL && !rightLaser->deleted) {
+            updateLaserTarget(rightLaser, objects, points_vbo);
+         }
+      }
+
+      for (vector<EffectOverTime*>::iterator it = effects.begin(); it != effects.end(); ) {
+         if ((*it)->deleted || (*it)->effectedObject->deleted) {
+            delete *it;
+            it = effects.erase(it);
+         } else {
+            EffectOverTime* eot = *it;
+            eot->effectedValue = eot->startValue + (current_seconds - eot->startTime) * eot->changePerSecond;
+
+            it++;
          }
       }
@@ -1168,5 +806,5 @@
       }
       */
-      if (cam_moved) {
+      if (cam_moved && false) { // disable camera movement
          T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
 
@@ -1219,4 +857,10 @@
    glfwTerminate();
 
+   // free memory
+
+   for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
+      delete *it;
+   }
+
    return 0;
 }
@@ -1248,14 +892,14 @@
       SceneObject* closest_object = NULL;
 
-      for (vector<SceneObject>::iterator it = objects.begin(); it != objects.end(); it++) {
-         if (it->type == TYPE_LASER) continue;
-         for (unsigned int p_idx = 0; p_idx < it->points.size(); p_idx += 9) {
+      for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
+         if ((*it)->type == TYPE_LASER) continue;
+         for (unsigned int p_idx = 0; p_idx < (*it)->points.size(); p_idx += 9) {
             if (faceClicked(
                {
-                  vec3(it->points[p_idx], it->points[p_idx + 1], it->points[p_idx + 2]),
-                  vec3(it->points[p_idx + 3], it->points[p_idx + 4], it->points[p_idx + 5]),
-                  vec3(it->points[p_idx + 6], it->points[p_idx + 7], it->points[p_idx + 8]),
+                  vec3((*it)->points[p_idx], (*it)->points[p_idx + 1], (*it)->points[p_idx + 2]),
+                  vec3((*it)->points[p_idx + 3], (*it)->points[p_idx + 4], (*it)->points[p_idx + 5]),
+                  vec3((*it)->points[p_idx + 6], (*it)->points[p_idx + 7], (*it)->points[p_idx + 8]),
                },
-               &*it, ray_world, vec4(cam_pos, 1.0f), click_point
+               *it, ray_world, vec4(cam_pos, 1.0f), click_point
             )) {
                click_point = view_mat * click_point;
@@ -1263,5 +907,5 @@
                if (-NEAR_CLIP >= click_point.z && click_point.z > -FAR_CLIP && click_point.z > closest_point.z) {
                   closest_point = vec3(click_point);
-                  closest_object = &*it;
+                  closest_object = *it;
                }
             }
@@ -1414,21 +1058,22 @@
 }
 
-void initObject(SceneObject& obj) {
+void initObject(SceneObject* obj) {
    // Each objects must have at least 3 points, so the size of
    // the points array must be a positive multiple of 9
-   if (obj.points.size() == 0 || (obj.points.size() % 9) != 0) {
+   if (obj->points.size() == 0 || (obj->points.size() % 9) != 0) {
+      // TODO: Maybe throw some kind of error here instead
       return;
    }
 
-   obj.id = objects.size(); // currently unused
-   obj.num_points = obj.points.size() / 3;
-   obj.model_transform = mat4(1.0f);
-   obj.deleted = false;
-
-   obj.normals.reserve(obj.points.size());
-   for (int i = 0; i < obj.points.size(); i += 9) {
-      vec3 point1 = vec3(obj.points[i], obj.points[i + 1], obj.points[i + 2]);
-      vec3 point2 = vec3(obj.points[i + 3], obj.points[i + 4], obj.points[i + 5]);
-      vec3 point3 = vec3(obj.points[i + 6], obj.points[i + 7], obj.points[i + 8]);
+   obj->id = objects.size(); // currently unused
+   obj->num_points = obj->points.size() / 3;
+   obj->model_transform = mat4(1.0f);
+   obj->deleted = false;
+
+   obj->normals.reserve(obj->points.size());
+   for (int i = 0; i < obj->points.size(); i += 9) {
+      vec3 point1 = vec3(obj->points[i], obj->points[i + 1], obj->points[i + 2]);
+      vec3 point2 = vec3(obj->points[i + 3], obj->points[i + 4], obj->points[i + 5]);
+      vec3 point3 = vec3(obj->points[i + 6], obj->points[i + 7], obj->points[i + 8]);
 
       vec3 normal = normalize(cross(point2 - point1, point3 - point1));
@@ -1436,18 +1081,18 @@
       // Add the same normal for all 3 points
       for (int j = 0; j < 3; j++) {
-         obj.normals.push_back(normal.x);
-         obj.normals.push_back(normal.y);
-         obj.normals.push_back(normal.z);
-      }
-   }
-
-   if (obj.type != TYPE_LASER) {
+         obj->normals.push_back(normal.x);
+         obj->normals.push_back(normal.y);
+         obj->normals.push_back(normal.z);
+      }
+   }
+
+   if (obj->type != TYPE_LASER) {
       calculateObjectBoundingBox(obj);
 
-      obj.bounding_center = vec3(obj.translate_mat * vec4(obj.bounding_center, 1.0f));
-   }
-}
-
-void addObjectToScene(SceneObject& obj,
+      obj->bounding_center = vec3(obj->translate_mat * vec4(obj->bounding_center, 1.0f));
+   }
+}
+
+void addObjectToScene(SceneObject* obj,
    map<GLuint, BufferInfo>& shaderBufferInfo,
    GLuint points_vbo,
@@ -1460,16 +1105,16 @@
    objects.push_back(obj);
 
-   BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
+   BufferInfo* bufferInfo = &shaderBufferInfo[obj->shader_program];
 
    // Check if the buffers aren't large enough to fit the new object and, if so, call
    // populateBuffers() to resize and repopupulate them
-   if (bufferInfo->vbo_capacity < (bufferInfo->ubo_offset + obj.num_points) ||
+   if (bufferInfo->vbo_capacity < (bufferInfo->ubo_offset + obj->num_points) ||
       bufferInfo->ubo_capacity < (bufferInfo->ubo_offset + 1)) {
 
-      if (leftLaserIdx != -1 && objects[leftLaserIdx].deleted) {
-         leftLaserIdx = -1;
-      }
-      if (rightLaserIdx != -1 && objects[rightLaserIdx].deleted) {
-         rightLaserIdx = -1;
+      if (leftLaser != NULL && leftLaser->deleted) {
+         leftLaser = NULL;
+      }
+      if (rightLaser != NULL && rightLaser->deleted) {
+         rightLaser = NULL;
       }
 
@@ -1483,5 +1128,5 @@
          model_mat_idx_vbo);
    } else {
-      copyObjectDataToBuffers(objects.back(), shaderBufferInfo,
+      copyObjectDataToBuffers(*objects.back(), shaderBufferInfo,
          points_vbo,
          colors_vbo,
@@ -1503,57 +1148,442 @@
 }
 
-void calculateObjectBoundingBox(SceneObject& obj) {
-   GLfloat min_x = obj.points[0];
-   GLfloat max_x = obj.points[0];
-   GLfloat min_y = obj.points[1];
-   GLfloat max_y = obj.points[1];
-   GLfloat min_z = obj.points[2];
-   GLfloat max_z = obj.points[2];
+void calculateObjectBoundingBox(SceneObject* obj) {
+   GLfloat min_x = obj->points[0];
+   GLfloat max_x = obj->points[0];
+   GLfloat min_y = obj->points[1];
+   GLfloat max_y = obj->points[1];
+   GLfloat min_z = obj->points[2];
+   GLfloat max_z = obj->points[2];
 
    // start from the second point
-   for (int i = 3; i < obj.points.size(); i += 3) {
-      if (min_x > obj.points[i]) {
-         min_x = obj.points[i];
-      }
-      else if (max_x < obj.points[i]) {
-         max_x = obj.points[i];
-      }
-
-      if (min_y > obj.points[i + 1]) {
-         min_y = obj.points[i + 1];
-      }
-      else if (max_y < obj.points[i + 1]) {
-         max_y = obj.points[i + 1];
-      }
-
-      if (min_z > obj.points[i + 2]) {
-         min_z = obj.points[i + 2];
-      }
-      else if (max_z < obj.points[i + 2]) {
-         max_z = obj.points[i + 2];
-      }
-   }
-
-   obj.bounding_center = vec3((min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f, (min_z + max_z) / 2.0f);
-
-   GLfloat radius_x = max_x - obj.bounding_center.x;
-   GLfloat radius_y = max_y - obj.bounding_center.y;
-   GLfloat radius_z = max_z - obj.bounding_center.z;
+   for (int i = 3; i < obj->points.size(); i += 3) {
+      if (min_x > obj->points[i]) {
+         min_x = obj->points[i];
+      }
+      else if (max_x < obj->points[i]) {
+         max_x = obj->points[i];
+      }
+
+      if (min_y > obj->points[i + 1]) {
+         min_y = obj->points[i + 1];
+      }
+      else if (max_y < obj->points[i + 1]) {
+         max_y = obj->points[i + 1];
+      }
+
+      if (min_z > obj->points[i + 2]) {
+         min_z = obj->points[i + 2];
+      }
+      else if (max_z < obj->points[i + 2]) {
+         max_z = obj->points[i + 2];
+      }
+   }
+
+   obj->bounding_center = vec3((min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f, (min_z + max_z) / 2.0f);
+
+   GLfloat radius_x = max_x - obj->bounding_center.x;
+   GLfloat radius_y = max_y - obj->bounding_center.y;
+   GLfloat radius_z = max_z - obj->bounding_center.z;
 
    // TODO: This actually underestimates the radius. Might need to be fixed at some point.
    // TODO: Does not take into account any scaling in the model matrix
-   obj.bounding_radius = radius_x;
-   if (obj.bounding_radius < radius_y)
-      obj.bounding_radius = radius_y;
-   if (obj.bounding_radius < radius_z)
-      obj.bounding_radius = radius_z;
-
-   for (int i = 0; i < obj.points.size(); i += 3) {
-      obj.points[i] -= obj.bounding_center.x;
-      obj.points[i + 1] -= obj.bounding_center.y;
-      obj.points[i + 2] -= obj.bounding_center.z;
-   }
-
-   obj.bounding_center = vec3(0.0f, 0.0f, 0.0f);
+   obj->bounding_radius = radius_x;
+   if (obj->bounding_radius < radius_y)
+      obj->bounding_radius = radius_y;
+   if (obj->bounding_radius < radius_z)
+      obj->bounding_radius = radius_z;
+
+   for (int i = 0; i < obj->points.size(); i += 3) {
+      obj->points[i] -= obj->bounding_center.x;
+      obj->points[i + 1] -= obj->bounding_center.y;
+      obj->points[i + 2] -= obj->bounding_center.z;
+   }
+
+   obj->bounding_center = vec3(0.0f, 0.0f, 0.0f);
+}
+
+SceneObject* createShip(GLuint shader) {
+   SceneObject* ship = new SceneObject();
+
+   ship->type = TYPE_SHIP;
+   ship->shader_program = shader;
+
+   ship->points = {
+      //back
+      -0.5f,    0.3f,    0.0f,
+      -0.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      -0.5f,    0.3f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      0.5f,    0.3f,    0.0f,
+
+      // left back
+      -0.5f,    0.3f,   -2.0f,
+      -0.5f,    0.0f,   -2.0f,
+      -0.5f,    0.0f,    0.0f,
+      -0.5f,    0.3f,   -2.0f,
+      -0.5f,    0.0f,    0.0f,
+      -0.5f,    0.3f,    0.0f,
+
+      // right back
+      0.5f,    0.3f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,   -2.0f,
+      0.5f,    0.3f,    0.0f,
+      0.5f,    0.0f,   -2.0f,
+      0.5f,    0.3f,   -2.0f,
+
+      // left mid
+      -0.25f,   0.3f,   -3.0f,
+      -0.25f,   0.0f,   -3.0f,
+      -0.5f,    0.0f,   -2.0f,
+      -0.25f,   0.3f,   -3.0f,
+      -0.5f,    0.0f,   -2.0f,
+      -0.5f,    0.3f,   -2.0f,
+
+      // right mid
+      0.5f,    0.3f,   -2.0f,
+      0.5f,    0.0f,   -2.0f,
+      0.25f,   0.0f,   -3.0f,
+      0.5f,    0.3f,   -2.0f,
+      0.25f,   0.0f,   -3.0f,
+      0.25f,   0.3f,   -3.0f,
+
+      // left front
+      0.0f,    0.0f,   -3.5f,
+      -0.25f,   0.0f,   -3.0f,
+      -0.25f,   0.3f,   -3.0f,
+
+      // right front
+      0.25f,   0.3f,   -3.0f,
+      0.25f,   0.0f,   -3.0f,
+      0.0f,    0.0f,   -3.5f,
+
+      // top back
+      -0.5f,    0.3f,   -2.0f,
+      -0.5f,    0.3f,    0.0f,
+      0.5f,    0.3f,    0.0f,
+      -0.5f,    0.3f,   -2.0f,
+      0.5f,    0.3f,    0.0f,
+      0.5f,    0.3f,   -2.0f,
+
+      // bottom back
+      -0.5f,    0.0f,    0.0f,
+      -0.5f,    0.0f,   -2.0f,
+      0.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      -0.5f,    0.0f,   -2.0f,
+      0.5f,    0.0f,   -2.0f,
+
+      // top mid
+      -0.25f,   0.3f,   -3.0f,
+      -0.5f,    0.3f,   -2.0f,
+      0.5f,    0.3f,   -2.0f,
+      -0.25f,   0.3f,   -3.0f,
+      0.5f,    0.3f,   -2.0f,
+      0.25f,   0.3f,   -3.0f,
+
+      // bottom mid
+      -0.5f,    0.0f,   -2.0f,
+      -0.25f,   0.0f,   -3.0f,
+      0.5f,    0.0f,   -2.0f,
+      0.5f,    0.0f,   -2.0f,
+      -0.25f,   0.0f,   -3.0f,
+      0.25f,   0.0f,   -3.0f,
+
+      // top front
+      -0.25f,   0.3f,   -3.0f,
+      0.25f,   0.3f,   -3.0f,
+      0.0f,    0.0f,   -3.5f,
+
+      // bottom front
+      0.25f,   0.0f,   -3.0f,
+      -0.25f,   0.0f,   -3.0f,
+      0.0f,    0.0f,   -3.5f,
+
+      // left wing start back
+      -1.5f,    0.3f,    0.0f,
+      -1.5f,    0.0f,    0.0f,
+      -0.5f,    0.0f,    0.0f,
+      -1.5f,    0.3f,    0.0f,
+      -0.5f,    0.0f,    0.0f,
+      -0.5f,    0.3f,    0.0f,
+
+      // left wing start top
+      -0.5f,    0.3f,   -0.3f,
+      -1.3f,    0.3f,   -0.3f,
+      -1.5f,    0.3f,    0.0f,
+      -0.5f,    0.3f,   -0.3f,
+      -1.5f,    0.3f,    0.0f,
+      -0.5f,    0.3f,    0.0f,
+
+      // left wing start front
+      -0.5f,    0.3f,   -0.3f,
+      -0.5f,    0.0f,   -0.3f,
+      -1.3f,    0.0f,   -0.3f,
+      -0.5f,    0.3f,   -0.3f,
+      -1.3f,    0.0f,   -0.3f,
+      -1.3f,    0.3f,   -0.3f,
+
+      // left wing start bottom
+      -0.5f,    0.0f,    0.0f,
+      -1.5f,    0.0f,    0.0f,
+      -1.3f,    0.0f,   -0.3f,
+      -0.5f,    0.0f,    0.0f,
+      -1.3f,    0.0f,   -0.3f,
+      -0.5f,    0.0f,   -0.3f,
+
+      // left wing end outside
+      -1.5f,    0.3f,    0.0f,
+      -2.2f,    0.15f,  -0.8f,
+      -1.5f,    0.0f,    0.0f,
+
+      // left wing end top
+      -1.3f,    0.3f,   -0.3f,
+      -2.2f,    0.15f,  -0.8f,
+      -1.5f,    0.3f,    0.0f,
+
+      // left wing end front
+      -1.3f,    0.0f,   -0.3f,
+      -2.2f,    0.15f,  -0.8f,
+      -1.3f,    0.3f,   -0.3f,
+
+      // left wing end bottom
+      -1.5f,    0.0f,    0.0f,
+      -2.2f,    0.15f,  -0.8f,
+      -1.3f,    0.0f,   -0.3f,
+
+      // right wing start back
+      1.5f,    0.0f,    0.0f,
+      1.5f,    0.3f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      1.5f,    0.3f,    0.0f,
+      0.5f,    0.3f,    0.0f,
+
+      // right wing start top
+      1.3f,    0.3f,   -0.3f,
+      0.5f,    0.3f,   -0.3f,
+      1.5f,    0.3f,    0.0f,
+      1.5f,    0.3f,    0.0f,
+      0.5f,    0.3f,   -0.3f,
+      0.5f,    0.3f,    0.0f,
+
+      // right wing start front
+      0.5f,    0.0f,   -0.3f,
+      0.5f,    0.3f,   -0.3f,
+      1.3f,    0.0f,   -0.3f,
+      1.3f,    0.0f,   -0.3f,
+      0.5f,    0.3f,   -0.3f,
+      1.3f,    0.3f,   -0.3f,
+
+      // right wing start bottom
+      1.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,    0.0f,
+      1.3f,    0.0f,   -0.3f,
+      1.3f,    0.0f,   -0.3f,
+      0.5f,    0.0f,    0.0f,
+      0.5f,    0.0f,   -0.3f,
+
+      // right wing end outside
+      2.2f,    0.15f,  -0.8f,
+      1.5f,    0.3f,    0.0f,
+      1.5f,    0.0f,    0.0f,
+
+      // right wing end top
+      2.2f,    0.15f,  -0.8f,
+      1.3f,    0.3f,   -0.3f,
+      1.5f,    0.3f,    0.0f,
+
+      // right wing end front
+      2.2f,    0.15f,  -0.8f,
+      1.3f,    0.0f,   -0.3f,
+      1.3f,    0.3f,   -0.3f,
+
+      // right wing end bottom
+      2.2f,    0.15f,  -0.8f,
+      1.5f,    0.0f,    0.0f,
+      1.3f,    0.0f,   -0.3f,
+   };
+   ship->colors = {
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+      0.0f, 0.0f, 1.0f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+      0.0f, 0.0f, 0.3f,
+   };
+   ship->texcoords = { 0.0f };
+   ship->selected_colors = { 0.0f };
+
+   mat4 T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
+   mat4 R_model(1.0f);
+   ship->model_base = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
+
+   ship->translate_mat = T_model;
+
+   initObject(ship);
+
+   return ship;
 }
 
@@ -1572,13 +1602,14 @@
 // TODO: Make the color parameter have an effect
 // TODO: Come up with a better way of passing the object back than copying it
-SceneObject createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp) {
-   SceneObject obj = SceneObject();
-   obj.type = TYPE_LASER;
-   obj.shader_program = laser_sp;
+Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp) {
+   Laser* obj = new Laser();
+   obj->type = TYPE_LASER;
+   obj->targetAsteroid = NULL;
+   obj->shader_program = laser_sp;
 
    vec3 ray = end - start;
    float length = glm::length(ray);
 
-   obj.points = {
+   obj->points = {
        width / 2, 0.0f, -width / 2,
       -width / 2, 0.0f, -width / 2,
@@ -1601,5 +1632,5 @@
    };
 
-   obj.texcoords = {
+   obj->texcoords = {
       1.0f, 0.5f,
       0.0f, 0.5f,
@@ -1636,11 +1667,11 @@
    float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
 
-   obj.model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
+   obj->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
 
    initObject(obj);
 
-   obj.model_transform = rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) * obj.model_transform;
-   obj.model_transform = rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) * obj.model_transform;
-   obj.model_transform = translate(mat4(1.0f), start) * obj.model_transform;
+   obj->model_transform = rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) * obj->model_transform;
+   obj->model_transform = rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) * obj->model_transform;
+   obj->model_transform = translate(mat4(1.0f), start) * obj->model_transform;
 
    return obj;
@@ -1677,5 +1708,5 @@
 }
 
-void populateBuffers(vector<SceneObject>& objects,
+void populateBuffers(vector<SceneObject*>& objects,
                   map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint points_vbo,
@@ -1694,5 +1725,5 @@
    map<GLuint, unsigned int> shaderUboCounts;
 
-   vector<SceneObject>::iterator it;
+   vector<SceneObject*>::iterator it;
 
    /* Find all shaders that need to be used and the number of objects and
@@ -1702,29 +1733,20 @@
    * vertex buffer for each shader.
    */
-   for (it = objects.begin(); it != objects.end();) {
-      if (it->deleted) {
-         // terrible way of keeping track of the laser scene objects
-         // TODO: Find a more robust way of doing this, one that would work well
-         // for any objects in the scene
-         if (leftLaserIdx > it - objects.begin()) {
-            leftLaserIdx--;
-         }
-         if (rightLaserIdx > it - objects.begin()) {
-            rightLaserIdx--;
-         }
-
+   for (it = objects.begin(); it != objects.end(); ) {
+      if ((*it)->deleted) {
+         delete *it;
          it = objects.erase(it);
       } else {
-         points_buffer_size += it->num_points * sizeof(GLfloat) * 3;
-         textures_buffer_size += it->num_points * sizeof(GLfloat) * 2;
+         points_buffer_size += (*it)->num_points * sizeof(GLfloat) * 3;
+         textures_buffer_size += (*it)->num_points * sizeof(GLfloat) * 2;
          ubo_buffer_size += 16 * sizeof(GLfloat);
-         model_mat_idx_buffer_size += it->num_points * sizeof(GLuint);
-
-         if (shaderCounts.count(it->shader_program) == 0) {
-            shaderCounts[it->shader_program] = it->num_points;
-            shaderUboCounts[it->shader_program] = 1;
+         model_mat_idx_buffer_size += (*it)->num_points * sizeof(GLuint);
+
+         if (shaderCounts.count((*it)->shader_program) == 0) {
+            shaderCounts[(*it)->shader_program] = (*it)->num_points;
+            shaderUboCounts[(*it)->shader_program] = 1;
          } else {
-            shaderCounts[it->shader_program] += it->num_points;
-            shaderUboCounts[it->shader_program]++;
+            shaderCounts[(*it)->shader_program] += (*it)->num_points;
+            shaderUboCounts[(*it)->shader_program]++;
          }
 
@@ -1796,5 +1818,5 @@
 
    for (it = objects.begin(); it != objects.end(); it++) {
-      copyObjectDataToBuffers(*it, shaderBufferInfo,
+      copyObjectDataToBuffers(**it, shaderBufferInfo,
          points_vbo,
          colors_vbo,
@@ -1863,12 +1885,12 @@
 }
 
-void translateLaser(SceneObject& laser, const vec3& translation, GLuint ubo) {
+void translateLaser(Laser* laser, const vec3& translation, GLuint ubo) {
    // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
    // and then re-used here
 
-   mat4 new_model_transform = translate(mat4(1.0f), translation) * laser.model_transform;
-
-   vec3 start = vec3(laser.model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
-   vec3 end = vec3(laser.model_transform * vec4(0.0f, 0.0f, laser.points[38], 1.0f));
+   mat4 new_model_transform = translate(mat4(1.0f), translation) * laser->model_transform;
+
+   vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
+   vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[38], 1.0f));
 
    vec3 ray = end - start;
@@ -1889,25 +1911,25 @@
    float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
 
-   laser.model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
-
-   transformObject(laser, translate(mat4(1.0f), translation), ubo);
-}
-
-void updateLaserTarget(SceneObject& laser, vector<SceneObject>& objects, GLuint points_vbo) {
+   laser->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
+
+   transformObject(*laser, translate(mat4(1.0f), translation), ubo);
+}
+
+void updateLaserTarget(Laser* laser, vector<SceneObject*>& objects, GLuint points_vbo) {
    // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
    // and then re-used here
 
-   vec3 start = vec3(laser.model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
-   vec3 end = vec3(laser.model_transform * vec4(0.0f, 0.0f, laser.points[2] + laser.points[20], 1.0f));
+   vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
+   vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[2] + laser->points[20], 1.0f));
 
    vec3 intersection(0.0f), closestIntersection(0.0f);
-   SceneObject* closestAsteroid = NULL;
-
-   for (vector<SceneObject>::iterator it = objects.begin(); it != objects.end(); it++) {
-      if (it->type == TYPE_ASTEROID && !it->deleted && getLaserAndAsteroidIntersection(start, end, *it, intersection)) {
+   Asteroid* closestAsteroid = NULL;
+
+   for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
+      if ((*it)->type == TYPE_ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {
          // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points
          if (closestAsteroid == NULL || intersection.z > closestIntersection.z) {
             // TODO: At this point, find the real intersection of the laser with one of the asteroid's sides
-            closestAsteroid = &*it;
+            closestAsteroid = (Asteroid*)*it;
             closestIntersection = intersection;
          }
@@ -1915,23 +1937,47 @@
    }
 
-   float width = laser.points[0] - laser.points[2];
-
-   float length = 5.24f;
+   float width = laser->points[0] - laser->points[2];
+
+   if (laser->targetAsteroid != closestAsteroid) {
+      if (laser->targetAsteroid != NULL) {
+         if (laser == leftLaser) {
+            leftLaserEffect->deleted = true;
+         } else if (laser == rightLaser) {
+            rightLaserEffect->deleted = true;
+         }
+      }
+
+      EffectOverTime* eot = NULL;
+
+      if (closestAsteroid != NULL) {
+         eot = new EffectOverTime(closestAsteroid->hp, -5, closestAsteroid);
+         effects.push_back(eot);
+      }
+
+      if (laser == leftLaser) {
+         leftLaserEffect = eot;
+      } else if (laser == rightLaser) {
+         rightLaserEffect = eot;
+      }
+   }
+   laser->targetAsteroid = closestAsteroid;
+
+   float length = 5.24f; // I think this was to make sure the laser went past the end of the screen
    if (closestAsteroid != NULL) {
       length = glm::length(closestIntersection - start);
    }
 
-   laser.points[20] = -length + width / 2;
-   laser.points[23] = -length + width / 2;
-   laser.points[29] = -length + width / 2;
-   laser.points[38] = -length;
-   laser.points[41] = -length;
-   laser.points[44] = -length + width / 2;
-   laser.points[47] = -length;
-   laser.points[50] = -length + width / 2;
-   laser.points[53] = -length + width / 2;
+   laser->points[20] = -length + width / 2;
+   laser->points[23] = -length + width / 2;
+   laser->points[29] = -length + width / 2;
+   laser->points[38] = -length;
+   laser->points[41] = -length;
+   laser->points[44] = -length + width / 2;
+   laser->points[47] = -length;
+   laser->points[50] = -length + width / 2;
+   laser->points[53] = -length + width / 2;
 
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
-   glBufferSubData(GL_ARRAY_BUFFER, laser.vertex_vbo_offset * sizeof(GLfloat) * 3, laser.points.size() * sizeof(GLfloat), &laser.points[0]);
+   glBufferSubData(GL_ARRAY_BUFFER, laser->vertex_vbo_offset * sizeof(GLfloat) * 3, laser->points.size() * sizeof(GLfloat), &laser->points[0]);
 }
 
@@ -2042,6 +2088,9 @@
    */
 
+   stringstream ss;
+   ss << "FPS:   " << fps;
+
    {
-      ImGui::SetNextWindowSize(ImVec2(85, 22), ImGuiCond_Once);
+      ImGui::SetNextWindowSize(ImVec2(95, 46), ImGuiCond_Once);
       ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once);
       ImGui::Begin("WndStats", NULL,
@@ -2050,4 +2099,5 @@
          ImGuiWindowFlags_NoMove);
       ImGui::Text("Score: ???");
+      ImGui::Text(ss.str().c_str());
       ImGui::End();
    }
@@ -2108,18 +2158,11 @@
 }
 
-void spawnAsteroid(vec3 pos, GLuint shader,
-                  map<GLuint, BufferInfo>& shaderBufferInfo,
-                  GLuint points_vbo,
-                  GLuint colors_vbo,
-                  GLuint selected_colors_vbo,
-                  GLuint texcoords_vbo,
-                  GLuint normals_vbo,
-                  GLuint ubo,
-                  GLuint model_mat_idx_vbo) {
-   SceneObject obj = SceneObject();
-   obj.type = TYPE_ASTEROID;
-   obj.shader_program = shader;
-
-   obj.points = {
+Asteroid* createAsteroid(vec3 pos, GLuint shader) {
+   Asteroid* obj = new Asteroid();
+   obj->type = TYPE_ASTEROID;
+   obj->hp = 10.0f;
+   obj->shader_program = shader;
+
+   obj->points = {
       // front
       1.0f,  1.0f,  1.0f,
@@ -2170,5 +2213,5 @@
       -1.0f, -1.0f,  1.0f,
    };
-   obj.colors = {
+   obj->colors = {
       // front
       0.8f, 0.0f, 0.0f,
@@ -2219,12 +2262,12 @@
       0.8f, 0.0f, 0.0f,
    };
-   obj.texcoords = { 0.0f };
-   obj.selected_colors = { 0.0f };
+   obj->texcoords = { 0.0f };
+   obj->selected_colors = { 0.0f };
 
    mat4 T = translate(mat4(1.0f), pos);
    mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));
-   obj.model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
-
-   obj.translate_mat = T;
+   obj->model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
+
+   obj->translate_mat = T;
 
    initObject(obj);
@@ -2234,14 +2277,7 @@
    // TODO: Once the intersection check with the sides of the asteroid is done,
    // this can be removed.
-   obj.bounding_radius /= 8.0f;
-
-   addObjectToScene(obj, shaderBufferInfo,
-                  points_vbo,
-                  colors_vbo,
-                  selected_colors_vbo,
-                  texcoords_vbo,
-                  normals_vbo,
-                  ubo,
-                  model_mat_idx_vbo);
+   obj->bounding_radius /= 8.0f;
+
+   return obj;
 }
 
