Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision 8d5e67b04a81ce0618a77041eacf03ded067e180)
+++ new-game.cpp	(revision c3c31583ad31ee8dd502bda3b31722487b8ec276)
@@ -42,6 +42,6 @@
    GLuint shader_program;
    unsigned int num_points;
-   GLint vertex_vbo_offset;
-   GLint ubo_offset;
+   GLuint vertex_vbo_offset;
+   GLuint ubo_offset;
    vector<GLfloat> points;
    vector<GLfloat> colors;
@@ -49,4 +49,14 @@
    vector<GLfloat> normals;
    vector<GLfloat> selected_colors;
+   bool deleted;
+};
+
+struct BufferInfo {
+   unsigned int vbo_base;
+   unsigned int vbo_offset;
+   unsigned int vbo_capacity;
+   unsigned int ubo_base;
+   unsigned int ubo_offset;
+   unsigned int ubo_capacity;
 };
 
@@ -84,4 +94,5 @@
 mat4 proj_mat;
 
+// TODO: Consider using a list instead since it will make element deletion more efficient
 vector<SceneObject> objects;
 queue<Event> events;
@@ -113,15 +124,43 @@
 void print4DVector(string label, vec4 v);
 
-void addObjectToScene(SceneObject& obj);
+void addObjectToSceneDuringInit(SceneObject& obj);
+void addObjectToScene(SceneObject& obj, 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);
+void removeObjectFromScene(int objectId, GLuint ubo);
+
+void initializeBuffers(
+                  GLuint* points_vbo,
+                  GLuint* colors_vbo,
+                  GLuint* selected_colors_vbo,
+                  GLuint* texcoords_vbo,
+                  GLuint* normals_vbo,
+                  GLuint* ubo,
+                  GLuint* model_mat_idx_vbo);
+
 void populateBuffers(vector<SceneObject>& objects,
-                     GLuint* points_vbo,
-                     GLuint* colors_vbo,
-                     GLuint* selected_colors_vbo,
-                     GLuint* texcoords_vbo,
-                     GLuint* normals_vbo,
-                     GLuint* ubo,
-                     GLuint* model_mat_idx_vbo,
-                     map<GLuint, unsigned int>& shaderCounts,
-                     map<GLuint, unsigned int>& curShaderBase);
+                  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);
+
+void copyObjectDataToBuffers(SceneObject& obj,
+                  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);
 
 void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
@@ -136,9 +175,16 @@
                   GLuint colors_vbo, GLuint texcoords_vbo, GLuint selected_colors_vbo,
                   SceneObject* selectedObject,
-                  map<GLuint, unsigned int>& shaderCounts,
-                  map<GLuint, unsigned int>& curShaderBase);
+                  map<GLuint, BufferInfo>& shaderBufferInfo);
 void renderSceneGui();
 
-void spawnAsteroid(vec3 pos, GLuint shader);
+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);
 
 int main(int argc, char* argv[]) {
@@ -285,6 +331,11 @@
     */
 
+   map<GLuint, BufferInfo> shaderBufferInfo;
+
    GLuint color_sp = loadShaderProgram("./color.vert", "./color.frag");
    GLuint texture_sp = loadShaderProgram("./texture.vert", "./texture.frag");
+
+   shaderBufferInfo[color_sp] = BufferInfo();
+   shaderBufferInfo[texture_sp] = BufferInfo();
 
    SceneObject obj;
@@ -328,9 +379,9 @@
    };
 
-   T_model = translate(mat4(), vec3(0.45f, 0.0f, 0.0f));
+   T_model = translate(mat4(), vec3(0.45f, -1.5f, 0.0f));
    R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
    obj.model_base = T_model*R_model;
 
-   addObjectToScene(obj);
+   addObjectToSceneDuringInit(obj);
 
    // square
@@ -370,9 +421,9 @@
    };
 
-   T_model = translate(mat4(), vec3(-0.5f, 0.0f, -1.00f));
+   T_model = translate(mat4(), vec3(-0.5f, -1.5f, -1.00f));
    R_model = rotate(mat4(), 0.5f, vec3(0.0f, 1.0f, 0.0f));
    obj.model_base = T_model*R_model;
 
-   addObjectToScene(obj);
+   addObjectToSceneDuringInit(obj);
    */
 
