Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision fe5e3ca6a77a5b0bca064bb258065b3bd70d7e7a)
+++ new-game.cpp	(revision c5fb958b35bfbdd43d77150e4abdeb8fd0efa383)
@@ -50,4 +50,5 @@
    TYPE_ASTEROID,
    TYPE_LASER,
+   TYPE_EXPLOSION,
 };
 
@@ -143,5 +144,6 @@
                   GLuint ubo,
                   GLuint model_mat_idx_vbo,
-                  GLuint asteroid_sp);
+                  GLuint asteroid_sp,
+                  GLuint explosion_sp);
 void removeObjectFromScene(SceneObject& obj, GLuint ubo);
 
@@ -157,5 +159,13 @@
                   GLuint* model_mat_idx_vbo);
 
-GLuint initializeParticleEffectBuffers(vec3 origin, mat4 proj, mat4 view, GLuint explosion_sp);
+GLuint initializeParticleEffectBuffers(vec3 origin, mat4 proj, mat4 view, GLuint explosion_sp,
+                  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 populateBuffers(vector<SceneObject*>& objects,
@@ -168,5 +178,6 @@
                   GLuint ubo,
                   GLuint model_mat_idx_vbo,
-                  GLuint asteroid_sp);
+                  GLuint asteroid_sp,
+                  GLuint explosion_sp);
 
 void copyObjectDataToBuffers(SceneObject& obj,
@@ -183,7 +194,9 @@
 void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
 
+// instead of using these methods, create constructors for these
 SceneObject* createShip(GLuint shader);
 Asteroid* createAsteroid(vec3 pos, GLuint shader);
 Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp);
+SceneObject* createExplosion(GLuint shader);
 
 void translateLaser(Laser* laser, const vec3& translation, GLuint ubo);
@@ -199,5 +212,4 @@
                   GLuint colors_vbo, GLuint selected_colors_vbo,
                   SceneObject* selectedObject);
-void renderExplosion(GLuint explosion_sp, GLuint explosion_vao, GLuint tex);
 
 void renderSceneGui();
@@ -248,4 +260,6 @@
 Laser* rightLaser = NULL;
 EffectOverTime* rightLaserEffect = NULL;
+
+SceneObject* objExplosion;
 
 /*
@@ -450,4 +464,5 @@
    shaderBufferInfo[texture_sp] = BufferInfo();
    shaderBufferInfo[laser_sp] = BufferInfo();
+   shaderBufferInfo[explosion_sp] = BufferInfo();
 
    cam_pos = vec3(0.0f, 0.0f, 2.0f);
@@ -482,5 +497,6 @@
       ubo,
       model_mat_idx_vbo,
-      asteroid_sp);
+      asteroid_sp,
+      explosion_sp);
 
    GLuint color_vao = 0;
@@ -494,15 +510,15 @@
 
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
-   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    // Comment these two lines out when I want to use selected colors
    glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
-   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
-   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
-   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
+   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, NULL);
 
    GLuint asteroid_vao = 0;
@@ -516,14 +532,14 @@
 
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
-   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
-   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
-   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
-   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
+   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, NULL);
 
    GLuint texture_vao = 0;
@@ -537,14 +553,14 @@
 
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
-   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
-   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
-   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
-   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
+   glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, NULL);
 
    GLuint laser_vao = 0;
@@ -557,11 +573,11 @@
 
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
-   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
-   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
-   glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, 0, 0);
+   glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, 0, NULL);
 
    float cam_speed = 1.0f;
@@ -597,5 +613,48 @@
    proj_mat = make_mat4(proj_arr);
 
-   GLuint explosion_vao = initializeParticleEffectBuffers(vec3(0.0f, -1.2f, 0.65f), proj_mat, view_mat, explosion_sp);
+   GLuint explosion_vao = initializeParticleEffectBuffers(vec3(0.0f, -1.2f, 0.65f), proj_mat, view_mat,
+      explosion_sp,
+      shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo);
+
+   /* TODO: Fix the UBO binding code based on the following forum post (in order to support multiple ubos):
+
+      No, you're misunderstanding how this works. UBO binding works exactly like texture object binding.
+
+      The OpenGL context has a number of slots for binding UBOs. There are GL_MAX_UNIFORM_BUFFER_BINDINGS number of
+      slots for UBO binding.
+
+      Uniform Blocks in a program can be set to use one of the slots in the context. You do this by first querying
+      the block index using the block name (glGetUniformBlockIndex). This is similar to how you need to use
+      glGetUniformLocation in order to set a uniform's value with glUniform. Block indices, like uniform locations,
+      are specific to a program.
+
+      Once you have the block index, you use glUniformBlockBinding to set that specific program to use a particular
+      uniform buffer slot in the context.
+
+      Let's say you have a global UBO that you want to use for every program. To make using it easier, you want to
+      bind it just once.
+
+      So first, you pick a uniform buffer slot in the context, one that always will refer to this UBO. Let's say
+      you pick slot 8.
+
+      When you build a program object that may use this global uniform buffer, what you do is quite simple. First,
+      after linking the program, call glGetUniformBlockIndex(program, "NameOfGlobalUniformBlock"). If you get back
+      GL_INVALID_INDEX, then you know that the global uniform block isn't used in that program. Otherwise you get
+      back a block index.
+
+      If you got a valid block index, then you call glUniformBlockBinding(program, uniformBlockIndex, 8). Remember
+      that 8 is the uniform buffer context slot that we selected earlier. This causes this particular program to
+      use uniform buffer slot #8 to find the buffer for "NameOfGlobalUniformBlock".
+
+      Finally, to set the actual buffer in the context, call glBindBufferRange(GL_UNIFORM_BUFFER, 8,
+      bufferObjectName, offset, size);
+   */
 
    GLuint ub_binding_point = 0;
