Index: laser.vert
===================================================================
--- laser.vert	(revision 9f9f9a7cc841cfce67bdaef5b74e8948bf835d81)
+++ laser.vert	(revision fd6f4653858e63f2de67d87f3a8ac9a5ca787745)
@@ -1,8 +1,15 @@
 #version 410
+
+#define MAX_NUM_OBJECTS 1024
 
 uniform mat4 view, proj;
 
+layout (std140) uniform models {
+  mat4 model_mats[MAX_NUM_OBJECTS];
+};
+
 layout(location = 0) in vec3 vertex_position;
 layout(location = 1) in vec2 vt;
+layout(location = 2) in uint ubo_index;
 
 out vec2 texture_coordinates;
@@ -10,5 +17,5 @@
 
 void main() {
-  position_eye = vec3(view * vec4(vertex_position, 1.0));
+  position_eye = vec3(view * model_mats[ubo_index] * vec4(vertex_position, 1.0));
   texture_coordinates = vt;
 
Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision 9f9f9a7cc841cfce67bdaef5b74e8948bf835d81)
+++ new-game.cpp	(revision fd6f4653858e63f2de67d87f3a8ac9a5ca787745)
@@ -46,4 +46,17 @@
  *
  * NOTE: Asteroid movement currently depends on framerate, fix this in a generic/reusable way
+ */
+
+/* LASER POSITIONING ALGORITHM (to be implemented)
+ * -Determine the length of the laser based on the start and end points
+ * -Create a laser (long thin rectangle) of that length and the appropriate width
+ *  along the z axis, facing up, and with its start point at the origin (to make sure rotations happen around that point) 
+ * -Determine the line from the camera that intersects the line the laser should lie on at a 90 degree angle
+ * -The angle between that line and the laser's normal should be the angle needed to rotate the laser so it faces the camera
+ * -Now, create the transformation matrix for the laser to correctly position it
+ *   -First, rotate along the z axis by the angle calculated above
+ *   -Then, determine the correct angles and rotate around the y and x axes to make the laser point in the right direction
+ *   -Finally, translate the laser to its correct position by getting the difference between the camera position
+ *    and the laser start point
  */
 
@@ -125,5 +138,5 @@
 void calculateObjectBoundingBox(SceneObject& obj);
 
-void addLaserToScene(SceneObject& obj, vec3 start, vec3 end, vec3 color, GLfloat width);
+void addLaserToScene(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp);
 
 void initializeBuffers(
@@ -163,5 +176,5 @@
 void renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
-                  GLuint color_vao, GLuint texture_vao,
+                  GLuint color_vao, GLuint texture_vao, GLuint laser_vao,
                   GLuint colors_vbo, GLuint selected_colors_vbo,
                   SceneObject* selectedObject);
@@ -855,13 +868,6 @@
    addObjectToSceneDuringInit(obj);
 