@@ -753,28 +804,75 @@
    obj.model_base = T_model * R_model * scale(mat4(), vec3(0.1f, 0.1f, 0.1f));
 
-   addObjectToScene(obj);
-
-   spawnAsteroid(vec3(0.0f, -1.2f, -21.5f), color_sp);
-   spawnAsteroid(vec3(1.0f, -1.2f, -21.5f), color_sp);
-   spawnAsteroid(vec3(-0.5f, -1.2f, -20.8f), color_sp);
+   addObjectToSceneDuringInit(obj);
 
    vector<SceneObject>::iterator obj_it;
-   GLsizeiptr offset;
 
    GLuint points_vbo, colors_vbo, selected_colors_vbo, texcoords_vbo,
       normals_vbo, ubo, model_mat_idx_vbo;
 
-   map<GLuint, unsigned int> shaderCounts, curShaderBase;
+   initializeBuffers(
+      &points_vbo,
+      &colors_vbo,
+      &selected_colors_vbo,
+      &texcoords_vbo,
+      &normals_vbo,
+      &ubo,
+      &model_mat_idx_vbo);
 
    populateBuffers(objects,
-                  &points_vbo,
-                  &colors_vbo,
-                  &selected_colors_vbo,
-                  &texcoords_vbo,
-                  &normals_vbo,
-                  &ubo,
-                  &model_mat_idx_vbo,
-                  shaderCounts,
-                  curShaderBase);
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+
+   spawnAsteroid(vec3(0.0f, -1.2f, -21.5f), color_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+   spawnAsteroid(vec3(1.0f, -1.2f, -21.5f), color_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+   spawnAsteroid(vec3(-0.5f, -1.2f, -20.8f), color_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+   spawnAsteroid(vec3(-0.3f, -1.2f, -20.8f), color_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+   spawnAsteroid(vec3(-0.1f, -1.2f, -20.8f), color_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
 
    GLuint vao = 0;
@@ -969,5 +1067,78 @@
             transformObject(objects[2], translate(mat4(), vec3(0.0f, 0.0f, 0.06f)), ubo);
             transformObject(objects[3], translate(mat4(), vec3(0.0f, 0.0f, 0.04f)), ubo);
+            transformObject(objects[4], translate(mat4(), vec3(0.0f, 0.0f, 0.06f)), ubo);
+            transformObject(objects[5], translate(mat4(), vec3(0.0f, 0.0f, 0.04f)), ubo);
          }
+
+         if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
+            removeObjectFromScene(0, ubo);
+         }
+      }
+
+      if (key_state[GLFW_KEY_ESCAPE] == GLFW_PRESS) {
+         glfwSetWindowShouldClose(window, 1);
+      }
+
+      float dist = cam_speed * elapsed_seconds;
+      if (key_pressed[GLFW_KEY_A]) {
+         vec3 dir = (inverse(R) * vec4(-1.0f, 0.0f, 0.0f, 1.0f)).xyz();
+         cam_pos += dir * dist;
+
+         cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_D]) {
+         vec3 dir = (inverse(R) * vec4(1.0f, 0.0f, 0.0f, 1.0f)).xyz();
+         cam_pos += dir * dist;
+
+         cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_W]) {
+         vec3 dir = (inverse(R) * vec4(0.0f, 0.0f, -1.0f, 1.0f)).xyz();
+         cam_pos += dir * dist;
+
+         cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_S]) {
+         vec3 dir = (inverse(R) * vec4(0.0f, 0.0f, 1.0f, 1.0f)).xyz();
+         cam_pos += dir * dist;
+
+         cam_moved = true;
+      }
+      /*
+      if (key_pressed[GLFW_KEY_LEFT]) {
+      cam_yaw += cam_yaw_speed * elapsed_seconds;
+      cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_RIGHT]) {
+      cam_yaw -= cam_yaw_speed * elapsed_seconds;
+      cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_UP]) {
+      cam_pitch += cam_pitch_speed * elapsed_seconds;
+      cam_moved = true;
+      }
+      if (key_pressed[GLFW_KEY_DOWN]) {
+      cam_pitch -= cam_pitch_speed * elapsed_seconds;
+      cam_moved = true;
+      }
+      */
+      if (cam_moved) {
+         T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
+
+         mat4 yaw_mat = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
+         mat4 pitch_mat = rotate(mat4(), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
+         R = pitch_mat * yaw_mat;
+
+         view_mat = R * T;
+
+         //printVector("cam pos", cam_pos);
+
+         glUseProgram(color_sp);
+         glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
+
+         glUseProgram(texture_sp);
+         glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
+
+         cam_moved = false;
       }
 
@@ -988,5 +1159,5 @@
                colors_vbo, texcoords_vbo, selected_colors_vbo,
                selectedObject,
-               shaderCounts, curShaderBase);
+               shaderBufferInfo);
             renderSceneGui();
             break;