@@ -621,4 +680,5 @@
    GLuint explosion_start_time_loc = glGetUniformLocation(explosion_sp, "explosion_start_time");
    GLuint cur_time_loc = glGetUniformLocation(explosion_sp, "cur_time");
+   //GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(explosion_sp, "models");
 
 
@@ -654,4 +714,11 @@
    glUniformBlockBinding(laser_sp, laser_sp_models_ub_index, ub_binding_point);
    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
+
+
+   /*
+   glUseProgram(explosion_sp);
+   glUniformBlockBinding(explosion_sp, explosion_sp_models_ub_index, ub_binding_point);
+   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
+   */
 
 
@@ -732,5 +799,6 @@
                ubo,
                model_mat_idx_vbo,
-               asteroid_sp);
+               asteroid_sp,
+               explosion_sp);
 
             elapsed_seconds_spawn -= 0.5f;
@@ -792,5 +860,6 @@
                ubo,
                model_mat_idx_vbo,
-               asteroid_sp);
+               asteroid_sp,
+               explosion_sp);
          } else if (key_state[GLFW_KEY_Z] == GLFW_RELEASE) {
             removeObjectFromScene(*leftLaser, ubo);
@@ -810,5 +879,6 @@
                ubo,
                model_mat_idx_vbo,
-               asteroid_sp);
+               asteroid_sp,
+               explosion_sp);
          } else if (key_state[GLFW_KEY_X] == GLFW_RELEASE) {
             removeObjectFromScene(*rightLaser, ubo);
@@ -826,12 +896,34 @@
                }
                if (((Asteroid*)objects[i])->hp <= 0) {
+                  printVector("center", objects[i]->bounding_center);
+
+                  // TODO: Optimize this so I don't recalculate the camera rotation every time
+                  float cam_pitch = -50.0f * 2.0f * 3.14159f / 360.0f;
+                  mat4 pitch_mat = rotate(mat4(1.0f), cam_pitch, vec3(1.0f, 0.0f, 0.0f));
+                  mat4 model_mat = translate(mat4(1.0f), objects[i]->bounding_center + vec3(0.0f, 0.0f, 0.0f)) * pitch_mat;
+
                   removeObjectFromScene(*objects[i], ubo);
                   score++;
 
-                  // render an explosion
+                  objExplosion->model_mat = model_mat;
+
+                  // initiate an explosion
                   glUseProgram(explosion_sp);
+                  
+                  GLuint model_mat_loc = glGetUniformLocation(explosion_sp, "model_mat");
+                  glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, value_ptr(objExplosion->model_mat));
+
+                  // TODO: To get ubos working for the explosion,
+                  // I need to calculate the correct ubo index for the model matrix
+                  // Then I need to copy the matrix into the right place in the ubo and
+                  // copy the index into the correct uniform
+
+                  // STEP 1: Make sure the UBO offset for the explosion shader is correct
+
+                  cout << "UBO OFFSET: " << objExplosion->ubo_offset << endl;
+                  //glBindBuffer(GL_UNIFORM_BUFFER, ubo);
+                  //glBufferSubData(GL_UNIFORM_BUFFER, objExplosion->ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(objExplosion->model_mat));
+
                   glUniform1f(explosion_start_time_loc, (GLfloat)glfwGetTime());