-   obj = SceneObject();
-   obj.shader_program = laser_sp;
-
-   addLaserToScene(obj, vec3(0.34f, -2.0f, 1.6f), vec3(0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f);
-
-   obj = SceneObject();
-   obj.shader_program = laser_sp;
-
-   addLaserToScene(obj, vec3(-0.34f, -2.0f, 1.6f), vec3(-0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f);
+   addLaserToScene(vec3(0.34f, -2.0f, 1.6f), vec3(0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f, laser_sp);
+   addLaserToScene(vec3(-0.34f, -2.0f, 1.6f), vec3(-0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f, laser_sp);
 
    vector<SceneObject>::iterator obj_it;
@@ -928,4 +934,21 @@
    glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
 
+   GLuint laser_vao = 0;
+   glGenVertexArrays(1, &laser_vao);
+   glBindVertexArray(laser_vao);
+
+   glEnableVertexAttribArray(0);
+   glEnableVertexAttribArray(1);
+   glEnableVertexAttribArray(2);
+
+   glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+   glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
+   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+   glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
+   glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, 0, 0);
+
    float cam_speed = 1.0f;
    float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
@@ -965,4 +988,5 @@
    GLuint ub_binding_point = 0;
 
+   // TODO: Replace test_loc and mat_loc with more descriptive names
    GLuint view_test_loc = glGetUniformLocation(color_sp, "view");
    GLuint proj_test_loc = glGetUniformLocation(color_sp, "proj");
@@ -976,4 +1000,6 @@
    GLuint laser_proj_mat_loc = glGetUniformLocation(laser_sp, "proj");
    GLuint laser_color_loc = glGetUniformLocation(laser_sp, "laser_color");
+   GLuint laser_sp_ub_index = glGetUniformBlockIndex(laser_sp, "models");
+
 
    glUseProgram(color_sp);
@@ -983,4 +1009,5 @@
    glUniformBlockBinding(color_sp, color_sp_ub_index, ub_binding_point);
    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
+
 
    glUseProgram(texture_sp);
@@ -996,4 +1023,8 @@
    glUniformMatrix4fv(laser_proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
    glUniform3f(laser_color_loc, 0.2f, 1.0f, 0.2f);
+
+   glUniformBlockBinding(laser_sp, laser_sp_ub_index, ub_binding_point);
+   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
+
 
    bool cam_moved = false;
@@ -1203,5 +1234,5 @@
             renderScene(shaderBufferInfo,
                color_sp, texture_sp, laser_sp,
-               color_vao, texture_vao,
+               color_vao, texture_vao, laser_vao,
                colors_vbo, selected_colors_vbo,
                selectedObject);
@@ -1551,56 +1582,32 @@
 }
 
-// currently only works correctly for lasers oriented along the z axis
-void addLaserToScene(SceneObject& obj, vec3 start, vec3 end, vec3 color, GLfloat width) {
+void addLaserToScene(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp) {
+   SceneObject obj = SceneObject();
    obj.id = objects.size(); // currently unused
    obj.type = TYPE_LASER;
+   obj.shader_program = laser_sp;
    obj.deleted = false;
 
-   // I really need to create a direction vector and add/subtract that from start and end
-   // to get the right coords
-   // Also need to multiply the width times a vector perpendicular to it
-   vec3 dir = end - start;
+   float length = (end-start).length();
 
    obj.points = {
-      start.x + width / 2, start.y, start.z - width / 2,
-      start.x - width / 2, start.y, start.z - width / 2,
-      start.x - width / 2, start.y, start.z,
-      start.x + width / 2, start.y, start.z - width / 2,
-      start.x - width / 2, start.y, start.z,
-      start.x + width / 2, start.y, start.z,
-      end.x + width / 2,   end.y,   end.z + width / 2,
-      end.x - width / 2,   end.y,   end.z + width / 2,
-      start.x - width / 2, start.y, start.z - width / 2,
-      end.x + width / 2,   end.y,   end.z + width / 2,
-      start.x - width / 2, start.y, start.z - width / 2,
-      start.x + width / 2, start.y, start.z - width / 2,
-      end.x + width / 2,   end.y,   end.z,
-      end.x - width / 2,   end.y,   end.z,
-      end.x - width / 2,   end.y,   end.z + width / 2,
-      end.x + width / 2,   end.y,   end.z,
-      end.x - width / 2,   end.y,   end.z + width / 2,
-      end.x + width / 2,   end.y,   end.z + width / 2,
-   };
-
-   vec3 end_color = vec3(1.0f, 0.0f, 0.0f); // temporary
-   obj.colors = {
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      color.x, color.y, color.z,
-      color.x, color.y, color.z,
-      color.x, color.y, color.z,
-      color.x, color.y, color.z,
-      color.x, color.y, color.z,
-      color.x, color.y, color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
-      end_color.x, end_color.y, end_color.z,
+       width / 2, 0.0f, -width / 2,
+      -width / 2, 0.0f, -width / 2,
+      -width / 2, 0.0f, 0.0f,
+       width / 2, 0.0f, -width / 2,
+      -width / 2, 0.0f, 0.0f,
+       width / 2, 0.0f, 0.0f,
+       width / 2, 0.0f, -length + width / 2,
+      -width / 2, 0.0f, -length + width / 2,
+      -width / 2, 0.0f, -width / 2,
+       width / 2, 0.0f, -length + width / 2,
+      -width / 2, 0.0f, -width / 2,
+       width / 2, 0.0f, -width / 2,
+       width / 2, 0.0f, -length,
+      -width / 2, 0.0f, -length,
+      -width / 2, 0.0f, -length + width / 2,
+       width / 2, 0.0f, -length,
+      -width / 2, 0.0f, -length + width / 2,
+       width / 2, 0.0f, -length + width / 2,
    };
 
@@ -1627,4 +1634,6 @@
 
    obj.num_points = obj.points.size() / 3;
+   obj.model_base = translate(mat4(1.0f), start);
+   obj.model_transform = mat4(1.0f);
 
    objects.push_back(obj);
@@ -1796,29 +1805,26 @@
    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, 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, 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);
+   }
 
    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, 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, 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_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));
-   }
+   }
+
+   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));
 
    bufferInfo->vbo_offset += obj.num_points;
@@ -1838,5 +1844,5 @@
 void renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
-                  GLuint color_vao, GLuint texture_vao,
+                  GLuint color_vao, GLuint texture_vao, GLuint laser_vao,
                   GLuint colors_vbo, GLuint selected_colors_vbo,
                   SceneObject* selectedObject) {
@@ -1865,5 +1871,5 @@
 
    glUseProgram(laser_sp);
-   glBindVertexArray(texture_vao);
+   glBindVertexArray(laser_vao);
 
    glDrawArrays(GL_TRIANGLES, shaderBufferInfo[laser_sp].vbo_base, shaderBufferInfo[laser_sp].vbo_offset);