@@ -994,71 +1165,4 @@
 
       glfwSwapBuffers(window);
-
-      if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
-         glfwSetWindowShouldClose(window, 1);
-      }
-
-      float dist = cam_speed * elapsed_seconds;
-      if (glfwGetKey(window, GLFW_KEY_A)) {
-         vec3 dir = (inverse(R) * vec4(-1.0f, 0.0f, 0.0f, 1.0f)).xyz();
-         cam_pos += dir * dist;
-
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_D)) {
-         vec3 dir = (inverse(R) * vec4(1.0f, 0.0f, 0.0f, 1.0f)).xyz();
-         cam_pos += dir * dist;
-
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_W)) {
-         vec3 dir = (inverse(R) * vec4(0.0f, 0.0f, -1.0f, 1.0f)).xyz();
-         cam_pos += dir * dist;
-
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_S)) {
-         vec3 dir = (inverse(R) * vec4(0.0f, 0.0f, 1.0f, 1.0f)).xyz();
-         cam_pos += dir * dist;
-
-         cam_moved = true;
-      }
-      /*
-      if (glfwGetKey(window, GLFW_KEY_LEFT)) {
-         cam_yaw += cam_yaw_speed * elapsed_seconds;
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_RIGHT)) {
-         cam_yaw -= cam_yaw_speed * elapsed_seconds;
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_UP)) {
-         cam_pitch += cam_pitch_speed * elapsed_seconds;
-         cam_moved = true;
-      }
-      if (glfwGetKey(window, GLFW_KEY_DOWN)) {
-         cam_pitch -= cam_pitch_speed * elapsed_seconds;
-         cam_moved = true;
-      }
-      */
-      if (cam_moved) {
-         T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
-
-         mat4 yaw_mat = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
-         mat4 pitch_mat = rotate(mat4(), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
-         R = pitch_mat * yaw_mat;
-
-         view_mat = R*T;
-
-         //printVector("cam pos", cam_pos);
-
-         glUseProgram(color_sp);
-         glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
-
-         glUseProgram(texture_sp);
-         glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
-
-         cam_moved = false;
-      }
    }
 
@@ -1265,8 +1369,9 @@
 }
 