-                  cout << "REMOVED" << endl;
-                  cout << i << endl;
                }
             }
@@ -1288,5 +1380,5 @@
    }
 
-   if (obj->type != TYPE_LASER) {
+   if (obj->type == TYPE_SHIP || obj->type == TYPE_ASTEROID) {
       calculateObjectBoundingBox(obj);
 
@@ -1304,5 +1396,6 @@
    GLuint ubo,
    GLuint model_mat_idx_vbo,
-   GLuint asteroid_sp) {
+   GLuint asteroid_sp,
+   GLuint explosion_sp) {
    objects.push_back(obj);
 
@@ -1311,5 +1404,5 @@
    // 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->vbo_offset + obj->num_points) ||
       bufferInfo->ubo_capacity < (bufferInfo->ubo_offset + 1)) {
 
@@ -1329,5 +1422,6 @@
          ubo,
          model_mat_idx_vbo,
-         asteroid_sp);
+         asteroid_sp,
+         explosion_sp);
    } else {
       copyObjectDataToBuffers(*objects.back(), shaderBufferInfo,
@@ -1805,5 +1899,4 @@
 */
 // TODO: Make the color parameter have an effect
-// TODO: Come up with a better way of passing the object back than copying it
 Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp) {
    Laser* obj = new Laser();
@@ -1912,5 +2005,13 @@
 }
 
-GLuint initializeParticleEffectBuffers(vec3 origin, mat4 proj, mat4 view, GLuint explosion_sp) {
+GLuint initializeParticleEffectBuffers(vec3 origin, mat4 proj, mat4 view, GLuint explosion_sp,
+                  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) {
    //unsigned int num_explosions = 1;
 
@@ -1969,4 +2070,8 @@
    glBindVertexArray(vao);
 
+   glEnableVertexAttribArray(0);
+   glEnableVertexAttribArray(1);
+   glEnableVertexAttribArray(2);
+
    glBindBuffer(GL_ARRAY_BUFFER, velocity_vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
@@ -1975,6 +2080,21 @@
    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, NULL);
 
-   glEnableVertexAttribArray(0);
-   glEnableVertexAttribArray(1);
+   // TODO: I think I can call glVertexAttribIPointer whenever the vbo_base changes
+   // to rebind the ubo index vbo
+   glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
+   glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, 0, NULL);
+
+   objExplosion = createExplosion(explosion_sp);
+   objExplosion->num_points = EXPLOSION_PARTICLE_COUNT;
+   addObjectToScene(objExplosion, shaderBufferInfo,
+      points_vbo,
+      colors_vbo,
+      selected_colors_vbo,
+      texcoords_vbo,
+      normals_vbo,
+      ubo,
+      model_mat_idx_vbo,
+      0,
+      explosion_sp);
 
    return vao;
@@ -1990,5 +2110,6 @@
                   GLuint ubo,
                   GLuint ubo_idx_vbo,
-                  GLuint asteroid_sp) {
+                  GLuint asteroid_sp,
+                  GLuint explosion_sp) {
    GLsizeiptr num_points = 0;
    GLsizeiptr num_objects = 0;
@@ -1996,4 +2117,11 @@
    map<GLuint, unsigned int> shaderCounts;
    map<GLuint, unsigned int> shaderUboCounts;
+
+   map<GLuint, BufferInfo>::iterator shaderIt;
+
+   for (shaderIt = shaderBufferInfo.begin(); shaderIt != shaderBufferInfo.end(); shaderIt++) {
+      shaderCounts[shaderIt->first] = 0;
+      shaderUboCounts[shaderIt->first] = 0;
+   }
 
    vector<SceneObject*>::iterator it;
@@ -2013,11 +2141,6 @@
          num_objects++;
 
-         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]++;
 
          it++;
@@ -2029,5 +2152,5 @@
    num_objects *= 2;
 
-   map<GLuint, unsigned int>::iterator shaderIt;
+   map<GLuint, unsigned int>::iterator shaderCountIt;
    unsigned int lastShaderCount = 0;
    unsigned int lastShaderUboCount = 0;
@@ -2040,26 +2163,30 @@
    * object being added.
    */
-   for (shaderIt = shaderCounts.begin(); shaderIt != shaderCounts.end(); shaderIt++) {
+   for (shaderCountIt = shaderCounts.begin(); shaderCountIt != shaderCounts.end(); shaderCountIt++) {
       // When populating the buffers, leave as much empty space as space taken up by existing objects
       // to allow new objects to be added without immediately having to resize the buffers
-      shaderBufferInfo[shaderIt->first].vbo_base = lastShaderCount * 2;
-      shaderBufferInfo[shaderIt->first].ubo_base = lastShaderUboCount * 2;
+      shaderBufferInfo[shaderCountIt->first].vbo_base = lastShaderCount * 2;
+      shaderBufferInfo[shaderCountIt->first].ubo_base = lastShaderUboCount * 2;
+
+      if (shaderCountIt->first == explosion_sp) {
+         cout << "EXPLOSION VBO_BASE: " << shaderBufferInfo[shaderCountIt->first].vbo_base << endl;
+      }
 
       /*
-      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;
+      cout << "shader: " << shaderCountIt->first << endl;
+      cout << "point counts: " << shaderCounts[shaderCountIt->first] << endl;
+      cout << "object counts: " << shaderUboCounts[shaderCountIt->first] << endl;
+      cout << "vbo_base: " << shaderBufferInfo[shaderCountIt->first].vbo_base << endl;
+      cout << "ubo_base: " << shaderBufferInfo[shaderCountIt->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];
-      lastShaderUboCount += shaderUboCounts[shaderIt->first];
+      shaderBufferInfo[shaderCountIt->first].vbo_offset = 0;
+      shaderBufferInfo[shaderCountIt->first].ubo_offset = 0;
+
+      shaderBufferInfo[shaderCountIt->first].vbo_capacity = shaderCounts[shaderCountIt->first] * 2;
+      shaderBufferInfo[shaderCountIt->first].ubo_capacity = shaderUboCounts[shaderCountIt->first] * 2;
+
+      lastShaderCount += shaderCounts[shaderCountIt->first];
+      lastShaderUboCount += shaderUboCounts[shaderCountIt->first];
    }
 
@@ -2115,10 +2242,7 @@
    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, texcoords_vbo);
-   glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 2, obj.texcoords.size() * sizeof(GLfloat), &obj.texcoords[0]);
-
+   if (obj.type == TYPE_EXPLOSION) {
+      cout << "UBO OFFSET: " << obj.ubo_offset << endl;
+   }
    glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
    for (unsigned int i = 0; i < obj.num_points; i++) {
@@ -2126,25 +2250,33 @@
    }
 
-   if (obj.type != TYPE_LASER) {
-      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, normals_vbo);
-      glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.normals.size() * sizeof(GLfloat), &obj.normals[0]);
-   }
-
-   obj.model_mat = obj.model_transform * obj.model_base;
-   glBindBuffer(GL_UNIFORM_BUFFER, ubo);
-   glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
-
-   if (obj.type == TYPE_ASTEROID) {
-      glUseProgram(asteroid_sp);
-
-      ostringstream oss;
-      oss << "hp[" << obj.ubo_offset << "]";
-      glUniform1f(glGetUniformLocation(asteroid_sp, oss.str().c_str()), ((Asteroid*)&obj)->hp);
+   if (obj.type != TYPE_EXPLOSION) {
+      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, texcoords_vbo);
+      glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 2, obj.texcoords.size() * sizeof(GLfloat), &obj.texcoords[0]);
+
+      if (obj.type != TYPE_LASER) {
+         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, normals_vbo);
+         glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.normals.size() * sizeof(GLfloat), &obj.normals[0]);
+      }
+
+      obj.model_mat = obj.model_transform * obj.model_base;
+      glBindBuffer(GL_UNIFORM_BUFFER, ubo);
+      glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
+
+      if (obj.type == TYPE_ASTEROID) {
+         glUseProgram(asteroid_sp);
+
+         ostringstream oss;
+         oss << "hp[" << obj.ubo_offset << "]";
+         glUniform1f(glGetUniformLocation(asteroid_sp, oss.str().c_str()), ((Asteroid*)&obj)->hp);
+      }
    }
 
@@ -2325,5 +2457,5 @@
    if (selectedObject != NULL) {
       glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
-      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
       glDrawArrays(GL_TRIANGLES, selectedObject->vertex_vbo_offset, selectedObject->num_points);
@@ -2333,5 +2465,5 @@
    // Uncomment this code when I want to use selected colors again
    // glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
-   // glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
+   // glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
    glDrawArrays(GL_TRIANGLES, shaderBufferInfo[color_sp].vbo_base, shaderBufferInfo[color_sp].vbo_offset);
@@ -2354,20 +2486,15 @@
    glDrawArrays(GL_TRIANGLES, shaderBufferInfo[laser_sp].vbo_base, shaderBufferInfo[laser_sp].vbo_offset);
 
-   glDisable(GL_BLEND);
-
-   renderExplosion(explosion_sp, explosion_vao, 0);
-}
-
-void renderExplosion(GLuint explosion_sp, GLuint explosion_vao, GLuint tex) {
-   glEnable(GL_BLEND);
+   glUseProgram(explosion_sp);
+
+   //glActiveTexture(GL_TEXTURE1);
+   //glBindTexture(GL_TEXTURE_2D, tex); // tex is 0 here
+
    glEnable(GL_PROGRAM_POINT_SIZE);
-
-   //glActiveTexture(GL_TEXTURE1);
-   //glBindTexture(GL_TEXTURE_2D, tex);
-   glUseProgram(explosion_sp);
-
    glBindVertexArray(explosion_vao);
 
-   glDrawArrays(GL_POINTS, 0, EXPLOSION_PARTICLE_COUNT);
+   glDrawArrays(GL_POINTS, 0, shaderBufferInfo[explosion_sp].vbo_offset);
+   //glDrawArrays(GL_POINTS, shaderBufferInfo[explosion_sp].vbo_base, shaderBufferInfo[explosion_sp].vbo_offset);
+   //cout << shaderBufferInfo[explosion_sp].vbo_base << ", " << shaderBufferInfo[explosion_sp].vbo_offset << endl;
 
    glDisable(GL_PROGRAM_POINT_SIZE);
@@ -2474,6 +2601,6 @@
    Asteroid* obj = new Asteroid();
    obj->type = TYPE_ASTEROID;
+   obj->shader_program = shader;
    obj->hp = 10.0f;
-   obj->shader_program = shader;
 
    obj->points = {
@@ -2595,4 +2722,17 @@
 }
 
+SceneObject* createExplosion(GLuint shader) {
+   SceneObject* obj = new SceneObject();
+   obj->type = TYPE_EXPLOSION;
+   obj->shader_program = shader;
+
+   obj->points = {};
+   obj->colors = {};
+
+   initObject(obj);
+
+   return obj;
+}
+
 float getRandomNum(float low, float high) {
    return low + ((float)rand()/RAND_MAX) * (high-low);
