Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision fabed35a3b55b12b0f68d21d134322aa46d18f01)
+++ new-game.cpp	(revision 612d1f6169693232d03c30388f8a5c8f88f1e010)
@@ -145,4 +145,6 @@
 void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
 
+void translateLaser(SceneObject& laser, const vec3& translation, GLuint ubo);
+
 void renderMainMenu();
 void renderMainMenuGui();
@@ -213,5 +215,4 @@
 
 /*
-* TODO: Make lasers shoot from the ends of the ship's wings when the user presses a button and disappear after a second or so
 * TODO: Asteroid movement currently depends on framerate, fix this in a generic/reusable way
 */
@@ -1041,10 +1042,9 @@
             transformObject(objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
 
-            // TODO: Update the rotation of the lasers as they moves so they point towards the camera
             if (leftLaserIdx != -1) {
-               transformObject(objects[leftLaserIdx], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
+               translateLaser(objects[leftLaserIdx], vec3(0.01f, 0.0f, 0.0f), ubo);
             }
             if (rightLaserIdx != -1) {
-               transformObject(objects[rightLaserIdx], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
+               translateLaser(objects[rightLaserIdx], vec3(0.01f, 0.0f, 0.0f), ubo);
             }
          }
@@ -1052,10 +1052,9 @@
             transformObject(objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
 
-            // TODO: Update the rotation of the lasers as they moves so they point towards the camera
             if (leftLaserIdx != -1) {
-               transformObject(objects[leftLaserIdx], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
+               translateLaser(objects[leftLaserIdx], vec3(-0.01f, 0.0f, 0.0f), ubo);
             }
             if (rightLaserIdx != -1) {
-               transformObject(objects[rightLaserIdx], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
+               translateLaser(objects[rightLaserIdx], vec3(-0.01f, 0.0f, 0.0f), ubo);
             }
          }
@@ -1630,11 +1629,11 @@
    float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
 
-   obj.model_base = mat4(1.0f);
-   obj.model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f)) * obj.model_base;
-   obj.model_base = rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) * obj.model_base;
-   obj.model_base = rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) * obj.model_base;
-   obj.model_base = translate(mat4(1.0f), start) * obj.model_base;
+   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;
 
    return obj;
@@ -1857,4 +1856,37 @@
 }
 
+void translateLaser(SceneObject& laser, const vec3& translation, GLuint ubo) {
+   if (laser.deleted) return;
+
+   // TODO: A lot of the values I calculate 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[2] + laser.points[20], 1.0f));
+
+   vec3 ray = end - start;
+   float length = glm::length(ray);
+
+   float xAxisRotation = asin(ray.y / length);
+   float yAxisRotation = atan2(-ray.x, -ray.z);
+
+   vec3 normal(rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) *
+      rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) *
+      vec4(0.0f, 1.0f, 0.0f, 1.0f));
+
+   // To project point P onto line AB:
+   // projection = A + dot(AP,AB) / dot(AB,AB) * AB
+   vec3 projOnLaser = start + glm::dot(cam_pos - start, ray) / (length*length) * ray;
+   vec3 laserToCam = cam_pos - projOnLaser;
+
+   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 renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
                   GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