-void addObjectToScene(SceneObject& obj) {
+void addObjectToSceneDuringInit(SceneObject& obj) {
    obj.id = objects.size(); // currently unused
    obj.num_points = obj.points.size() / 3;
    obj.model_transform = mat4();
+   obj.deleted = false;
 
    obj.normals.reserve(obj.points.size());
@@ -1289,14 +1394,91 @@
 }
 
+void addObjectToScene(SceneObject& obj,
+                  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) {
+   addObjectToSceneDuringInit(obj);
+
+   BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
+
+   // Check if the buffers aren't large enough to fit the new object and, if so, print an error and quit.
+   // This is a temporary sanity check to make sure things are working as expected
+   if (bufferInfo->vbo_capacity < (bufferInfo->ubo_offset + obj.num_points) ||
+      bufferInfo->ubo_capacity < (bufferInfo->ubo_offset + 1)) {
+      populateBuffers(objects, shaderBufferInfo,
+         points_vbo,
+         colors_vbo,
+         selected_colors_vbo,
+         texcoords_vbo,
+         normals_vbo,
+         ubo,
+         model_mat_idx_vbo);
+   } else {
+      copyObjectDataToBuffers(objects.back(), shaderBufferInfo,
+         points_vbo,
+         colors_vbo,
+         selected_colors_vbo,
+         texcoords_vbo,
+         normals_vbo,
+         ubo,
+         model_mat_idx_vbo);
+   }
+}
+
+void removeObjectFromScene(int objectId, GLuint ubo) {
+   SceneObject& obj = objects[objectId];
+
+   if (!obj.deleted) {
+      // Move the object outside the render bounds of the scene so it doesn't get rendered
+      // TODO: Find a better way of hiding the object until the next time buffers are repopulated
+      transformObject(obj, translate(mat4(), vec3(0.0f, 0.0f, FAR_CLIP * 1000.0f)), ubo);
+      obj.deleted = true;
+   }
+}
+
+void initializeBuffers(
+                  GLuint* points_vbo,
+                  GLuint* colors_vbo,
+                  GLuint* selected_colors_vbo,
+                  GLuint* texcoords_vbo,
+                  GLuint* normals_vbo,
+                  GLuint* ubo,
+                  GLuint* model_mat_idx_vbo) {
+   *points_vbo = 0;
+   glGenBuffers(1, points_vbo);
+
+   *colors_vbo = 0;
+   glGenBuffers(1, colors_vbo);
+
+   *selected_colors_vbo = 0;
+   glGenBuffers(1, selected_colors_vbo);
+
+   *texcoords_vbo = 0;
+   glGenBuffers(1, texcoords_vbo);
+
+   *normals_vbo = 0;
+   glGenBuffers(1, normals_vbo);
+
+   *ubo = 0;
+   glGenBuffers(1, ubo);
+
+   *model_mat_idx_vbo = 0;
+   glGenBuffers(1, model_mat_idx_vbo);
+}
+
 void populateBuffers(vector<SceneObject>& objects,
-                     GLuint* points_vbo,
-                     GLuint* colors_vbo,
-                     GLuint* selected_colors_vbo,
-                     GLuint* texcoords_vbo,
-                     GLuint* normals_vbo,
-                     GLuint* ubo,
-                     GLuint* model_mat_idx_vbo,
-                     map<GLuint, unsigned int>& shaderCounts,
-                     map<GLuint, unsigned int>& curShaderBase) {
+                  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) {
    GLsizeiptr points_buffer_size = 0;
    GLsizeiptr textures_buffer_size = 0;
@@ -1304,32 +1486,41 @@
    GLsizeiptr model_mat_idx_buffer_size = 0;
 
-   map<GLuint, unsigned int> curShaderOffset;
-
+   map<GLuint, unsigned int> shaderCounts;
    map<GLuint, unsigned int> shaderUboCounts;
-   map<GLuint, unsigned int> curShaderUboBase;
-   map<GLuint, unsigned int> curShaderUboOffset;
 
    vector<SceneObject>::iterator it;
 
    /* Find all shaders that need to be used and  the number of objects and
-    * number of points for each shader. Construct a map from shader id to count
-    * of points being drawn using that shader (for thw model matrix ubo, we
-    * need object counts instead). These will be used to get offsets into the
-    * vertex buffer for each shader.
-    */
-   for (it = objects.begin(); it != objects.end(); it++) {
-      points_buffer_size += it->points.size() * sizeof(GLfloat);
-      textures_buffer_size += it->texcoords.size() * sizeof(GLfloat);
-      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;
+   * number of points for each shader. Construct a map from shader id to count
+   * of points being drawn using that shader (for thw model matrix ubo, we
+   * need object counts instead). These will be used to get offsets into the
+   * vertex buffer for each shader.
+   */
+   for (it = objects.begin(); it != objects.end();) {
+      if (it->deleted) {
+         it = objects.erase(it);
       } else {
-         shaderCounts[it->shader_program] += it->num_points;
-         shaderUboCounts[it->shader_program]++;
-      }
-   }
+         points_buffer_size += it->points.size() * sizeof(GLfloat);
+         textures_buffer_size += it->texcoords.size() * sizeof(GLfloat);
+         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;
+         } else {
+            shaderCounts[it->shader_program] += it->num_points;
+            shaderUboCounts[it->shader_program]++;
+         }
+
+         it++;
+      }
+   }
+
+   // double the buffer sizes to leave room for new objects
+   points_buffer_size *= 2;
+   textures_buffer_size *= 2;
+   ubo_buffer_size *= 2;
+   model_mat_idx_buffer_size *= 2;
 
    map<GLuint, unsigned int>::iterator shaderIt;
@@ -1338,91 +1529,104 @@
 
    /*
-    * The counts calculated above can be used to get the starting offset of
-    * each shader in the vertex buffer. Create a map of base offsets to mark
-    * where the data for the first object using a given shader begins. Also,
-    * create a map of current offsets to mark where to copy data for the next
-    * object being added.
-    */
-   cout << "Shader counts:" << endl;
+   * The counts calculated above can be used to get the starting offset of
+   * each shader in the vertex buffer. Create a map of base offsets to mark
+   * where the data for the first object using a given shader begins. Also,
+   * create a map of current offsets to mark where to copy data for the next
+   * object being added.
+   */
    for (shaderIt = shaderCounts.begin(); shaderIt != shaderCounts.end(); shaderIt++) {
-      curShaderOffset[shaderIt->first] = 0;
-      curShaderUboOffset[shaderIt->first] = 0;
-
-      curShaderBase[shaderIt->first] = lastShaderCount;
+      shaderBufferInfo[shaderIt->first].vbo_base = lastShaderCount * 2;
+      shaderBufferInfo[shaderIt->first].ubo_base = lastShaderUboCount * 2;
+      cout << "shader: " << shaderIt->first << endl;
+      cout << "point counts: " << shaderCounts[shaderIt->first] << endl;
+      cout << "object counts: " << shaderUboCounts[shaderIt->first] << endl;
+      cout << "vbo_base: " << shaderBufferInfo[shaderIt->first].vbo_base << endl;
+      cout << "ubo_base: " << shaderBufferInfo[shaderIt->first].ubo_base << endl;
+
+      shaderBufferInfo[shaderIt->first].vbo_offset = 0;
+      shaderBufferInfo[shaderIt->first].ubo_offset = 0;
+
+      shaderBufferInfo[shaderIt->first].vbo_capacity = shaderCounts[shaderIt->first] * 2;
+      shaderBufferInfo[shaderIt->first].ubo_capacity = shaderUboCounts[shaderIt->first] * 2;
+
       lastShaderCount += shaderCounts[shaderIt->first];
-
-      curShaderUboBase[shaderIt->first] = lastShaderUboCount;
       lastShaderUboCount += shaderUboCounts[shaderIt->first];
    }
 
-   // Initialize all the buffers using the counts calculated above
-
-   *points_vbo = 0;
-   glGenBuffers(1, points_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *points_vbo);
+   // Allocate all the buffers using the counts calculated above
+
+   glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
    glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *colors_vbo = 0;
-   glGenBuffers(1, colors_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *colors_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
    glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *selected_colors_vbo = 0;
-   glGenBuffers(1, selected_colors_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *selected_colors_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
    glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *texcoords_vbo = 0;
-   glGenBuffers(1, texcoords_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *texcoords_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
    glBufferData(GL_ARRAY_BUFFER, textures_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *normals_vbo = 0;
-   glGenBuffers(1, normals_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *normals_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
    glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *ubo = 0;
-   glGenBuffers(1, ubo);
-   glBindBuffer(GL_UNIFORM_BUFFER, *ubo);
+   glBindBuffer(GL_UNIFORM_BUFFER, ubo);
    glBufferData(GL_UNIFORM_BUFFER, ubo_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
-   *model_mat_idx_vbo = 0;
-   glGenBuffers(1, model_mat_idx_vbo);
-   glBindBuffer(GL_ARRAY_BUFFER, *model_mat_idx_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
    glBufferData(GL_ARRAY_BUFFER, model_mat_idx_buffer_size, NULL, GL_DYNAMIC_DRAW);
 
    for (it = objects.begin(); it != objects.end(); it++) {
-      it->vertex_vbo_offset = curShaderBase[it->shader_program] + curShaderOffset[it->shader_program];
-      it->ubo_offset = curShaderUboBase[it->shader_program] + curShaderUboOffset[it->shader_program];
-
-      glBindBuffer(GL_ARRAY_BUFFER, *points_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->points.size() * sizeof(GLfloat), &it->points[0]);
-
-      glBindBuffer(GL_ARRAY_BUFFER, *colors_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->colors.size() * sizeof(GLfloat), &it->colors[0]);
-
-      glBindBuffer(GL_ARRAY_BUFFER, *selected_colors_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->selected_colors.size() * sizeof(GLfloat), &it->selected_colors[0]);
-
-      glBindBuffer(GL_ARRAY_BUFFER, *texcoords_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 2, it->texcoords.size() * sizeof(GLfloat), &it->texcoords[0]);
-
-      glBindBuffer(GL_ARRAY_BUFFER, *normals_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->normals.size() * sizeof(GLfloat), &it->normals[0]);
-
-      glBindBuffer(GL_ARRAY_BUFFER, *model_mat_idx_vbo);
-      for (int i = 0; i < it->num_points; i++) {
-         glBufferSubData(GL_ARRAY_BUFFER, (it->vertex_vbo_offset + i) * sizeof(GLuint), sizeof(GLuint), &it->ubo_offset);
-      }
-
-      curShaderOffset[it->shader_program] += it->num_points;
-
-      it->model_mat = it->model_base * it->model_transform;
-      glBindBuffer(GL_UNIFORM_BUFFER, *ubo);
-      glBufferSubData(GL_UNIFORM_BUFFER, it->ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(it->model_mat));
-
-      curShaderUboOffset[it->shader_program]++;
-   }
+      copyObjectDataToBuffers(*it, shaderBufferInfo,
+         points_vbo,
+         colors_vbo,
+         selected_colors_vbo,
+         texcoords_vbo,
+         normals_vbo,
+         ubo,
+         model_mat_idx_vbo);
+   }
+}
+
+void copyObjectDataToBuffers(SceneObject& obj,
+                  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) {
+   BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
+
+   obj.vertex_vbo_offset = bufferInfo->vbo_base + bufferInfo->vbo_offset;
+   obj.ubo_offset = bufferInfo->ubo_base + bufferInfo->ubo_offset;
+
+   glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
+   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.points.size() * sizeof(GLfloat), &obj.points[0]);
+
+   glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
+   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.colors.size() * sizeof(GLfloat), &obj.colors[0]);
+
+   glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
+   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.selected_colors.size() * sizeof(GLfloat), &obj.selected_colors[0]);
+
+   glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
+   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 2, obj.texcoords.size() * sizeof(GLfloat), &obj.texcoords[0]);
+
+   glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
+   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.normals.size() * sizeof(GLfloat), &obj.normals[0]);
+
+   glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
+   for (int i = 0; i < obj.num_points; i++) {
+      glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * sizeof(GLuint), sizeof(GLuint), &obj.ubo_offset);
+   }
+
+   obj.model_mat = obj.model_base * obj.model_transform;
+   glBindBuffer(GL_UNIFORM_BUFFER, ubo);
+   glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
+
+   bufferInfo->vbo_offset += obj.num_points;
+   bufferInfo->ubo_offset++;
 }
 
@@ -1441,6 +1645,5 @@
                   GLuint colors_vbo, GLuint texcoords_vbo, GLuint selected_colors_vbo,
                   SceneObject* selectedObject,
-                  map<GLuint, unsigned int>& shaderCounts,
-                  map<GLuint, unsigned int>& curShaderBase) {
+                  map<GLuint, BufferInfo>& shaderBufferInfo) {
 
    glUseProgram(color_sp);
@@ -1457,10 +1660,10 @@
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
 
-   glDrawArrays(GL_TRIANGLES, curShaderBase[color_sp], shaderCounts[color_sp]);
+   glDrawArrays(GL_TRIANGLES, shaderBufferInfo[color_sp].vbo_base, shaderBufferInfo[color_sp].vbo_offset);
 
    glUseProgram(texture_sp);
    glBindVertexArray(vao2);
 
-   glDrawArrays(GL_TRIANGLES, curShaderBase[texture_sp], shaderCounts[texture_sp]);
+   glDrawArrays(GL_TRIANGLES, shaderBufferInfo[texture_sp].vbo_base, shaderBufferInfo[texture_sp].vbo_offset);
 }
 
@@ -1556,5 +1759,13 @@
 }
 
-void spawnAsteroid(vec3 pos, GLuint shader) {
+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.shader_program = shader;
@@ -1665,4 +1876,11 @@
    obj.model_base = T * R * scale(mat4(), vec3(0.1f, 0.1f, 0.1f));
 
-   addObjectToScene(obj);
-}
+   addObjectToScene(obj, shaderBufferInfo,
+                  points_vbo,
+                  colors_vbo,
+                  selected_colors_vbo,
+                  texcoords_vbo,
+                  normals_vbo,
+                  ubo,
+                  model_mat_idx_vbo);
+}
