| [22b2c37] | 1 | #include "logger.h"
 | 
|---|
| [5272b6b] | 2 | 
 | 
|---|
| [485424b] | 3 | #include "stb_image.h"
 | 
|---|
 | 4 | 
 | 
|---|
| [4e0b82b] | 5 | // I think this was for the OpenGL 4 book font file tutorial
 | 
|---|
 | 6 | //#define STB_IMAGE_WRITE_IMPLEMENTATION
 | 
|---|
 | 7 | //#include "stb_image_write.h"
 | 
|---|
 | 8 | 
 | 
|---|
| [1099b95] | 9 | #define _USE_MATH_DEFINES
 | 
|---|
| [5c9d193] | 10 | 
 | 
|---|
| [c62eee6] | 11 | #include <glm/mat4x4.hpp>
 | 
|---|
| [7ee66ea] | 12 | #include <glm/gtc/matrix_transform.hpp>
 | 
|---|
 | 13 | #include <glm/gtc/type_ptr.hpp>
 | 
|---|
 | 14 | 
 | 
|---|
| [c1ca5b5] | 15 | #include "IMGUI/imgui.h"
 | 
|---|
 | 16 | #include "imgui_impl_glfw_gl3.h"
 | 
|---|
 | 17 | 
 | 
|---|
| [5272b6b] | 18 | #include <GL/glew.h>
 | 
|---|
 | 19 | #include <GLFW/glfw3.h>
 | 
|---|
 | 20 | 
 | 
|---|
| [22b2c37] | 21 | #include <cstdio>
 | 
|---|
| [5527206] | 22 | #include <cstdlib>
 | 
|---|
 | 23 | #include <ctime>
 | 
|---|
| [22b2c37] | 24 | #include <iostream>
 | 
|---|
| [ec4456b] | 25 | #include <fstream>
 | 
|---|
| [1f3d32b] | 26 | #include <sstream>
 | 
|---|
| [93baa0e] | 27 | #include <cmath>
 | 
|---|
| [1099b95] | 28 | #include <string>
 | 
|---|
| [19c9338] | 29 | #include <array>
 | 
|---|
| [df652d5] | 30 | #include <vector>
 | 
|---|
| [93462c6] | 31 | #include <queue>
 | 
|---|
| [0d5c100] | 32 | #include <map>
 | 
|---|
| [22b2c37] | 33 | 
 | 
|---|
| [7e10667] | 34 | #include "utils.h"
 | 
|---|
 | 35 | 
 | 
|---|
| [5272b6b] | 36 | using namespace std;
 | 
|---|
| [7ee66ea] | 37 | using namespace glm;
 | 
|---|
 | 38 | 
 | 
|---|
| [92b1e90] | 39 | enum State {
 | 
|---|
 | 40 |    STATE_MAIN_MENU,
 | 
|---|
 | 41 |    STATE_GAME,
 | 
|---|
 | 42 | };
 | 
|---|
 | 43 | 
 | 
|---|
 | 44 | enum Event {
 | 
|---|
 | 45 |    EVENT_GO_TO_MAIN_MENU,
 | 
|---|
 | 46 |    EVENT_GO_TO_GAME,
 | 
|---|
 | 47 |    EVENT_QUIT,
 | 
|---|
 | 48 | };
 | 
|---|
 | 49 | 
 | 
|---|
 | 50 | enum ObjectType {
 | 
|---|
 | 51 |    TYPE_SHIP,
 | 
|---|
 | 52 |    TYPE_ASTEROID,
 | 
|---|
 | 53 |    TYPE_LASER,
 | 
|---|
| [646f3f2] | 54 |    TYPE_EXPLOSION,
 | 
|---|
| [92b1e90] | 55 | };
 | 
|---|
 | 56 | 
 | 
|---|
| [a0eb547] | 57 | enum AttribType {
 | 
|---|
 | 58 |    ATTRIB_UNIFORM,
 | 
|---|
 | 59 |    ATTRIB_OBJECT_VARYING,
 | 
|---|
 | 60 |    ATTRIB_POINT_VARYING,
 | 
|---|
 | 61 | };
 | 
|---|
 | 62 | 
 | 
|---|
| [49db5fc] | 63 | // Add more types as I need them
 | 
|---|
 | 64 | enum UniformType {
 | 
|---|
 | 65 |    UNIFORM_NONE,
 | 
|---|
 | 66 |    UNIFORM_MATRIX_4F,
 | 
|---|
 | 67 |    UNIFORM_1F,
 | 
|---|
 | 68 |    UNIFORM_3F,
 | 
|---|
 | 69 | };
 | 
|---|
 | 70 | 
 | 
|---|
| [c4c205e] | 71 | enum UIValueType {
 | 
|---|
 | 72 |    UIVALUE_INT,
 | 
|---|
 | 73 |    UIVALUE_DOUBLE,
 | 
|---|
 | 74 | };
 | 
|---|
 | 75 | 
 | 
|---|
| [df652d5] | 76 | struct SceneObject {
 | 
|---|
| [d9f99b2] | 77 |    unsigned int id;
 | 
|---|
| [92b1e90] | 78 |    ObjectType type;
 | 
|---|
| [7e10667] | 79 |    bool deleted;
 | 
|---|
| [95595de] | 80 | 
 | 
|---|
 | 81 |    // Currently, model_transform should only have translate, and rotation and scale need to be done in model_base since
 | 
|---|
 | 82 |    // they need to be done when the object is at the origin. I should change this to have separate scale, rotate, and translate
 | 
|---|
 | 83 |    // matrices for each object that can be updated independently and then applied to the object in that order.
 | 
|---|
| [4c7cd57] | 84 |    // TODO: Actually, to make this as generic as possible, each object should have a matrix stack to support,
 | 
|---|
 | 85 |    // for instance, applying a rotate, then a translate, then another rotate. Think about and implement the best approach.
 | 
|---|
| [5c403fe] | 86 |    mat4 model_mat, model_base, model_transform;
 | 
|---|
| [95595de] | 87 |    mat4 translate_mat; // beginning of doing what's mentioned above
 | 
|---|
| [05e43cf] | 88 |    unsigned int num_points;
 | 
|---|
| [c3c3158] | 89 |    GLuint vertex_vbo_offset;
 | 
|---|
 | 90 |    GLuint ubo_offset;
 | 
|---|
| [07ed460] | 91 |    vector<GLfloat> points;
 | 
|---|
 | 92 |    vector<GLfloat> colors;
 | 
|---|
 | 93 |    vector<GLfloat> texcoords;
 | 
|---|
| [9dd2eb7] | 94 |    vector<GLfloat> normals;
 | 
|---|
| [3d06b4e] | 95 |    vec3 bounding_center;
 | 
|---|
 | 96 |    GLfloat bounding_radius;
 | 
|---|
| [c3c3158] | 97 | };
 | 
|---|
 | 98 | 
 | 
|---|
| [1f3d32b] | 99 | struct Asteroid : SceneObject {
 | 
|---|
| [0e0f851] | 100 |    float hp;
 | 
|---|
| [1f3d32b] | 101 | };
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 | struct Laser : SceneObject {
 | 
|---|
 | 104 |    Asteroid* targetAsteroid;
 | 
|---|
 | 105 | };
 | 
|---|
 | 106 | 
 | 
|---|
| [dc19a39] | 107 | struct ParticleEffect : SceneObject {
 | 
|---|
 | 108 |    vector<GLfloat> particleVelocities;
 | 
|---|
 | 109 |    vector<GLfloat> particleTimes;
 | 
|---|
| [7e10667] | 110 |    GLfloat startTime;
 | 
|---|
 | 111 |    GLfloat duration;
 | 
|---|
| [dc19a39] | 112 | };
 | 
|---|
 | 113 | 
 | 
|---|
| [1f3d32b] | 114 | struct EffectOverTime {
 | 
|---|
| [0e0f851] | 115 |    float& effectedValue;
 | 
|---|
 | 116 |    float startValue;
 | 
|---|
| [1f3d32b] | 117 |    double startTime;
 | 
|---|
| [0e0f851] | 118 |    float changePerSecond;
 | 
|---|
| [1f3d32b] | 119 |    bool deleted;
 | 
|---|
 | 120 |    SceneObject* effectedObject;
 | 
|---|
 | 121 | 
 | 
|---|
| [39ac76d] | 122 |    // TODO: Why not just use an initializer list for all the instance variables
 | 
|---|
| [b220f78] | 123 |    // TODO: Maybe pass in startTime instead of calling glfwGetTime() here
 | 
|---|
| [0e0f851] | 124 |    EffectOverTime(float& effectedValue, float changePerSecond, SceneObject* object)
 | 
|---|
 | 125 |       : effectedValue(effectedValue), changePerSecond(changePerSecond), effectedObject(object) {
 | 
|---|
| [1f3d32b] | 126 |       startValue = effectedValue;
 | 
|---|
 | 127 |       startTime = glfwGetTime();
 | 
|---|
 | 128 |       deleted = false;
 | 
|---|
 | 129 |    }
 | 
|---|
 | 130 | };
 | 
|---|
 | 131 | 
 | 
|---|
| [c3c3158] | 132 | struct BufferInfo {
 | 
|---|
 | 133 |    unsigned int ubo_base;
 | 
|---|
 | 134 |    unsigned int ubo_offset;
 | 
|---|
 | 135 |    unsigned int ubo_capacity;
 | 
|---|
| [df652d5] | 136 | };
 | 
|---|
 | 137 | 
 | 
|---|
| [a0eb547] | 138 | struct AttribInfo {
 | 
|---|
 | 139 |    AttribType attribType;
 | 
|---|
 | 140 |    GLuint index;
 | 
|---|
 | 141 |    GLint size;
 | 
|---|
 | 142 |    GLenum type;
 | 
|---|
| [49db5fc] | 143 |    UniformType uniType;
 | 
|---|
 | 144 |    GLuint buffer; // For uniforms, this is the uniform location
 | 
|---|
| [a0eb547] | 145 |    size_t fieldOffset;
 | 
|---|
| [49db5fc] | 146 |    GLfloat* data; // pointer to data source for uniform attributes
 | 
|---|
| [a0eb547] | 147 | };
 | 
|---|
 | 148 | 
 | 
|---|
| [7a55b49] | 149 | struct ShaderModelGroup {
 | 
|---|
 | 150 |    GLuint shaderProgram;
 | 
|---|
 | 151 |    GLuint vao;
 | 
|---|
| [a0eb547] | 152 |    map<string, AttribInfo> attribs;
 | 
|---|
| [7a55b49] | 153 |    unsigned int numPoints;
 | 
|---|
| [a0eb547] | 154 |    unsigned int vboCapacity;
 | 
|---|
| [7a55b49] | 155 | };
 | 
|---|
 | 156 | 
 | 
|---|
| [c4c205e] | 157 | struct UIValue {
 | 
|---|
 | 158 |    UIValueType type;
 | 
|---|
 | 159 |    string label;
 | 
|---|
 | 160 |    void* value;
 | 
|---|
 | 161 | 
 | 
|---|
 | 162 |    UIValue(UIValueType _type, string _label, void* _value) : type(_type), label(_label), value(_value) {}
 | 
|---|
 | 163 | };
 | 
|---|
 | 164 | 
 | 
|---|
| [4f3262f] | 165 | void glfw_error_callback(int error, const char* description);
 | 
|---|
 | 166 | 
 | 
|---|
 | 167 | void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
 | 
|---|
| [f7d35da] | 168 | void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
 | 
|---|
| [e6bc0f4] | 169 | void window_size_callback(GLFWwindow* window, int width, int height);
 | 
|---|
| [4f3262f] | 170 | 
 | 
|---|
| [0e0f851] | 171 | void APIENTRY debugGlCallback(
 | 
|---|
 | 172 |    GLenum source,
 | 
|---|
 | 173 |    GLenum type,
 | 
|---|
 | 174 |    GLuint id,
 | 
|---|
 | 175 |    GLenum severity,
 | 
|---|
 | 176 |    GLsizei length,
 | 
|---|
 | 177 |    const GLchar* message,
 | 
|---|
 | 178 |    const void* userParam
 | 
|---|
 | 179 | );
 | 
|---|
 | 180 | 
 | 
|---|
| [d9f99b2] | 181 | bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point);
 | 
|---|
| [5c9d193] | 182 | bool insideTriangle(vec3 p, array<vec3, 3> triangle_points);
 | 
|---|
| [33a9664] | 183 | 
 | 
|---|
| [ec4456b] | 184 | GLuint loadShader(GLenum type, string file);
 | 
|---|
| [485424b] | 185 | GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath);
 | 
|---|
 | 186 | unsigned char* loadImage(string file_name, int* x, int* y);
 | 
|---|
| [ec4456b] | 187 | 
 | 
|---|
| [7e10667] | 188 | void printVec3(string label, const vec3& v);
 | 
|---|
 | 189 | void printVec4(string label, const vec4& v);
 | 
|---|
 | 190 | void printMat4(string label, const mat4& m);
 | 
|---|
| [d12d003] | 191 | 
 | 
|---|
| [1f3d32b] | 192 | void initObject(SceneObject* obj);
 | 
|---|
 | 193 | void addObjectToScene(SceneObject* obj,
 | 
|---|
| [8316333] | 194 |                   map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 195 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [f97e638] | 196 |                   GLuint ubo);
 | 
|---|
| [95595de] | 197 | void removeObjectFromScene(SceneObject& obj, GLuint ubo);
 | 
|---|
| [c3c3158] | 198 | 
 | 
|---|
| [7a55b49] | 199 | ShaderModelGroup createModelGroup(GLuint shaderProgram);
 | 
|---|
 | 200 | void removeModelFromGroup(ShaderModelGroup& modelGroup, SceneObject& model);
 | 
|---|
 | 201 | void addModelToGroup(ShaderModelGroup& modelGroup, SceneObject& model);
 | 
|---|
 | 202 | 
 | 
|---|
| [a0eb547] | 203 | void defineModelGroupAttrib(ShaderModelGroup& modelGroup, string name, AttribType attribType, GLint size, GLenum type, size_t fieldOffset);
 | 
|---|
| [49db5fc] | 204 | void defineModelGroupUniform(ShaderModelGroup& modelGroup, string name, AttribType attribType, GLint size, UniformType type, GLfloat* data);
 | 
|---|
| [a0eb547] | 205 | void initModelGroupAttribs(ShaderModelGroup& modelGroup);
 | 
|---|
| [49db5fc] | 206 | void bindUniformData(AttribInfo& attrib);
 | 
|---|
| [b220f78] | 207 | void bindUniformData(AttribInfo& attrib, GLfloat* data);
 | 
|---|
| [a0eb547] | 208 | 
 | 
|---|
 | 209 | size_t GLsizeof(GLenum);
 | 
|---|
 | 210 | GLvoid* getVectorAttribPtr(SceneObject& obj, size_t attribOffset);
 | 
|---|
 | 211 | GLvoid* getScalarAttribPtr(SceneObject& obj, size_t attribOffset);
 | 
|---|
 | 212 | 
 | 
|---|
| [1f3d32b] | 213 | void calculateObjectBoundingBox(SceneObject* obj);
 | 
|---|
| [b155f13] | 214 | 
 | 
|---|
| [dc19a39] | 215 | void initializeParticleEffectBuffers(map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 216 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [f97e638] | 217 |                   GLuint ubo);
 | 
|---|
| [db06984] | 218 | 
 | 
|---|
| [1f3d32b] | 219 | void populateBuffers(vector<SceneObject*>& objects,
 | 
|---|
| [c3c3158] | 220 |                   map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 221 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [f97e638] | 222 |                   GLuint ubo);
 | 
|---|
| [c3c3158] | 223 | 
 | 
|---|
 | 224 | void copyObjectDataToBuffers(SceneObject& obj,
 | 
|---|
 | 225 |                   map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 226 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [49db5fc] | 227 |                   GLuint ubo);
 | 
|---|
| [f9a242b] | 228 | 
 | 
|---|
| [5c403fe] | 229 | void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
 | 
|---|
 | 230 | 
 | 
|---|
| [646f3f2] | 231 | // TODO: instead of using these methods, create constructors for these
 | 
|---|
| [dd9771c] | 232 | SceneObject* createShip();
 | 
|---|
 | 233 | Asteroid* createAsteroid(vec3 pos);
 | 
|---|
 | 234 | Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width);
 | 
|---|
| [7e10667] | 235 | ParticleEffect* createExplosion(mat4 model_mat);
 | 
|---|
| [1f3d32b] | 236 | 
 | 
|---|
 | 237 | void translateLaser(Laser* laser, const vec3& translation, GLuint ubo);
 | 
|---|
| [a0eb547] | 238 | void updateLaserTarget(Laser* laser, vector<SceneObject*>& objects, ShaderModelGroup& laserSmg, GLuint asteroid_sp);
 | 
|---|
| [e9347b4] | 239 | bool getLaserAndAsteroidIntersection(vec3& start, vec3& end, SceneObject& asteroid, vec3& intersection);
 | 
|---|
| [612d1f6] | 240 | 
 | 
|---|
| [93462c6] | 241 | void renderMainMenu();
 | 
|---|
 | 242 | void renderMainMenuGui();
 | 
|---|
 | 243 | 
 | 
|---|
| [7e10667] | 244 | void renderScene(map<ObjectType, ShaderModelGroup>& modelGroups, GLuint ubo);
 | 
|---|
| [c4c205e] | 245 | void renderSceneGui(map<string, vector<UIValue>> valueLists);
 | 
|---|
 | 246 | 
 | 
|---|
| [a9d191a] | 247 | void initGuiValueLists(map<string, vector<UIValue>> valueLists);
 | 
|---|
| [c4c205e] | 248 | void renderGuiValueList(vector<UIValue>& values);
 | 
|---|
| [d12d003] | 249 | 
 | 
|---|
| [5527206] | 250 | float getRandomNum(float low, float high);
 | 
|---|
 | 251 | 
 | 
|---|
 | 252 | #define NUM_KEYS (512)
 | 
|---|
 | 253 | #define ONE_DEG_IN_RAD ((2.0f * M_PI) / 360.0f) // 0.017444444 (maybe make this a const instead)
 | 
|---|
| [8fbd34f] | 254 | #define TARGET_FPS 60.0f
 | 
|---|
| [5527206] | 255 | 
 | 
|---|
 | 256 | const int KEY_STATE_UNCHANGED = -1;
 | 
|---|
 | 257 | const bool FULLSCREEN = false;
 | 
|---|
| [db06984] | 258 | const int EXPLOSION_PARTICLE_COUNT = 300;
 | 
|---|
| [5527206] | 259 | unsigned int MAX_UNIFORMS = 0; // Requires OpenGL constants only available at runtime, so it can't be const
 | 
|---|
 | 260 | 
 | 
|---|
 | 261 | int key_state[NUM_KEYS];
 | 
|---|
| [fabed35] | 262 | bool key_down[NUM_KEYS];
 | 
|---|
| [5527206] | 263 | 
 | 
|---|
| [e6bc0f4] | 264 | int windowWidth = 640;
 | 
|---|
 | 265 | int windowHeight = 480;
 | 
|---|
| [5527206] | 266 | 
 | 
|---|
 | 267 | vec3 cam_pos;
 | 
|---|
 | 268 | 
 | 
|---|
 | 269 | mat4 view_mat;
 | 
|---|
 | 270 | mat4 proj_mat;
 | 
|---|
 | 271 | 
 | 
|---|
| [1f3d32b] | 272 | vector<SceneObject*> objects;
 | 
|---|
| [5527206] | 273 | queue<Event> events;
 | 
|---|
| [1f3d32b] | 274 | vector<EffectOverTime*> effects;
 | 
|---|
| [5527206] | 275 | 
 | 
|---|
 | 276 | SceneObject* clickedObject = NULL;
 | 
|---|
 | 277 | SceneObject* selectedObject = NULL;
 | 
|---|
 | 278 | 
 | 
|---|
 | 279 | float NEAR_CLIP = 0.1f;
 | 
|---|
 | 280 | float FAR_CLIP = 100.0f;
 | 
|---|
 | 281 | 
 | 
|---|
| [95595de] | 282 | // TODO: Should really have some array or struct of UI-related variables
 | 
|---|
| [5527206] | 283 | bool isRunning = true;
 | 
|---|
 | 284 | 
 | 
|---|
 | 285 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
 | 
|---|
 | 286 | 
 | 
|---|
| [1f3d32b] | 287 | Laser* leftLaser = NULL;
 | 
|---|
 | 288 | EffectOverTime* leftLaserEffect = NULL;
 | 
|---|
 | 289 | 
 | 
|---|
 | 290 | Laser* rightLaser = NULL;
 | 
|---|
 | 291 | EffectOverTime* rightLaserEffect = NULL;
 | 
|---|
| [fabed35] | 292 | 
 | 
|---|
| [a9d191a] | 293 | map<string, vector<UIValue>> valueLists;
 | 
|---|
 | 294 | 
 | 
|---|
| [3effd81] | 295 | /*
 | 
|---|
| [e9347b4] | 296 | * TODO: Asteroid and ship movement currently depend on framerate, fix this in a generic/reusable way
 | 
|---|
 | 297 | * Disabling vsync is a great way to test this
 | 
|---|
| [3effd81] | 298 | */
 | 
|---|
 | 299 | 
 | 
|---|
| [c1ca5b5] | 300 | int main(int argc, char* argv[]) {
 | 
|---|
| [5272b6b] | 301 |    cout << "New OpenGL Game" << endl;
 | 
|---|
 | 302 | 
 | 
|---|
| [bae0911] | 303 |    restart_gl_log();
 | 
|---|
 | 304 |    gl_log("starting GLFW\n%s", glfwGetVersionString());
 | 
|---|
| [22b2c37] | 305 | 
 | 
|---|
| [ec4456b] | 306 |    glfwSetErrorCallback(glfw_error_callback);
 | 
|---|
| [5272b6b] | 307 |    if (!glfwInit()) {
 | 
|---|
| [bae0911] | 308 |       gl_log_err("ERROR: could not start GLFW3");
 | 
|---|
| [5272b6b] | 309 |       return 1;
 | 
|---|
| [be246ad] | 310 |    }
 | 
|---|
 | 311 | 
 | 
|---|
 | 312 | #ifdef __APPLE__
 | 
|---|
 | 313 |    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 | 
|---|
 | 314 |    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 | 
|---|
 | 315 |    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
 | 
|---|
 | 316 |    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 | 
|---|
| [446e55d] | 317 | #else
 | 
|---|
 | 318 |    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
 | 
|---|
 | 319 |    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 | 
|---|
| [be246ad] | 320 | #endif
 | 
|---|
| [5272b6b] | 321 | 
 | 
|---|
| [ec4456b] | 322 |    GLFWwindow* window = NULL;
 | 
|---|
| [e856d62] | 323 |    GLFWmonitor* mon = NULL;
 | 
|---|
| [ec4456b] | 324 | 
 | 
|---|
| [0e0f851] | 325 |    glfwWindowHint(GLFW_SAMPLES, 16);
 | 
|---|
 | 326 |    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);
 | 
|---|
 | 327 | 
 | 
|---|
| [ec4456b] | 328 |    if (FULLSCREEN) {
 | 
|---|
| [e856d62] | 329 |       mon = glfwGetPrimaryMonitor();
 | 
|---|
| [ec4456b] | 330 |       const GLFWvidmode* vmode = glfwGetVideoMode(mon);
 | 
|---|
 | 331 | 
 | 
|---|
| [e6bc0f4] | 332 |       windowWidth = vmode->width;
 | 
|---|
 | 333 |       windowHeight = vmode->height;
 | 
|---|
| [e856d62] | 334 |       cout << "Fullscreen resolution " << vmode->width << "x" << vmode->height << endl;
 | 
|---|
| [ec4456b] | 335 |    }
 | 
|---|
| [e6bc0f4] | 336 |    window = glfwCreateWindow(windowWidth, windowHeight, "New OpenGL Game", mon, NULL);
 | 
|---|
| [ec4456b] | 337 | 
 | 
|---|
| [5272b6b] | 338 |    if (!window) {
 | 
|---|
| [bae0911] | 339 |       gl_log_err("ERROR: could not open window with GLFW3");
 | 
|---|
| [5272b6b] | 340 |       glfwTerminate();
 | 
|---|
 | 341 |       return 1;
 | 
|---|
 | 342 |    }
 | 
|---|
| [c62eee6] | 343 | 
 | 
|---|
| [644a2e4] | 344 |    glfwMakeContextCurrent(window);
 | 
|---|
| [e6bc0f4] | 345 |    glViewport(0, 0, windowWidth, windowHeight);
 | 
|---|
 | 346 | 
 | 
|---|
| [5272b6b] | 347 |    glewExperimental = GL_TRUE;
 | 
|---|
 | 348 |    glewInit();
 | 
|---|
 | 349 | 
 | 
|---|
| [0e0f851] | 350 |    if (GLEW_KHR_debug) {
 | 
|---|
 | 351 |       cout << "FOUND GLEW debug extension" << endl;
 | 
|---|
 | 352 |       glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
 | 
|---|
 | 353 |       glDebugMessageCallback((GLDEBUGPROC)debugGlCallback, nullptr);
 | 
|---|
 | 354 |       cout << "Bound debug callback" << endl;
 | 
|---|
| [446e55d] | 355 |    } else {
 | 
|---|
| [e6bc0f4] | 356 |       cout << "OpenGL debug message callback is not supported" << endl;
 | 
|---|
| [0e0f851] | 357 |    }
 | 
|---|
 | 358 | 
 | 
|---|
| [5527206] | 359 |    srand(time(0));
 | 
|---|
 | 360 | 
 | 
|---|
| [14ff67c] | 361 |    /*
 | 
|---|
 | 362 |    * RENDERING ALGORITHM NOTES:
 | 
|---|
 | 363 |    *
 | 
|---|
 | 364 |    * Basically, I need to split my objects into groups, so that each group fits into
 | 
|---|
 | 365 |    * GL_MAX_UNIFORM_BLOCK_SIZE. I need to have an offset and a size for each group.
 | 
|---|
 | 366 |    * Getting the offset is straitforward. The size may as well be GL_MAX_UNIFORM_BLOCK_SIZE
 | 
|---|
 | 367 |    * for each group, since it seems that smaller sizes just round up to the nearest GL_MAX_UNIFORM_BLOCK_SIZE
 | 
|---|
 | 368 |    *
 | 
|---|
 | 369 |    * I'll need to have a loop inside my render loop that calls glBindBufferRange(GL_UNIFORM_BUFFER, ...
 | 
|---|
 | 370 |    * for every 1024 objects and then draws all those objects with one glDraw call.
 | 
|---|
 | 371 |    *
 | 
|---|
| [0d5c100] | 372 |    * Since I currently have very few objects, I'll wait to implement this  until I have
 | 
|---|
 | 373 |    * a reasonable number of objects always using the same shader.
 | 
|---|
| [14ff67c] | 374 |    */
 | 
|---|
 | 375 | 
 | 
|---|
 | 376 |    GLint UNIFORM_BUFFER_OFFSET_ALIGNMENT, MAX_UNIFORM_BLOCK_SIZE;
 | 
|---|
 | 377 |    glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &UNIFORM_BUFFER_OFFSET_ALIGNMENT);
 | 
|---|
 | 378 |    glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &MAX_UNIFORM_BLOCK_SIZE);
 | 
|---|
 | 379 | 
 | 
|---|
 | 380 |    MAX_UNIFORMS = MAX_UNIFORM_BLOCK_SIZE / sizeof(mat4);
 | 
|---|
 | 381 | 
 | 
|---|
 | 382 |    cout << "UNIFORM_BUFFER_OFFSET_ALIGNMENT: " << UNIFORM_BUFFER_OFFSET_ALIGNMENT << endl;
 | 
|---|
 | 383 |    cout << "MAX_UNIFORMS: " << MAX_UNIFORMS << endl;
 | 
|---|
 | 384 | 
 | 
|---|
| [c1ca5b5] | 385 |    // Setup Dear ImGui binding
 | 
|---|
 | 386 |    IMGUI_CHECKVERSION();
 | 
|---|
 | 387 |    ImGui::CreateContext();
 | 
|---|
 | 388 |    ImGuiIO& io = ImGui::GetIO(); (void)io;
 | 
|---|
 | 389 |    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls
 | 
|---|
 | 390 |    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;   // Enable Gamepad Controls
 | 
|---|
 | 391 |    ImGui_ImplGlfwGL3_Init(window, true);
 | 
|---|
 | 392 | 
 | 
|---|
 | 393 |    // Setup style
 | 
|---|
 | 394 |    ImGui::StyleColorsDark();
 | 
|---|
 | 395 |    //ImGui::StyleColorsClassic();
 | 
|---|
 | 396 | 
 | 
|---|
 | 397 |    glfwSetMouseButtonCallback(window, mouse_button_callback);
 | 
|---|
| [f7d35da] | 398 |    glfwSetKeyCallback(window, key_callback);
 | 
|---|
| [c1ca5b5] | 399 | 
 | 
|---|
| [e6bc0f4] | 400 |    glfwSetWindowSizeCallback(window, window_size_callback);
 | 
|---|
 | 401 | 
 | 
|---|
| [5272b6b] | 402 |    const GLubyte* renderer = glGetString(GL_RENDERER);
 | 
|---|
 | 403 |    const GLubyte* version = glGetString(GL_VERSION);
 | 
|---|
| [0e0f851] | 404 |    cout << "Renderer: " << renderer << endl;
 | 
|---|
| [bae0911] | 405 |    cout << "Supported OpenGL version: " << version << endl;
 | 
|---|
 | 406 | 
 | 
|---|
 | 407 |    gl_log("Renderer: %s", renderer);
 | 
|---|
 | 408 |    gl_log("Supported OpenGL version: %s", version);
 | 
|---|
| [93baa0e] | 409 | 
 | 
|---|
| [9f9f9a7] | 410 |    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 | 
|---|
 | 411 | 
 | 
|---|
| [5272b6b] | 412 |    glEnable(GL_DEPTH_TEST);
 | 
|---|
 | 413 |    glDepthFunc(GL_LESS);
 | 
|---|
| [516668e] | 414 | 
 | 
|---|
| [93baa0e] | 415 |    glEnable(GL_CULL_FACE);
 | 
|---|
 | 416 |    // glCullFace(GL_BACK);
 | 
|---|
 | 417 |    // glFrontFace(GL_CW);
 | 
|---|
 | 418 | 
 | 
|---|
| [9f9f9a7] | 419 |    int x, y;
 | 
|---|
 | 420 |    unsigned char* texImage = loadImage("laser.png", &x, &y);
 | 
|---|
 | 421 |    if (texImage) {
 | 
|---|
 | 422 |       cout << "Laser texture loaded successfully!" << endl;
 | 
|---|
| [155a7cf] | 423 |       cout << x << ", " << y << endl;
 | 
|---|
 | 424 |       cout << "first 4 bytes are: " << texImage[0] << " " << texImage[1] << " " << texImage[2] << " " << texImage[3] << endl;
 | 
|---|
| [9f9f9a7] | 425 |    }
 | 
|---|
 | 426 | 
 | 
|---|
 | 427 |    GLuint laserTex = 0;
 | 
|---|
 | 428 |    glGenTextures(1, &laserTex);
 | 
|---|
| [485424b] | 429 |    glActiveTexture(GL_TEXTURE0);
 | 
|---|
| [9f9f9a7] | 430 |    glBindTexture(GL_TEXTURE_2D, laserTex);
 | 
|---|
| [485424b] | 431 |    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);
 | 
|---|
 | 432 | 
 | 
|---|
 | 433 |    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
|---|
 | 434 |    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
|---|
 | 435 |    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
|---|
 | 436 |    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
|---|
 | 437 | 
 | 
|---|
| [0d5c100] | 438 |    /* RENDERING ALGORITHM
 | 
|---|
 | 439 |     * 
 | 
|---|
 | 440 |     * Create a separate vbo for each of the following things:
 | 
|---|
 | 441 |     * - points
 | 
|---|
 | 442 |     * - colors
 | 
|---|
 | 443 |     * - texture coordinates
 | 
|---|
 | 444 |     * - selected colors
 | 
|---|
 | 445 |     * - normals
 | 
|---|
 | 446 |     * - indices into a ubo that stores a model matrix for each object
 | 
|---|
 | 447 |     *
 | 
|---|
 | 448 |     * Also, make a model matrix ubo, the entirety of which will be passed to the vertex shader.
 | 
|---|
 | 449 |     * The vbo containing the correct index into the ubo (mentioned above) will be used to select
 | 
|---|
 | 450 |     * the right model matrix for each point. The index in the vbo will be the saem for all points
 | 
|---|
 | 451 |     * of any given object.
 | 
|---|
 | 452 |     *
 | 
|---|
 | 453 |     * Right now, the currently selected object is drawn using one color (specified in the selected
 | 
|---|
 | 454 |     * colors vbo) regardless of whether it is normally rendering using colors or a texture. The selected
 | 
|---|
 | 455 |     * object is rendering by binding the selected colors vbo in place of the colors vbo and using the colors
 | 
|---|
 | 456 |     * shader. Then, the selected object is redrawn along with all other objects, but the depth buffer test
 | 
|---|
 | 457 |     * prevents the unselected version of the object from appearing on the screen. This lets me render all the
 | 
|---|
 | 458 |     * objects that use a particular shader using one glDrawArrays() call.
 | 
|---|
 | 459 |     */
 | 
|---|
| [cffca4d] | 460 | 
 | 
|---|
| [49db5fc] | 461 |    GLfloat laserColor[3] = {0.2f, 1.0f, 0.2f};
 | 
|---|
| [b220f78] | 462 |    GLfloat curTime, prevTime, elapsedTime;
 | 
|---|
| [49db5fc] | 463 | 
 | 
|---|
| [f97e638] | 464 |    GLuint ubo = 0;
 | 
|---|
 | 465 |    glGenBuffers(1, &ubo);
 | 
|---|
| [81f28c0] | 466 | 
 | 
|---|
| [a0eb547] | 467 |    map<GLuint, BufferInfo> shaderBufferInfo;
 | 
|---|
 | 468 |    map<ObjectType, ShaderModelGroup> modelGroups;
 | 
|---|
 | 469 | 
 | 
|---|
 | 470 |    modelGroups[TYPE_SHIP] = createModelGroup(
 | 
|---|
 | 471 |       loadShaderProgram("./ship.vert", "./ship.frag"));
 | 
|---|
 | 472 |    shaderBufferInfo[modelGroups[TYPE_SHIP].shaderProgram] = BufferInfo(); // temporary
 | 
|---|
| [0e0f851] | 473 | 
 | 
|---|
| [a0eb547] | 474 |    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_position", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 475 |       3, GL_FLOAT, offset_of(&SceneObject::points));
 | 
|---|
| [a0eb547] | 476 |    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_color", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 477 |       3, GL_FLOAT, offset_of(&SceneObject::colors));
 | 
|---|
| [a0eb547] | 478 |    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_normal", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 479 |       3, GL_FLOAT, offset_of(&SceneObject::normals));
 | 
|---|
| [a0eb547] | 480 |    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "ubo_index", ATTRIB_OBJECT_VARYING,
 | 
|---|
| [7e10667] | 481 |       1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
 | 
|---|
| [81f28c0] | 482 | 
 | 
|---|
| [49db5fc] | 483 |    defineModelGroupUniform(modelGroups[TYPE_SHIP], "view", ATTRIB_UNIFORM,
 | 
|---|
 | 484 |       1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
 | 
|---|
 | 485 |    defineModelGroupUniform(modelGroups[TYPE_SHIP], "proj", ATTRIB_UNIFORM,
 | 
|---|
 | 486 |       1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
 | 
|---|
 | 487 | 
 | 
|---|
| [a0eb547] | 488 |    initModelGroupAttribs(modelGroups[TYPE_SHIP]);
 | 
|---|
| [20e0020] | 489 | 
 | 
|---|
| [a0eb547] | 490 |    modelGroups[TYPE_ASTEROID] = createModelGroup(
 | 
|---|
 | 491 |       loadShaderProgram("./asteroid.vert", "./asteroid.frag"));
 | 
|---|
 | 492 |    shaderBufferInfo[modelGroups[TYPE_ASTEROID].shaderProgram] = BufferInfo(); // temporary
 | 
|---|
| [0e0f851] | 493 | 
 | 
|---|
| [a0eb547] | 494 |    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_position", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 495 |       3, GL_FLOAT, offset_of(&SceneObject::points));
 | 
|---|
| [a0eb547] | 496 |    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_color", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 497 |       3, GL_FLOAT, offset_of(&SceneObject::colors));
 | 
|---|
| [a0eb547] | 498 |    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_normal", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 499 |       3, GL_FLOAT, offset_of(&SceneObject::normals));
 | 
|---|
| [a0eb547] | 500 |    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "ubo_index", ATTRIB_OBJECT_VARYING,
 | 
|---|
| [7e10667] | 501 |       1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
 | 
|---|
| [a0eb547] | 502 | 
 | 
|---|
| [49db5fc] | 503 |    defineModelGroupUniform(modelGroups[TYPE_ASTEROID], "view", ATTRIB_UNIFORM,
 | 
|---|
 | 504 |       1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
 | 
|---|
 | 505 |    defineModelGroupUniform(modelGroups[TYPE_ASTEROID], "proj", ATTRIB_UNIFORM,
 | 
|---|
 | 506 |       1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
 | 
|---|
 | 507 | 
 | 
|---|
| [a0eb547] | 508 |    initModelGroupAttribs(modelGroups[TYPE_ASTEROID]);
 | 
|---|
| [0e0f851] | 509 | 
 | 
|---|
| [a0eb547] | 510 |    modelGroups[TYPE_LASER] = createModelGroup(
 | 
|---|
 | 511 |       loadShaderProgram("./laser.vert", "./laser.frag"));
 | 
|---|
 | 512 |    shaderBufferInfo[modelGroups[TYPE_LASER].shaderProgram] = BufferInfo(); // temporary
 | 
|---|
| [0e0f851] | 513 | 
 | 
|---|
| [a0eb547] | 514 |    defineModelGroupAttrib(modelGroups[TYPE_LASER], "vertex_position", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 515 |       3, GL_FLOAT, offset_of(&SceneObject::points));
 | 
|---|
| [a0eb547] | 516 |    defineModelGroupAttrib(modelGroups[TYPE_LASER], "vt", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 517 |       2, GL_FLOAT, offset_of(&SceneObject::texcoords));
 | 
|---|
| [a0eb547] | 518 |    defineModelGroupAttrib(modelGroups[TYPE_LASER], "ubo_index", ATTRIB_OBJECT_VARYING,
 | 
|---|
| [7e10667] | 519 |       1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
 | 
|---|
| [20e0020] | 520 | 
 | 
|---|
| [49db5fc] | 521 |    defineModelGroupUniform(modelGroups[TYPE_LASER], "view", ATTRIB_UNIFORM,
 | 
|---|
 | 522 |       1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
 | 
|---|
 | 523 |    defineModelGroupUniform(modelGroups[TYPE_LASER], "proj", ATTRIB_UNIFORM,
 | 
|---|
 | 524 |       1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
 | 
|---|
 | 525 |     defineModelGroupUniform(modelGroups[TYPE_LASER], "laser_color", ATTRIB_UNIFORM,
 | 
|---|
 | 526 |       1, UNIFORM_3F, laserColor);
 | 
|---|
 | 527 | 
 | 
|---|
| [a0eb547] | 528 |    initModelGroupAttribs(modelGroups[TYPE_LASER]);
 | 
|---|
| [20e0020] | 529 | 
 | 
|---|
| [a0eb547] | 530 |    modelGroups[TYPE_EXPLOSION] = createModelGroup(
 | 
|---|
 | 531 |       loadShaderProgram("./explosion.vert", "./explosion.frag"));
 | 
|---|
 | 532 |    shaderBufferInfo[modelGroups[TYPE_EXPLOSION].shaderProgram] = BufferInfo(); // temporary
 | 
|---|
 | 533 | 
 | 
|---|
| [b220f78] | 534 |    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "v_i", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 535 |       3, GL_FLOAT, offset_of(&ParticleEffect::particleVelocities));
 | 
|---|
| [b220f78] | 536 |    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "start_time", ATTRIB_POINT_VARYING,
 | 
|---|
| [7e10667] | 537 |       1, GL_FLOAT, offset_of(&ParticleEffect::particleTimes));
 | 
|---|
| [dc19a39] | 538 |    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "ubo_index", ATTRIB_OBJECT_VARYING,
 | 
|---|
| [7e10667] | 539 |       1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
 | 
|---|
| [b220f78] | 540 | 
 | 
|---|
 | 541 |    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "cur_time", ATTRIB_UNIFORM,
 | 
|---|
 | 542 |       1, UNIFORM_1F, &curTime);
 | 
|---|
 | 543 |    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "view", ATTRIB_UNIFORM,
 | 
|---|
 | 544 |       1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
 | 
|---|
 | 545 |    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "proj", ATTRIB_UNIFORM,
 | 
|---|
 | 546 |       1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
 | 
|---|
 | 547 | 
 | 
|---|
| [b05e2b5] | 548 |    initModelGroupAttribs(modelGroups[TYPE_EXPLOSION]);
 | 
|---|
| [de53394] | 549 | 
 | 
|---|
| [a0eb547] | 550 |    cam_pos = vec3(0.0f, 0.0f, 2.0f);
 | 
|---|
 | 551 |    float cam_yaw = 0.0f * 2.0f * 3.14159f / 360.0f;
 | 
|---|
 | 552 |    float cam_pitch = -50.0f * 2.0f * 3.14159f / 360.0f;
 | 
|---|
 | 553 | 
 | 
|---|
 | 554 |    // player ship
 | 
|---|
| [a926b79] | 555 |    objects.push_back(createShip());
 | 
|---|
| [a0eb547] | 556 | 
 | 
|---|
 | 557 |    vector<SceneObject>::iterator obj_it;
 | 
|---|
 | 558 | 
 | 
|---|
| [7e10667] | 559 |    populateBuffers(objects, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [20e0020] | 560 | 
 | 
|---|
| [1f3d32b] | 561 |    float cam_speed = 1.0f;
 | 
|---|
 | 562 |    float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
 | 
|---|
 | 563 |    float cam_pitch_speed = 60.0f*ONE_DEG_IN_RAD;
 | 
|---|
| [20e0020] | 564 | 
 | 
|---|
| [1f3d32b] | 565 |    // glm::lookAt can create the view matrix
 | 
|---|
 | 566 |    // glm::perspective can create the projection matrix
 | 
|---|
| [20e0020] | 567 | 
 | 
|---|
| [1f3d32b] | 568 |    mat4 T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
 | 
|---|
 | 569 |    mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
 | 
|---|
 | 570 |    mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
 | 
|---|
 | 571 |    mat4 R = pitch_mat * yaw_mat;
 | 
|---|
 | 572 |    view_mat = R*T;
 | 
|---|
| [20e0020] | 573 | 
 | 
|---|
| [1f3d32b] | 574 |    // TODO: Create a function to construct the projection matrix
 | 
|---|
 | 575 |    // (Maybe I should just use glm::perspective, after making sure it matches what I have now)
 | 
|---|
 | 576 |    float fov = 67.0f * ONE_DEG_IN_RAD;
 | 
|---|
| [e6bc0f4] | 577 |    float aspect = (float)windowWidth / (float)windowHeight;
 | 
|---|
| [20e0020] | 578 | 
 | 
|---|
| [1f3d32b] | 579 |    float range = tan(fov * 0.5f) * NEAR_CLIP;
 | 
|---|
 | 580 |    float Sx = NEAR_CLIP / (range * aspect);
 | 
|---|
 | 581 |    float Sy = NEAR_CLIP / range;
 | 
|---|
 | 582 |    float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
 | 
|---|
 | 583 |    float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
 | 
|---|
| [20e0020] | 584 | 
 | 
|---|
| [1f3d32b] | 585 |    float proj_arr[] = {
 | 
|---|
 | 586 |      Sx, 0.0f, 0.0f, 0.0f,
 | 
|---|
 | 587 |      0.0f, Sy, 0.0f, 0.0f,
 | 
|---|
 | 588 |      0.0f, 0.0f, Sz, -1.0f,
 | 
|---|
 | 589 |      0.0f, 0.0f, Pz, 0.0f,
 | 
|---|
| [f9a242b] | 590 |    };
 | 
|---|
| [1f3d32b] | 591 |    proj_mat = make_mat4(proj_arr);
 | 
|---|
| [81f28c0] | 592 | 
 | 
|---|
| [c5fb958] | 593 |    /* TODO: Fix the UBO binding code based on the following forum post (in order to support multiple ubos):
 | 
|---|
| [7e10667] | 594 |       (Also, I bookmarked a great explanation of this under )
 | 
|---|
| [c5fb958] | 595 | 
 | 
|---|
| [c55614a] | 596 |       CHECK MY OpenGL BOOKMARK CALLED "Learn OpenGL: Advanced GLSL"
 | 
|---|
 | 597 | 
 | 
|---|
| [c5fb958] | 598 |       No, you're misunderstanding how this works. UBO binding works exactly like texture object binding.
 | 
|---|
 | 599 | 
 | 
|---|
 | 600 |       The OpenGL context has a number of slots for binding UBOs. There are GL_MAX_UNIFORM_BUFFER_BINDINGS number of
 | 
|---|
 | 601 |       slots for UBO binding.
 | 
|---|
 | 602 | 
 | 
|---|
 | 603 |       Uniform Blocks in a program can be set to use one of the slots in the context. You do this by first querying
 | 
|---|
 | 604 |       the block index using the block name (glGetUniformBlockIndex). This is similar to how you need to use
 | 
|---|
 | 605 |       glGetUniformLocation in order to set a uniform's value with glUniform. Block indices, like uniform locations,
 | 
|---|
 | 606 |       are specific to a program.
 | 
|---|
 | 607 | 
 | 
|---|
 | 608 |       Once you have the block index, you use glUniformBlockBinding to set that specific program to use a particular
 | 
|---|
 | 609 |       uniform buffer slot in the context.
 | 
|---|
 | 610 | 
 | 
|---|
 | 611 |       Let's say you have a global UBO that you want to use for every program. To make using it easier, you want to
 | 
|---|
 | 612 |       bind it just once.
 | 
|---|
 | 613 | 
 | 
|---|
 | 614 |       So first, you pick a uniform buffer slot in the context, one that always will refer to this UBO. Let's say
 | 
|---|
 | 615 |       you pick slot 8.
 | 
|---|
 | 616 | 
 | 
|---|
 | 617 |       When you build a program object that may use this global uniform buffer, what you do is quite simple. First,
 | 
|---|
 | 618 |       after linking the program, call glGetUniformBlockIndex(program, "NameOfGlobalUniformBlock"). If you get back
 | 
|---|
 | 619 |       GL_INVALID_INDEX, then you know that the global uniform block isn't used in that program. Otherwise you get
 | 
|---|
 | 620 |       back a block index.
 | 
|---|
 | 621 | 
 | 
|---|
 | 622 |       If you got a valid block index, then you call glUniformBlockBinding(program, uniformBlockIndex, 8). Remember
 | 
|---|
 | 623 |       that 8 is the uniform buffer context slot that we selected earlier. This causes this particular program to
 | 
|---|
 | 624 |       use uniform buffer slot #8 to find the buffer for "NameOfGlobalUniformBlock".
 | 
|---|
 | 625 | 
 | 
|---|
 | 626 |       Finally, to set the actual buffer in the context, call glBindBufferRange(GL_UNIFORM_BUFFER, 8,
 | 
|---|
 | 627 |       bufferObjectName, offset, size);
 | 
|---|
 | 628 |    */
 | 
|---|
| [fe5e3ca] | 629 | 
 | 
|---|
| [1f3d32b] | 630 |    GLuint ub_binding_point = 0;
 | 
|---|
| [81f28c0] | 631 | 
 | 
|---|
| [4c7cd57] | 632 |    GLuint ship_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_SHIP].shaderProgram, "models");
 | 
|---|
| [0e0f851] | 633 | 
 | 
|---|
| [0414306] | 634 |    GLuint asteroid_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_ASTEROID].shaderProgram, "models");
 | 
|---|
| [81f28c0] | 635 | 
 | 
|---|
| [b62c109] | 636 |    GLuint laser_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_LASER].shaderProgram, "models");
 | 
|---|
| [81f28c0] | 637 | 
 | 
|---|
| [0414306] | 638 |    GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_EXPLOSION].shaderProgram, "models");
 | 
|---|
| [db06984] | 639 | 
 | 
|---|
| [81f28c0] | 640 | 
 | 
|---|
| [4c7cd57] | 641 |    glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
 | 
|---|
| [49db5fc] | 642 |    bindUniformData(modelGroups[TYPE_SHIP].attribs["view"]);
 | 
|---|
 | 643 |    bindUniformData(modelGroups[TYPE_SHIP].attribs["proj"]);
 | 
|---|
| [485424b] | 644 | 
 | 
|---|
| [4c7cd57] | 645 |    glUniformBlockBinding(modelGroups[TYPE_SHIP].shaderProgram, ship_sp_models_ub_index, ub_binding_point);
 | 
|---|
| [14ff67c] | 646 |    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
 | 
|---|
| [e165b85] | 647 | 
 | 
|---|
| [fd6f465] | 648 | 
 | 
|---|
| [0414306] | 649 |    glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
 | 
|---|
| [49db5fc] | 650 |    bindUniformData(modelGroups[TYPE_ASTEROID].attribs["view"]);
 | 
|---|
 | 651 |    bindUniformData(modelGroups[TYPE_ASTEROID].attribs["proj"]);
 | 
|---|
| [0e0f851] | 652 | 
 | 
|---|
| [0414306] | 653 |    glUniformBlockBinding(modelGroups[TYPE_ASTEROID].shaderProgram, asteroid_sp_models_ub_index, ub_binding_point);
 | 
|---|
| [0e0f851] | 654 |    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
 | 
|---|
 | 655 | 
 | 
|---|
 | 656 | 
 | 
|---|
| [49db5fc] | 657 |    // may want to do initialization for basic_texture uniform here too
 | 
|---|
 | 658 |    // Right now, I think I'm getting away without getting that uniform location because I'm only
 | 
|---|
 | 659 |    // using one texture, so setting it to GL_TEXTURE0 once works
 | 
|---|
| [b62c109] | 660 |    glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
 | 
|---|
| [49db5fc] | 661 |    bindUniformData(modelGroups[TYPE_LASER].attribs["view"]);
 | 
|---|
 | 662 |    bindUniformData(modelGroups[TYPE_LASER].attribs["proj"]);
 | 
|---|
 | 663 |    bindUniformData(modelGroups[TYPE_LASER].attribs["laser_color"]);
 | 
|---|
| [b155f13] | 664 | 
 | 
|---|
| [b62c109] | 665 |    glUniformBlockBinding(modelGroups[TYPE_LASER].shaderProgram, laser_sp_models_ub_index, ub_binding_point);
 | 
|---|
| [fd6f465] | 666 |    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
 | 
|---|
 | 667 | 
 | 
|---|
 | 668 | 
 | 
|---|
| [0414306] | 669 |    glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
 | 
|---|
| [7e10667] | 670 |    bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["view"]);
 | 
|---|
 | 671 |    bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["proj"]);
 | 
|---|
 | 672 | 
 | 
|---|
| [0414306] | 673 |    glUniformBlockBinding(modelGroups[TYPE_EXPLOSION].shaderProgram, explosion_sp_models_ub_index, ub_binding_point);
 | 
|---|
| [646f3f2] | 674 |    glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
 | 
|---|
 | 675 | 
 | 
|---|
 | 676 | 
 | 
|---|
| [c4c205e] | 677 |    double fps;
 | 
|---|
 | 678 |    unsigned int score = 0;
 | 
|---|
 | 679 | 
 | 
|---|
| [7ee66ea] | 680 |    bool cam_moved = false;
 | 
|---|
 | 681 | 
 | 
|---|
| [046ce72] | 682 |    int frame_count = 0;
 | 
|---|
| [f70ab75] | 683 |    double elapsed_seconds_fps = 0.0f;
 | 
|---|
| [5527206] | 684 |    double elapsed_seconds_spawn = 0.0f;
 | 
|---|
| [b220f78] | 685 | 
 | 
|---|
 | 686 |    prevTime = glfwGetTime();
 | 
|---|
| [046ce72] | 687 | 
 | 
|---|
| [9dd2eb7] | 688 |    // This draws wireframes. Useful for seeing separate faces and occluded objects.
 | 
|---|
 | 689 |    //glPolygonMode(GL_FRONT, GL_LINE);
 | 
|---|
 | 690 | 
 | 
|---|
| [1f3d32b] | 691 |    // disable vsync to see real framerate
 | 
|---|
 | 692 |    //glfwSwapInterval(0);
 | 
|---|
| [1c81bf0] | 693 | 
 | 
|---|
| [93462c6] | 694 |    State curState = STATE_MAIN_MENU;
 | 
|---|
 | 695 | 
 | 
|---|
| [a9d191a] | 696 |    initGuiValueLists(valueLists);
 | 
|---|
| [c4c205e] | 697 | 
 | 
|---|
 | 698 |    valueLists["stats value list"].push_back(UIValue(UIVALUE_INT, "Score", &score));
 | 
|---|
 | 699 |    valueLists["stats value list"].push_back(UIValue(UIVALUE_DOUBLE, "FPS", &fps));
 | 
|---|
 | 700 | 
 | 
|---|
| [5b3462b] | 701 |    while (!glfwWindowShouldClose(window) && isRunning) {
 | 
|---|
| [b220f78] | 702 |       curTime = glfwGetTime();
 | 
|---|
 | 703 |       elapsedTime = curTime - prevTime;
 | 
|---|
| [8fbd34f] | 704 | 
 | 
|---|
 | 705 |       // temporary code to get around vsync issue in OSX Sierra
 | 
|---|
| [b220f78] | 706 |       if (elapsedTime < (1.0f / TARGET_FPS)) {
 | 
|---|
| [8fbd34f] | 707 |         continue;
 | 
|---|
 | 708 |       }
 | 
|---|
 | 709 | 
 | 
|---|
| [b220f78] | 710 |       prevTime = curTime;
 | 
|---|
| [93baa0e] | 711 | 
 | 
|---|
| [b220f78] | 712 |       elapsed_seconds_fps += elapsedTime;
 | 
|---|
| [1f3d32b] | 713 |       if (elapsed_seconds_fps > 0.25f) {
 | 
|---|
 | 714 |          fps = (double)frame_count / elapsed_seconds_fps;
 | 
|---|
| [046ce72] | 715 | 
 | 
|---|
| [1f3d32b] | 716 |          frame_count = 0;
 | 
|---|
 | 717 |          elapsed_seconds_fps = 0.0f;
 | 
|---|
| [14ff67c] | 718 |       }
 | 
|---|
| [046ce72] | 719 | 
 | 
|---|
| [1f3d32b] | 720 |       frame_count++;
 | 
|---|
 | 721 | 
 | 
|---|
| [f7d35da] | 722 |       // Handle events
 | 
|---|
| [baa5848] | 723 | 
 | 
|---|
 | 724 |       clickedObject = NULL;
 | 
|---|
| [f7d35da] | 725 | 
 | 
|---|
 | 726 |       // reset the all key states to KEY_STATE_UNCHANGED (something the GLFW key callback can never return)
 | 
|---|
 | 727 |       // so that GLFW_PRESS and GLFW_RELEASE are only detected once
 | 
|---|
| [cf2d1e5] | 728 |       // TODO: Change this if we ever need to act on GLFW_REPEAT (which is when a key is held down
 | 
|---|
 | 729 |       //  continuously for a period of time)
 | 
|---|
| [f7d35da] | 730 |       fill(key_state, key_state + NUM_KEYS, KEY_STATE_UNCHANGED);
 | 
|---|
 | 731 | 
 | 
|---|
| [baa5848] | 732 |       glfwPollEvents();
 | 
|---|
 | 733 | 
 | 
|---|
| [93462c6] | 734 |       while (!events.empty()) {
 | 
|---|
 | 735 |          switch (events.front()) {
 | 
|---|
 | 736 |             case EVENT_GO_TO_MAIN_MENU:
 | 
|---|
 | 737 |                curState = STATE_MAIN_MENU;
 | 
|---|
 | 738 |                break;
 | 
|---|
 | 739 |             case EVENT_GO_TO_GAME:
 | 
|---|
 | 740 |                curState = STATE_GAME;
 | 
|---|
 | 741 |                break;
 | 
|---|
 | 742 |             case EVENT_QUIT:
 | 
|---|
 | 743 |                isRunning = false;
 | 
|---|
 | 744 |                break;
 | 
|---|
 | 745 |          }
 | 
|---|
 | 746 |          events.pop();
 | 
|---|
| [147ac6d] | 747 |       }
 | 
|---|
| [93462c6] | 748 | 
 | 
|---|
 | 749 |       if (curState == STATE_GAME) {
 | 
|---|
| [95595de] | 750 | 
 | 
|---|
| [b220f78] | 751 |          elapsed_seconds_spawn += elapsedTime;
 | 
|---|
| [95595de] | 752 |          if (elapsed_seconds_spawn > 0.5f) {
 | 
|---|
| [dd9771c] | 753 |             SceneObject* obj = createAsteroid(vec3(getRandomNum(-1.3f, 1.3f), -1.2f, getRandomNum(-5.5f, -4.5f)));
 | 
|---|
| [f97e638] | 754 |             addObjectToScene(obj, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [95595de] | 755 | 
 | 
|---|
 | 756 |             elapsed_seconds_spawn -= 0.5f;
 | 
|---|
 | 757 |          }
 | 
|---|
 | 758 | 
 | 
|---|
| [cf2d1e5] | 759 |          /*
 | 
|---|
| [93462c6] | 760 |          if (clickedObject == &objects[0]) {
 | 
|---|
 | 761 |             selectedObject = &objects[0];
 | 
|---|
 | 762 |          }
 | 
|---|
 | 763 |          if (clickedObject == &objects[1]) {
 | 
|---|
 | 764 |             selectedObject = &objects[1];
 | 
|---|
 | 765 |          }
 | 
|---|
| [cf2d1e5] | 766 |          */
 | 
|---|
| [f7d35da] | 767 | 
 | 
|---|
 | 768 |          /*
 | 
|---|
 | 769 |          if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
 | 
|---|
| [dba67b2] | 770 |             transformObject(objects[1], translate(mat4(1.0f), vec3(0.3f, 0.0f, 0.0f)), ubo);
 | 
|---|
| [f7d35da] | 771 |          }
 | 
|---|
| [fabed35] | 772 |          if (key_down[GLFW_KEY_RIGHT]) {
 | 
|---|
| [dba67b2] | 773 |             transformObject(objects[2], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
 | 
|---|
| [f7d35da] | 774 |          }
 | 
|---|
| [fabed35] | 775 |          if (key_down[GLFW_KEY_LEFT]) {
 | 
|---|
| [dba67b2] | 776 |             transformObject(objects[2], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
 | 
|---|
| [f7d35da] | 777 |          }
 | 
|---|
 | 778 |          */
 | 
|---|
| [cf2d1e5] | 779 | 
 | 
|---|
| [fabed35] | 780 |          if (key_down[GLFW_KEY_RIGHT]) {
 | 
|---|
| [1f3d32b] | 781 |             transformObject(*objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
 | 
|---|
| [fabed35] | 782 | 
 | 
|---|
| [1f3d32b] | 783 |             if (leftLaser != NULL && !leftLaser->deleted) {
 | 
|---|
 | 784 |                translateLaser(leftLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
 | 
|---|
| [fabed35] | 785 |             }
 | 
|---|
| [1f3d32b] | 786 |             if (rightLaser != NULL && !rightLaser->deleted) {
 | 
|---|
 | 787 |                translateLaser(rightLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
 | 
|---|
| [fabed35] | 788 |             }
 | 
|---|
| [cf2d1e5] | 789 |          }
 | 
|---|
| [fabed35] | 790 |          if (key_down[GLFW_KEY_LEFT]) {
 | 
|---|
| [1f3d32b] | 791 |             transformObject(*objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
 | 
|---|
| [fabed35] | 792 | 
 | 
|---|
| [1f3d32b] | 793 |             if (leftLaser != NULL && !leftLaser->deleted) {
 | 
|---|
 | 794 |                translateLaser(leftLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
 | 
|---|
| [fabed35] | 795 |             }
 | 
|---|
| [1f3d32b] | 796 |             if (rightLaser != NULL && !rightLaser->deleted) {
 | 
|---|
 | 797 |                translateLaser(rightLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
 | 
|---|
| [fabed35] | 798 |             }
 | 
|---|
| [8316333] | 799 |          }
 | 
|---|
| [fabed35] | 800 | 
 | 
|---|
 | 801 |          if (key_state[GLFW_KEY_Z] == GLFW_PRESS) {
 | 
|---|
| [1f3d32b] | 802 |             vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
| [8316333] | 803 | 
 | 
|---|
| [dd9771c] | 804 |             leftLaser = createLaser(
 | 
|---|
 | 805 |                vec3(-0.21f, -1.19f, 1.76f)+offset,
 | 
|---|
 | 806 |                vec3(-0.21f, -1.19f, -3.0f)+offset,
 | 
|---|
 | 807 |                vec3(0.0f, 1.0f, 0.0f), 0.03f);
 | 
|---|
| [f97e638] | 808 |             addObjectToScene(leftLaser, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [fabed35] | 809 |          } else if (key_state[GLFW_KEY_Z] == GLFW_RELEASE) {
 | 
|---|
| [1f3d32b] | 810 |             removeObjectFromScene(*leftLaser, ubo);
 | 
|---|
| [8316333] | 811 |          }
 | 
|---|
| [fabed35] | 812 | 
 | 
|---|
 | 813 |          if (key_state[GLFW_KEY_X] == GLFW_PRESS) {
 | 
|---|
| [1f3d32b] | 814 |             vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
| [8316333] | 815 | 
 | 
|---|
| [dd9771c] | 816 |             rightLaser = createLaser(
 | 
|---|
 | 817 |                vec3(0.21f, -1.19f, 1.76f) + offset,
 | 
|---|
 | 818 |                vec3(0.21f, -1.19f, -3.0f) + offset,
 | 
|---|
 | 819 |                vec3(0.0f, 1.0f, 0.0f), 0.03f);
 | 
|---|
| [f97e638] | 820 |             addObjectToScene(rightLaser, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [fabed35] | 821 |          } else if (key_state[GLFW_KEY_X] == GLFW_RELEASE) {
 | 
|---|
| [1f3d32b] | 822 |             removeObjectFromScene(*rightLaser, ubo);
 | 
|---|
| [cf2d1e5] | 823 |          }
 | 
|---|
 | 824 | 
 | 
|---|
| [92b1e90] | 825 |          // this code moves the asteroids
 | 
|---|
| [8e8aed6] | 826 |          for (unsigned int i = 0; i < objects.size(); i++) {
 | 
|---|
| [7e10667] | 827 |             if (!objects[i]->deleted) {
 | 
|---|
 | 828 |                if (objects[i]->type == TYPE_ASTEROID) {
 | 
|---|
 | 829 |                   transformObject(*objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
 | 
|---|
 | 830 | 
 | 
|---|
 | 831 |                   vec3 obj_center = vec3(view_mat * vec4(objects[i]->bounding_center, 1.0f));
 | 
|---|
 | 832 | 
 | 
|---|
 | 833 |                   if ((obj_center.z - objects[i]->bounding_radius) > -NEAR_CLIP) {
 | 
|---|
 | 834 |                      removeObjectFromScene(*objects[i], ubo);
 | 
|---|
 | 835 |                   }
 | 
|---|
 | 836 |                   if (((Asteroid*)objects[i])->hp <= 0) {
 | 
|---|
 | 837 |                      // TODO: Optimize this so I don't recalculate the camera rotation every time
 | 
|---|
 | 838 |                      float cam_pitch = -50.0f * 2.0f * 3.14159f / 360.0f;
 | 
|---|
 | 839 |                      mat4 pitch_mat = rotate(mat4(1.0f), cam_pitch, vec3(1.0f, 0.0f, 0.0f));
 | 
|---|
 | 840 |                      mat4 model_mat = translate(mat4(1.0f), objects[i]->bounding_center) * pitch_mat;
 | 
|---|
 | 841 | 
 | 
|---|
 | 842 |                      removeObjectFromScene(*objects[i], ubo);
 | 
|---|
 | 843 |                      score++;
 | 
|---|
 | 844 | 
 | 
|---|
 | 845 |                      addObjectToScene(createExplosion(model_mat), shaderBufferInfo, modelGroups, ubo);
 | 
|---|
 | 846 |                   }
 | 
|---|
 | 847 |                } else if (objects[i]->type == TYPE_EXPLOSION) {
 | 
|---|
 | 848 |                   ParticleEffect* explosion = (ParticleEffect*)objects[i];
 | 
|---|
 | 849 |                   if (glfwGetTime() >= explosion->startTime + explosion->duration) {
 | 
|---|
 | 850 |                      removeObjectFromScene(*objects[i], ubo);
 | 
|---|
 | 851 |                   }
 | 
|---|
| [2b0214c] | 852 |                }
 | 
|---|
| [5527206] | 853 |             }
 | 
|---|
| [cf2d1e5] | 854 |          }
 | 
|---|
| [93baa0e] | 855 | 
 | 
|---|
| [1f3d32b] | 856 |          if (leftLaser != NULL && !leftLaser->deleted) {
 | 
|---|
| [a0eb547] | 857 |             updateLaserTarget(leftLaser, objects, modelGroups[TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);
 | 
|---|
| [1f3d32b] | 858 |          }
 | 
|---|
 | 859 |          if (rightLaser != NULL && !rightLaser->deleted) {
 | 
|---|
| [a0eb547] | 860 |             updateLaserTarget(rightLaser, objects, modelGroups[TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);
 | 
|---|
| [1f3d32b] | 861 |          }
 | 
|---|
 | 862 |       }
 | 
|---|
 | 863 | 
 | 
|---|
 | 864 |       for (vector<EffectOverTime*>::iterator it = effects.begin(); it != effects.end(); ) {
 | 
|---|
 | 865 |          if ((*it)->deleted || (*it)->effectedObject->deleted) {
 | 
|---|
 | 866 |             delete *it;
 | 
|---|
 | 867 |             it = effects.erase(it);
 | 
|---|
 | 868 |          } else {
 | 
|---|
 | 869 |             EffectOverTime* eot = *it;
 | 
|---|
| [b220f78] | 870 |             eot->effectedValue = eot->startValue + (curTime - eot->startTime) * eot->changePerSecond;
 | 
|---|
| [1f3d32b] | 871 | 
 | 
|---|
 | 872 |             it++;
 | 
|---|
| [c3c3158] | 873 |          }
 | 
|---|
| [baa5848] | 874 |       }
 | 
|---|
| [df652d5] | 875 | 
 | 
|---|
| [c3c3158] | 876 |       if (key_state[GLFW_KEY_ESCAPE] == GLFW_PRESS) {
 | 
|---|
| [ec4456b] | 877 |          glfwSetWindowShouldClose(window, 1);
 | 
|---|
 | 878 |       }
 | 
|---|
| [7ee66ea] | 879 | 
 | 
|---|
| [b220f78] | 880 |       float dist = cam_speed * elapsedTime;
 | 
|---|
| [fabed35] | 881 |       if (key_down[GLFW_KEY_A]) {
 | 
|---|
| [dba67b2] | 882 |          vec3 dir = vec3(inverse(R) * vec4(-1.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
| [809ce16] | 883 |          cam_pos += dir * dist;
 | 
|---|
| [f7d35da] | 884 | 
 | 
|---|
| [7ee66ea] | 885 |          cam_moved = true;
 | 
|---|
 | 886 |       }
 | 
|---|
| [fabed35] | 887 |       if (key_down[GLFW_KEY_D]) {
 | 
|---|
| [dba67b2] | 888 |          vec3 dir = vec3(inverse(R) * vec4(1.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
| [809ce16] | 889 |          cam_pos += dir * dist;
 | 
|---|
| [f7d35da] | 890 | 
 | 
|---|
| [7ee66ea] | 891 |          cam_moved = true;
 | 
|---|
 | 892 |       }
 | 
|---|
| [fabed35] | 893 |       if (key_down[GLFW_KEY_W]) {
 | 
|---|
| [dba67b2] | 894 |          vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, -1.0f, 1.0f));
 | 
|---|
| [809ce16] | 895 |          cam_pos += dir * dist;
 | 
|---|
| [f7d35da] | 896 | 
 | 
|---|
| [7ee66ea] | 897 |          cam_moved = true;
 | 
|---|
 | 898 |       }
 | 
|---|
| [fabed35] | 899 |       if (key_down[GLFW_KEY_S]) {
 | 
|---|
| [dba67b2] | 900 |          vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, 1.0f, 1.0f));
 | 
|---|
| [809ce16] | 901 |          cam_pos += dir * dist;
 | 
|---|
| [f7d35da] | 902 | 
 | 
|---|
| [7ee66ea] | 903 |          cam_moved = true;
 | 
|---|
 | 904 |       }
 | 
|---|
| [cf2d1e5] | 905 |       /*
 | 
|---|
| [fabed35] | 906 |       if (key_down[GLFW_KEY_LEFT]) {
 | 
|---|
| [b220f78] | 907 |       cam_yaw += cam_yaw_speed * elapsedTime;
 | 
|---|
| [c3c3158] | 908 |       cam_moved = true;
 | 
|---|
| [7ee66ea] | 909 |       }
 | 
|---|
| [fabed35] | 910 |       if (key_down[GLFW_KEY_RIGHT]) {
 | 
|---|
| [b220f78] | 911 |       cam_yaw -= cam_yaw_speed * elapsedTime;
 | 
|---|
| [c3c3158] | 912 |       cam_moved = true;
 | 
|---|
| [7ee66ea] | 913 |       }
 | 
|---|
| [fabed35] | 914 |       if (key_down[GLFW_KEY_UP]) {
 | 
|---|
| [b220f78] | 915 |       cam_pitch += cam_pitch_speed * elapsedTime;
 | 
|---|
| [c3c3158] | 916 |       cam_moved = true;
 | 
|---|
| [809ce16] | 917 |       }
 | 
|---|
| [fabed35] | 918 |       if (key_down[GLFW_KEY_DOWN]) {
 | 
|---|
| [b220f78] | 919 |       cam_pitch -= cam_pitch_speed * elapsedTime;
 | 
|---|
| [c3c3158] | 920 |       cam_moved = true;
 | 
|---|
| [809ce16] | 921 |       }
 | 
|---|
| [cf2d1e5] | 922 |       */
 | 
|---|
| [1f3d32b] | 923 |       if (cam_moved && false) { // disable camera movement
 | 
|---|
| [dba67b2] | 924 |          T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
 | 
|---|
| [809ce16] | 925 | 
 | 
|---|
| [dba67b2] | 926 |          mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
 | 
|---|
 | 927 |          mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
 | 
|---|
| [809ce16] | 928 |          R = pitch_mat * yaw_mat;
 | 
|---|
| [f7d35da] | 929 | 
 | 
|---|
| [c3c3158] | 930 |          view_mat = R * T;
 | 
|---|
| [7ee66ea] | 931 | 
 | 
|---|
| [4c7cd57] | 932 |          glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
 | 
|---|
| [49db5fc] | 933 |          bindUniformData(modelGroups[TYPE_SHIP].attribs["view"]);
 | 
|---|
| [267c4c5] | 934 | 
 | 
|---|
| [b62c109] | 935 |          glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
 | 
|---|
| [49db5fc] | 936 |          bindUniformData(modelGroups[TYPE_LASER].attribs["view"]);
 | 
|---|
| [b155f13] | 937 | 
 | 
|---|
| [7ee66ea] | 938 |          cam_moved = false;
 | 
|---|
 | 939 |       }
 | 
|---|
| [c3c3158] | 940 | 
 | 
|---|
| [0414306] | 941 |       glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
 | 
|---|
| [b220f78] | 942 |       bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["cur_time"]);
 | 
|---|
| [db06984] | 943 | 
 | 
|---|
| [c3c3158] | 944 |       // Render scene
 | 
|---|
 | 945 | 
 | 
|---|
 | 946 |       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
|---|
 | 947 | 
 | 
|---|
| [e6bc0f4] | 948 |       // Anton's book suggests placing this here, after glClear(). Check it's impact on framerate
 | 
|---|
 | 949 |       //glViewport(0, 0, windowWidth, windowHeight);
 | 
|---|
 | 950 | 
 | 
|---|
| [c3c3158] | 951 |       switch (curState) {
 | 
|---|
 | 952 |          case STATE_MAIN_MENU:
 | 
|---|
 | 953 |             renderMainMenu();
 | 
|---|
 | 954 |             renderMainMenuGui();
 | 
|---|
 | 955 |             break;
 | 
|---|
 | 956 |          case STATE_GAME:
 | 
|---|
| [7e10667] | 957 |             renderScene(modelGroups, ubo);
 | 
|---|
| [c4c205e] | 958 |             renderSceneGui(valueLists);
 | 
|---|
| [c3c3158] | 959 |             break;
 | 
|---|
 | 960 |       }
 | 
|---|
 | 961 | 
 | 
|---|
 | 962 |       glfwSwapBuffers(window);
 | 
|---|
| [644a2e4] | 963 |    }
 | 
|---|
 | 964 | 
 | 
|---|
| [c1ca5b5] | 965 |    ImGui_ImplGlfwGL3_Shutdown();
 | 
|---|
 | 966 |    ImGui::DestroyContext();
 | 
|---|
 | 967 | 
 | 
|---|
 | 968 |    glfwDestroyWindow(window);
 | 
|---|
| [5272b6b] | 969 |    glfwTerminate();
 | 
|---|
| [c1ca5b5] | 970 | 
 | 
|---|
| [1f3d32b] | 971 |    // free memory
 | 
|---|
 | 972 | 
 | 
|---|
 | 973 |    for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
 | 
|---|
 | 974 |       delete *it;
 | 
|---|
 | 975 |    }
 | 
|---|
 | 976 | 
 | 
|---|
| [5272b6b] | 977 |    return 0;
 | 
|---|
 | 978 | }
 | 
|---|
| [ec4456b] | 979 | 
 | 
|---|
| [4f3262f] | 980 | void glfw_error_callback(int error, const char* description) {
 | 
|---|
| [bae0911] | 981 |    gl_log_err("GLFW ERROR: code %i msg: %s", error, description);
 | 
|---|
| [4f3262f] | 982 | }
 | 
|---|
 | 983 | 
 | 
|---|
 | 984 | void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
 | 
|---|
 | 985 |    double mouse_x, mouse_y;
 | 
|---|
 | 986 |    glfwGetCursorPos(window, &mouse_x, &mouse_y);
 | 
|---|
 | 987 | 
 | 
|---|
 | 988 |    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
 | 
|---|
 | 989 |       cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
 | 
|---|
 | 990 |       selectedObject = NULL;
 | 
|---|
 | 991 | 
 | 
|---|
| [e6bc0f4] | 992 |       float x = (2.0f*mouse_x) / windowWidth - 1.0f;
 | 
|---|
 | 993 |       float y = 1.0f - (2.0f*mouse_y) / windowHeight;
 | 
|---|
| [4f3262f] | 994 | 
 | 
|---|
 | 995 |       cout << "x: " << x << ", y: " << y << endl;
 | 
|---|
 | 996 | 
 | 
|---|
 | 997 |       vec4 ray_clip = vec4(x, y, -1.0f, 1.0f);
 | 
|---|
 | 998 |       vec4 ray_eye = inverse(proj_mat) * ray_clip;
 | 
|---|
| [dba67b2] | 999 |       ray_eye = vec4(vec2(ray_eye), -1.0f, 1.0f);
 | 
|---|
| [4f3262f] | 1000 |       vec4 ray_world = inverse(view_mat) * ray_eye;
 | 
|---|
 | 1001 | 
 | 
|---|
 | 1002 |       vec4 click_point;
 | 
|---|
 | 1003 |       vec3 closest_point = vec3(0.0f, 0.0f, -FAR_CLIP); // Any valid point will be closer than the far clipping plane, so initial value to that
 | 
|---|
 | 1004 |       SceneObject* closest_object = NULL;
 | 
|---|
 | 1005 | 
 | 
|---|
| [1f3d32b] | 1006 |       for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
 | 
|---|
 | 1007 |          if ((*it)->type == TYPE_LASER) continue;
 | 
|---|
 | 1008 |          for (unsigned int p_idx = 0; p_idx < (*it)->points.size(); p_idx += 9) {
 | 
|---|
| [0d5c100] | 1009 |             if (faceClicked(
 | 
|---|
 | 1010 |                {
 | 
|---|
| [1f3d32b] | 1011 |                   vec3((*it)->points[p_idx], (*it)->points[p_idx + 1], (*it)->points[p_idx + 2]),
 | 
|---|
 | 1012 |                   vec3((*it)->points[p_idx + 3], (*it)->points[p_idx + 4], (*it)->points[p_idx + 5]),
 | 
|---|
 | 1013 |                   vec3((*it)->points[p_idx + 6], (*it)->points[p_idx + 7], (*it)->points[p_idx + 8]),
 | 
|---|
| [4f3262f] | 1014 |                },
 | 
|---|
| [1f3d32b] | 1015 |                *it, ray_world, vec4(cam_pos, 1.0f), click_point
 | 
|---|
| [0d5c100] | 1016 |             )) {
 | 
|---|
| [4f3262f] | 1017 |                click_point = view_mat * click_point;
 | 
|---|
 | 1018 | 
 | 
|---|
 | 1019 |                if (-NEAR_CLIP >= click_point.z && click_point.z > -FAR_CLIP && click_point.z > closest_point.z) {
 | 
|---|
| [dba67b2] | 1020 |                   closest_point = vec3(click_point);
 | 
|---|
| [1f3d32b] | 1021 |                   closest_object = *it;
 | 
|---|
| [4f3262f] | 1022 |                }
 | 
|---|
 | 1023 |             }
 | 
|---|
 | 1024 |          }
 | 
|---|
 | 1025 |       }
 | 
|---|
 | 1026 | 
 | 
|---|
 | 1027 |       if (closest_object == NULL) {
 | 
|---|
 | 1028 |          cout << "No object was clicked" << endl;
 | 
|---|
| [f7d35da] | 1029 |       } else {
 | 
|---|
| [4f3262f] | 1030 |          clickedObject = closest_object;
 | 
|---|
 | 1031 |          cout << "Clicked object: " << clickedObject->id << endl;
 | 
|---|
 | 1032 |       }
 | 
|---|
 | 1033 |    }
 | 
|---|
 | 1034 | }
 | 
|---|
 | 1035 | 
 | 
|---|
| [f7d35da] | 1036 | void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
 | 
|---|
 | 1037 |    key_state[key] = action;
 | 
|---|
 | 1038 | 
 | 
|---|
 | 1039 |    // should be true for GLFW_PRESS and GLFW_REPEAT
 | 
|---|
| [fabed35] | 1040 |    key_down[key] = (action != GLFW_RELEASE);
 | 
|---|
| [f7d35da] | 1041 | }
 | 
|---|
 | 1042 | 
 | 
|---|
| [e6bc0f4] | 1043 | void window_size_callback(GLFWwindow* window, int width, int height) {
 | 
|---|
 | 1044 |    cout << "Window resized to (" << width << ", " << height << ")" << endl;
 | 
|---|
 | 1045 | 
 | 
|---|
 | 1046 |    windowWidth = width;
 | 
|---|
 | 1047 |    windowHeight = height;
 | 
|---|
 | 1048 | 
 | 
|---|
 | 1049 |    // TODO: Ideally, remove the window title bar when the window is maximized
 | 
|---|
 | 1050 |    // Check https://github.com/glfw/glfw/issues/778
 | 
|---|
 | 1051 | 
 | 
|---|
 | 1052 |    // This requires glfw3.3. I think I have to upgrade
 | 
|---|
 | 1053 |    // Doesn't seem to be needed in OSX and also causes a segfault there
 | 
|---|
 | 1054 |    //glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
 | 
|---|
 | 1055 | }
 | 
|---|
 | 1056 | 
 | 
|---|
| [0e0f851] | 1057 | void APIENTRY debugGlCallback(
 | 
|---|
 | 1058 |    GLenum source,
 | 
|---|
 | 1059 |    GLenum type,
 | 
|---|
 | 1060 |    GLuint id,
 | 
|---|
 | 1061 |    GLenum severity,
 | 
|---|
 | 1062 |    GLsizei length,
 | 
|---|
 | 1063 |    const GLchar* message,
 | 
|---|
 | 1064 |    const void* userParam
 | 
|---|
 | 1065 | ) {
 | 
|---|
 | 1066 |    string strMessage(message);
 | 
|---|
 | 1067 | 
 | 
|---|
 | 1068 |    // TODO: Use C++ strings directly
 | 
|---|
 | 1069 |    char source_str[2048];
 | 
|---|
 | 1070 |    char type_str[2048];
 | 
|---|
 | 1071 |    char severity_str[2048];
 | 
|---|
 | 1072 | 
 | 
|---|
 | 1073 |    switch (source) {
 | 
|---|
| [a0eb547] | 1074 |       case 0x8246:
 | 
|---|
 | 1075 |          strcpy(source_str, "API");
 | 
|---|
 | 1076 |          break;
 | 
|---|
 | 1077 |       case 0x8247:
 | 
|---|
 | 1078 |          strcpy(source_str, "WINDOW_SYSTEM");
 | 
|---|
 | 1079 |          break;
 | 
|---|
 | 1080 |       case 0x8248:
 | 
|---|
 | 1081 |          strcpy(source_str, "SHADER_COMPILER");
 | 
|---|
 | 1082 |          break;
 | 
|---|
 | 1083 |       case 0x8249:
 | 
|---|
 | 1084 |          strcpy(source_str, "THIRD_PARTY");
 | 
|---|
 | 1085 |          break;
 | 
|---|
 | 1086 |       case 0x824A:
 | 
|---|
 | 1087 |          strcpy(source_str, "APPLICATION");
 | 
|---|
 | 1088 |          break;
 | 
|---|
 | 1089 |       case 0x824B:
 | 
|---|
 | 1090 |          strcpy(source_str, "OTHER");
 | 
|---|
 | 1091 |          break;
 | 
|---|
 | 1092 |       default:
 | 
|---|
 | 1093 |          strcpy(source_str, "undefined");
 | 
|---|
 | 1094 |          break;
 | 
|---|
| [0e0f851] | 1095 |    }
 | 
|---|
 | 1096 | 
 | 
|---|
 | 1097 |    switch (type) {
 | 
|---|
| [a0eb547] | 1098 |       case 0x824C:
 | 
|---|
 | 1099 |          strcpy(type_str, "ERROR");
 | 
|---|
 | 1100 |          break;
 | 
|---|
 | 1101 |       case 0x824D:
 | 
|---|
 | 1102 |          strcpy(type_str, "DEPRECATED_BEHAVIOR");
 | 
|---|
 | 1103 |          break;
 | 
|---|
 | 1104 |       case 0x824E:
 | 
|---|
 | 1105 |          strcpy(type_str, "UNDEFINED_BEHAVIOR");
 | 
|---|
 | 1106 |          break;
 | 
|---|
 | 1107 |       case 0x824F:
 | 
|---|
 | 1108 |          strcpy(type_str, "PORTABILITY");
 | 
|---|
 | 1109 |          break;
 | 
|---|
 | 1110 |       case 0x8250:
 | 
|---|
 | 1111 |          strcpy(type_str, "PERFORMANCE");
 | 
|---|
 | 1112 |          break;
 | 
|---|
 | 1113 |       case 0x8251:
 | 
|---|
 | 1114 |          strcpy(type_str, "OTHER");
 | 
|---|
 | 1115 |          break;
 | 
|---|
 | 1116 |       case 0x8268:
 | 
|---|
 | 1117 |          strcpy(type_str, "MARKER");
 | 
|---|
 | 1118 |          break;
 | 
|---|
 | 1119 |       case 0x8269:
 | 
|---|
 | 1120 |          strcpy(type_str, "PUSH_GROUP");
 | 
|---|
 | 1121 |          break;
 | 
|---|
 | 1122 |       case 0x826A:
 | 
|---|
 | 1123 |          strcpy(type_str, "POP_GROUP");
 | 
|---|
 | 1124 |          break;
 | 
|---|
 | 1125 |       default:
 | 
|---|
 | 1126 |          strcpy(type_str, "undefined");
 | 
|---|
 | 1127 |          break;
 | 
|---|
| [0e0f851] | 1128 |    }
 | 
|---|
 | 1129 |    switch (severity) {
 | 
|---|
| [a0eb547] | 1130 |       case 0x9146:
 | 
|---|
 | 1131 |          strcpy(severity_str, "HIGH");
 | 
|---|
 | 1132 |          break;
 | 
|---|
 | 1133 |       case 0x9147:
 | 
|---|
 | 1134 |          strcpy(severity_str, "MEDIUM");
 | 
|---|
 | 1135 |          break;
 | 
|---|
 | 1136 |       case 0x9148:
 | 
|---|
 | 1137 |          strcpy(severity_str, "LOW");
 | 
|---|
 | 1138 |          break;
 | 
|---|
 | 1139 |       case 0x826B:
 | 
|---|
 | 1140 |          strcpy(severity_str, "NOTIFICATION");
 | 
|---|
 | 1141 |          break;
 | 
|---|
 | 1142 |       default:
 | 
|---|
 | 1143 |          strcpy(severity_str, "undefined");
 | 
|---|
 | 1144 |          break;
 | 
|---|
| [0e0f851] | 1145 |    }
 | 
|---|
 | 1146 | 
 | 
|---|
 | 1147 |    if (string(severity_str) != "NOTIFICATION") {
 | 
|---|
 | 1148 |       cout << "OpenGL Error!!!" << endl;
 | 
|---|
 | 1149 |       cout << "Source: " << string(source_str) << endl;
 | 
|---|
 | 1150 |       cout << "Type: " << string(type_str) << endl;
 | 
|---|
 | 1151 |       cout << "Severity: " << string(severity_str) << endl;
 | 
|---|
 | 1152 |       cout << strMessage << endl;
 | 
|---|
 | 1153 |    }
 | 
|---|
 | 1154 | }
 | 
|---|
 | 1155 | 
 | 
|---|
| [f7d35da] | 1156 | 
 | 
|---|
| [ec4456b] | 1157 | GLuint loadShader(GLenum type, string file) {
 | 
|---|
 | 1158 |   cout << "Loading shader from file " << file << endl;
 | 
|---|
 | 1159 | 
 | 
|---|
 | 1160 |   ifstream shaderFile(file);
 | 
|---|
 | 1161 |   GLuint shaderId = 0;
 | 
|---|
 | 1162 | 
 | 
|---|
 | 1163 |   if (shaderFile.is_open()) {
 | 
|---|
 | 1164 |     string line, shaderString;
 | 
|---|
 | 1165 | 
 | 
|---|
 | 1166 |     while(getline(shaderFile, line)) {
 | 
|---|
 | 1167 |       shaderString += line + "\n";
 | 
|---|
 | 1168 |     }
 | 
|---|
 | 1169 |     shaderFile.close();
 | 
|---|
 | 1170 |     const char* shaderCString = shaderString.c_str();
 | 
|---|
 | 1171 | 
 | 
|---|
 | 1172 |     shaderId = glCreateShader(type);
 | 
|---|
 | 1173 |     glShaderSource(shaderId, 1, &shaderCString, NULL);
 | 
|---|
 | 1174 |     glCompileShader(shaderId);
 | 
|---|
 | 1175 | 
 | 
|---|
 | 1176 |     cout << "Loaded successfully" << endl;
 | 
|---|
 | 1177 |   } else {
 | 
|---|
| [e856d62] | 1178 |     cout << "Failed to load the file" << endl;
 | 
|---|
| [ec4456b] | 1179 |   }
 | 
|---|
 | 1180 | 
 | 
|---|
 | 1181 |   return shaderId;
 | 
|---|
 | 1182 | }
 | 
|---|
| [485424b] | 1183 | 
 | 
|---|
 | 1184 | GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
 | 
|---|
 | 1185 |    GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
 | 
|---|
 | 1186 |    GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
 | 
|---|
 | 1187 | 
 | 
|---|
 | 1188 |    GLuint shader_program = glCreateProgram();
 | 
|---|
 | 1189 |    glAttachShader(shader_program, vs);
 | 
|---|
 | 1190 |    glAttachShader(shader_program, fs);
 | 
|---|
 | 1191 | 
 | 
|---|
 | 1192 |    glLinkProgram(shader_program);
 | 
|---|
 | 1193 | 
 | 
|---|
 | 1194 |    return shader_program;
 | 
|---|
 | 1195 | }
 | 
|---|
 | 1196 | 
 | 
|---|
 | 1197 | unsigned char* loadImage(string file_name, int* x, int* y) {
 | 
|---|
 | 1198 |   int n;
 | 
|---|
| [e856d62] | 1199 |   int force_channels = 4; // This forces RGBA (4 bytes per pixel)
 | 
|---|
| [485424b] | 1200 |   unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
 | 
|---|
| [e856d62] | 1201 | 
 | 
|---|
 | 1202 |   int width_in_bytes = *x * 4;
 | 
|---|
 | 1203 |   unsigned char *top = NULL;
 | 
|---|
 | 1204 |   unsigned char *bottom = NULL;
 | 
|---|
 | 1205 |   unsigned char temp = 0;
 | 
|---|
 | 1206 |   int half_height = *y / 2;
 | 
|---|
 | 1207 | 
 | 
|---|
 | 1208 |   // flip image upside-down to account for OpenGL treating lower-left as (0, 0)
 | 
|---|
 | 1209 |   for (int row = 0; row < half_height; row++) {
 | 
|---|
 | 1210 |      top = image_data + row * width_in_bytes;
 | 
|---|
 | 1211 |      bottom = image_data + (*y - row - 1) * width_in_bytes;
 | 
|---|
 | 1212 |      for (int col = 0; col < width_in_bytes; col++) {
 | 
|---|
 | 1213 |         temp = *top;
 | 
|---|
 | 1214 |         *top = *bottom;
 | 
|---|
 | 1215 |         *bottom = temp;
 | 
|---|
 | 1216 |         top++;
 | 
|---|
 | 1217 |         bottom++;
 | 
|---|
 | 1218 |      }
 | 
|---|
 | 1219 |   }
 | 
|---|
 | 1220 | 
 | 
|---|
| [485424b] | 1221 |   if (!image_data) {
 | 
|---|
| [bae0911] | 1222 |     gl_log_err("ERROR: could not load %s", file_name.c_str());
 | 
|---|
| [485424b] | 1223 |   }
 | 
|---|
| [e856d62] | 1224 | 
 | 
|---|
 | 1225 |   // Not Power-of-2 check
 | 
|---|
 | 1226 |   if ((*x & (*x - 1)) != 0 || (*y & (*y - 1)) != 0) {
 | 
|---|
| [bae0911] | 1227 |      gl_log_err("WARNING: texture %s is not power-of-2 dimensions", file_name.c_str());
 | 
|---|
| [e856d62] | 1228 |   }
 | 
|---|
 | 1229 | 
 | 
|---|
| [485424b] | 1230 |   return image_data;
 | 
|---|
 | 1231 | }
 | 
|---|
| [33a9664] | 1232 | 
 | 
|---|
| [d9f99b2] | 1233 | bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point) {
 | 
|---|
| [5c9d193] | 1234 |    // LINE EQUATION:            P = O + Dt
 | 
|---|
| [b73cb3b] | 1235 |    // O = cam
 | 
|---|
| [5c9d193] | 1236 |    // D = ray_world
 | 
|---|
 | 1237 | 
 | 
|---|
| [b73cb3b] | 1238 |    // PLANE EQUATION:   P dot n + d = 0
 | 
|---|
 | 1239 |    // n is the normal vector
 | 
|---|
 | 1240 |    // d is the offset from the origin
 | 
|---|
| [5c9d193] | 1241 | 
 | 
|---|
 | 1242 |    // Take the cross-product of two vectors on the plane to get the normal
 | 
|---|
| [d9f99b2] | 1243 |    vec3 v1 = points[1] - points[0];
 | 
|---|
 | 1244 |    vec3 v2 = points[2] - points[0];
 | 
|---|
| [5c9d193] | 1245 | 
 | 
|---|
| [1f3d32b] | 1246 |    vec3 normal = vec3(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
 | 
|---|
 | 1247 | 
 | 
|---|
 | 1248 |    vec3 local_ray = vec3(inverse(obj->model_mat) * world_ray);
 | 
|---|
 | 1249 |    vec3 local_cam = vec3(inverse(obj->model_mat) * cam);
 | 
|---|
 | 1250 | 
 | 
|---|
 | 1251 |    local_ray = local_ray - local_cam;
 | 
|---|
 | 1252 | 
 | 
|---|
 | 1253 |    float d = -glm::dot(points[0], normal);
 | 
|---|
 | 1254 |    float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
 | 
|---|
 | 1255 | 
 | 
|---|
 | 1256 |    vec3 intersection = local_cam + t*local_ray;
 | 
|---|
 | 1257 | 
 | 
|---|
 | 1258 |    if (insideTriangle(intersection, points)) {
 | 
|---|
 | 1259 |       click_point = obj->model_mat * vec4(intersection, 1.0f);
 | 
|---|
 | 1260 |       return true;
 | 
|---|
 | 1261 |    } else {
 | 
|---|
 | 1262 |       return false;
 | 
|---|
 | 1263 |    }
 | 
|---|
 | 1264 | }
 | 
|---|
 | 1265 | 
 | 
|---|
 | 1266 | bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
 | 
|---|
 | 1267 |    vec3 v21 = triangle_points[1] - triangle_points[0];
 | 
|---|
 | 1268 |    vec3 v31 = triangle_points[2] - triangle_points[0];
 | 
|---|
 | 1269 |    vec3 pv1 = p - triangle_points[0];
 | 
|---|
 | 1270 | 
 | 
|---|
 | 1271 |    float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
 | 
|---|
 | 1272 |    float x = (pv1.x-y*v31.x) / v21.x;
 | 
|---|
 | 1273 | 
 | 
|---|
 | 1274 |    return x > 0.0f && y > 0.0f && x+y < 1.0f;
 | 
|---|
 | 1275 | }
 | 
|---|
 | 1276 | 
 | 
|---|
| [7e10667] | 1277 | void printVec3(string label, const vec3& v) {
 | 
|---|
| [1f3d32b] | 1278 |    cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
 | 
|---|
 | 1279 | }
 | 
|---|
 | 1280 | 
 | 
|---|
| [7e10667] | 1281 | void printVec4(string label, const vec4& v) {
 | 
|---|
| [1f3d32b] | 1282 |    cout << label << " -> (" << v.x << "," << v.y << "," << v.z << "," << v.w << ")" << endl;
 | 
|---|
 | 1283 | }
 | 
|---|
 | 1284 | 
 | 
|---|
| [7e10667] | 1285 | void printMat4(string label, const mat4& m) {
 | 
|---|
 | 1286 |    cout << label << ": " << endl;
 | 
|---|
 | 1287 |    cout << "[ " << m[0][0] << " " << m[1][0] << " " << m[2][0] << " " << m[3][0] <<  " ]" << endl;
 | 
|---|
 | 1288 |    cout << "[ " << m[0][1] << " " << m[1][1] << " " << m[2][1] << " " << m[3][1] <<  " ]" << endl;
 | 
|---|
 | 1289 |    cout << "[ " << m[0][2] << " " << m[1][2] << " " << m[2][2] << " " << m[3][2] <<  " ]" << endl;
 | 
|---|
 | 1290 |    cout << "[ " << m[0][3] << " " << m[1][3] << " " << m[2][3] << " " << m[3][3] <<  " ]" << endl;
 | 
|---|
 | 1291 | }
 | 
|---|
| [1f3d32b] | 1292 | 
 | 
|---|
| [7e10667] | 1293 | // TODO: Pass a reference, not a pointer
 | 
|---|
 | 1294 | void initObject(SceneObject* obj) {
 | 
|---|
| [1f3d32b] | 1295 |    obj->id = objects.size(); // currently unused
 | 
|---|
 | 1296 |    obj->num_points = obj->points.size() / 3;
 | 
|---|
 | 1297 |    obj->model_transform = mat4(1.0f);
 | 
|---|
 | 1298 |    obj->deleted = false;
 | 
|---|
 | 1299 | 
 | 
|---|
 | 1300 |    obj->normals.reserve(obj->points.size());
 | 
|---|
| [8e8aed6] | 1301 |    for (unsigned int i = 0; i < obj->points.size(); i += 9) {
 | 
|---|
| [1f3d32b] | 1302 |       vec3 point1 = vec3(obj->points[i], obj->points[i + 1], obj->points[i + 2]);
 | 
|---|
 | 1303 |       vec3 point2 = vec3(obj->points[i + 3], obj->points[i + 4], obj->points[i + 5]);
 | 
|---|
 | 1304 |       vec3 point3 = vec3(obj->points[i + 6], obj->points[i + 7], obj->points[i + 8]);
 | 
|---|
 | 1305 | 
 | 
|---|
 | 1306 |       vec3 normal = normalize(cross(point2 - point1, point3 - point1));
 | 
|---|
 | 1307 | 
 | 
|---|
 | 1308 |       // Add the same normal for all 3 points
 | 
|---|
 | 1309 |       for (int j = 0; j < 3; j++) {
 | 
|---|
 | 1310 |          obj->normals.push_back(normal.x);
 | 
|---|
 | 1311 |          obj->normals.push_back(normal.y);
 | 
|---|
 | 1312 |          obj->normals.push_back(normal.z);
 | 
|---|
 | 1313 |       }
 | 
|---|
 | 1314 |    }
 | 
|---|
 | 1315 | 
 | 
|---|
| [646f3f2] | 1316 |    if (obj->type == TYPE_SHIP || obj->type == TYPE_ASTEROID) {
 | 
|---|
| [1f3d32b] | 1317 |       calculateObjectBoundingBox(obj);
 | 
|---|
 | 1318 | 
 | 
|---|
 | 1319 |       obj->bounding_center = vec3(obj->translate_mat * vec4(obj->bounding_center, 1.0f));
 | 
|---|
 | 1320 |    }
 | 
|---|
 | 1321 | }
 | 
|---|
 | 1322 | 
 | 
|---|
| [7e10667] | 1323 | // TODO: Check if I can pass in a reference to obj instead (do this for all other functions as well)
 | 
|---|
| [1f3d32b] | 1324 | void addObjectToScene(SceneObject* obj,
 | 
|---|
 | 1325 |    map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 1326 |    map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [f97e638] | 1327 |    GLuint ubo) {
 | 
|---|
| [1f3d32b] | 1328 |    objects.push_back(obj);
 | 
|---|
 | 1329 | 
 | 
|---|
| [dd9771c] | 1330 |    BufferInfo* bufferInfo = &shaderBufferInfo[modelGroups[obj->type].shaderProgram];
 | 
|---|
| [1f3d32b] | 1331 | 
 | 
|---|
 | 1332 |    // Check if the buffers aren't large enough to fit the new object and, if so, call
 | 
|---|
 | 1333 |    // populateBuffers() to resize and repopupulate them
 | 
|---|
| [7e10667] | 1334 |    if ((modelGroups[obj->type].vboCapacity < (modelGroups[obj->type].numPoints + obj->num_points) ||
 | 
|---|
 | 1335 |       bufferInfo->ubo_capacity <= bufferInfo->ubo_offset)) {
 | 
|---|
| [1f3d32b] | 1336 | 
 | 
|---|
 | 1337 |       if (leftLaser != NULL && leftLaser->deleted) {
 | 
|---|
 | 1338 |          leftLaser = NULL;
 | 
|---|
 | 1339 |       }
 | 
|---|
 | 1340 |       if (rightLaser != NULL && rightLaser->deleted) {
 | 
|---|
 | 1341 |          rightLaser = NULL;
 | 
|---|
 | 1342 |       }
 | 
|---|
 | 1343 | 
 | 
|---|
| [f97e638] | 1344 |       populateBuffers(objects, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [1f3d32b] | 1345 |    } else {
 | 
|---|
| [49db5fc] | 1346 |       copyObjectDataToBuffers(*objects.back(), shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [1f3d32b] | 1347 |    }
 | 
|---|
 | 1348 | }
 | 
|---|
 | 1349 | 
 | 
|---|
 | 1350 | void removeObjectFromScene(SceneObject& obj, GLuint ubo) {
 | 
|---|
 | 1351 |    if (!obj.deleted) {
 | 
|---|
 | 1352 |       // Move the object outside the render bounds of the scene so it doesn't get rendered
 | 
|---|
 | 1353 |       // TODO: Find a better way of hiding the object until the next time buffers are repopulated
 | 
|---|
 | 1354 |       transformObject(obj, translate(mat4(1.0f), vec3(0.0f, 0.0f, FAR_CLIP * 1000.0f)), ubo);
 | 
|---|
 | 1355 |       obj.deleted = true;
 | 
|---|
 | 1356 |    }
 | 
|---|
 | 1357 | }
 | 
|---|
 | 1358 | 
 | 
|---|
| [7e10667] | 1359 | // TODO: Pass a reference, not a pointer
 | 
|---|
| [1f3d32b] | 1360 | void calculateObjectBoundingBox(SceneObject* obj) {
 | 
|---|
 | 1361 |    GLfloat min_x = obj->points[0];
 | 
|---|
 | 1362 |    GLfloat max_x = obj->points[0];
 | 
|---|
 | 1363 |    GLfloat min_y = obj->points[1];
 | 
|---|
 | 1364 |    GLfloat max_y = obj->points[1];
 | 
|---|
 | 1365 |    GLfloat min_z = obj->points[2];
 | 
|---|
 | 1366 |    GLfloat max_z = obj->points[2];
 | 
|---|
 | 1367 | 
 | 
|---|
 | 1368 |    // start from the second point
 | 
|---|
| [8e8aed6] | 1369 |    for (unsigned int i = 3; i < obj->points.size(); i += 3) {
 | 
|---|
| [1f3d32b] | 1370 |       if (min_x > obj->points[i]) {
 | 
|---|
 | 1371 |          min_x = obj->points[i];
 | 
|---|
 | 1372 |       }
 | 
|---|
 | 1373 |       else if (max_x < obj->points[i]) {
 | 
|---|
 | 1374 |          max_x = obj->points[i];
 | 
|---|
 | 1375 |       }
 | 
|---|
 | 1376 | 
 | 
|---|
 | 1377 |       if (min_y > obj->points[i + 1]) {
 | 
|---|
 | 1378 |          min_y = obj->points[i + 1];
 | 
|---|
 | 1379 |       }
 | 
|---|
 | 1380 |       else if (max_y < obj->points[i + 1]) {
 | 
|---|
 | 1381 |          max_y = obj->points[i + 1];
 | 
|---|
 | 1382 |       }
 | 
|---|
 | 1383 | 
 | 
|---|
 | 1384 |       if (min_z > obj->points[i + 2]) {
 | 
|---|
 | 1385 |          min_z = obj->points[i + 2];
 | 
|---|
 | 1386 |       }
 | 
|---|
 | 1387 |       else if (max_z < obj->points[i + 2]) {
 | 
|---|
 | 1388 |          max_z = obj->points[i + 2];
 | 
|---|
 | 1389 |       }
 | 
|---|
 | 1390 |    }
 | 
|---|
 | 1391 | 
 | 
|---|
 | 1392 |    obj->bounding_center = vec3((min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f, (min_z + max_z) / 2.0f);
 | 
|---|
 | 1393 | 
 | 
|---|
 | 1394 |    GLfloat radius_x = max_x - obj->bounding_center.x;
 | 
|---|
 | 1395 |    GLfloat radius_y = max_y - obj->bounding_center.y;
 | 
|---|
 | 1396 |    GLfloat radius_z = max_z - obj->bounding_center.z;
 | 
|---|
 | 1397 | 
 | 
|---|
 | 1398 |    // TODO: This actually underestimates the radius. Might need to be fixed at some point.
 | 
|---|
 | 1399 |    // TODO: Does not take into account any scaling in the model matrix
 | 
|---|
 | 1400 |    obj->bounding_radius = radius_x;
 | 
|---|
 | 1401 |    if (obj->bounding_radius < radius_y)
 | 
|---|
 | 1402 |       obj->bounding_radius = radius_y;
 | 
|---|
 | 1403 |    if (obj->bounding_radius < radius_z)
 | 
|---|
 | 1404 |       obj->bounding_radius = radius_z;
 | 
|---|
 | 1405 | 
 | 
|---|
| [8e8aed6] | 1406 |    for (unsigned int i = 0; i < obj->points.size(); i += 3) {
 | 
|---|
| [1f3d32b] | 1407 |       obj->points[i] -= obj->bounding_center.x;
 | 
|---|
 | 1408 |       obj->points[i + 1] -= obj->bounding_center.y;
 | 
|---|
 | 1409 |       obj->points[i + 2] -= obj->bounding_center.z;
 | 
|---|
 | 1410 |    }
 | 
|---|
 | 1411 | 
 | 
|---|
 | 1412 |    obj->bounding_center = vec3(0.0f, 0.0f, 0.0f);
 | 
|---|
 | 1413 | }
 | 
|---|
 | 1414 | 
 | 
|---|
| [dd9771c] | 1415 | SceneObject* createShip() {
 | 
|---|
| [1f3d32b] | 1416 |    SceneObject* ship = new SceneObject();
 | 
|---|
 | 1417 | 
 | 
|---|
 | 1418 |    ship->type = TYPE_SHIP;
 | 
|---|
 | 1419 | 
 | 
|---|
 | 1420 |    ship->points = {
 | 
|---|
 | 1421 |       //back
 | 
|---|
 | 1422 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1423 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1424 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1425 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1426 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1427 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1428 | 
 | 
|---|
 | 1429 |       // left back
 | 
|---|
 | 1430 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1431 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1432 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1433 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1434 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1435 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1436 | 
 | 
|---|
 | 1437 |       // right back
 | 
|---|
 | 1438 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1439 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1440 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1441 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1442 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1443 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1444 | 
 | 
|---|
 | 1445 |       // left mid
 | 
|---|
 | 1446 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1447 |       -0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1448 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1449 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1450 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1451 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1452 | 
 | 
|---|
 | 1453 |       // right mid
 | 
|---|
 | 1454 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1455 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1456 |       0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1457 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1458 |       0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1459 |       0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1460 | 
 | 
|---|
 | 1461 |       // left front
 | 
|---|
 | 1462 |       0.0f,    0.0f,   -3.5f,
 | 
|---|
 | 1463 |       -0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1464 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1465 | 
 | 
|---|
 | 1466 |       // right front
 | 
|---|
 | 1467 |       0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1468 |       0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1469 |       0.0f,    0.0f,   -3.5f,
 | 
|---|
 | 1470 | 
 | 
|---|
 | 1471 |       // top back
 | 
|---|
 | 1472 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1473 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1474 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1475 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1476 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1477 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1478 | 
 | 
|---|
 | 1479 |       // bottom back
 | 
|---|
 | 1480 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1481 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1482 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1483 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1484 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1485 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1486 | 
 | 
|---|
 | 1487 |       // top mid
 | 
|---|
 | 1488 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1489 |       -0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1490 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1491 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1492 |       0.5f,    0.3f,   -2.0f,
 | 
|---|
 | 1493 |       0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1494 | 
 | 
|---|
 | 1495 |       // bottom mid
 | 
|---|
 | 1496 |       -0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1497 |       -0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1498 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1499 |       0.5f,    0.0f,   -2.0f,
 | 
|---|
 | 1500 |       -0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1501 |       0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1502 | 
 | 
|---|
 | 1503 |       // top front
 | 
|---|
 | 1504 |       -0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1505 |       0.25f,   0.3f,   -3.0f,
 | 
|---|
 | 1506 |       0.0f,    0.0f,   -3.5f,
 | 
|---|
 | 1507 | 
 | 
|---|
 | 1508 |       // bottom front
 | 
|---|
 | 1509 |       0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1510 |       -0.25f,   0.0f,   -3.0f,
 | 
|---|
 | 1511 |       0.0f,    0.0f,   -3.5f,
 | 
|---|
 | 1512 | 
 | 
|---|
 | 1513 |       // left wing start back
 | 
|---|
 | 1514 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1515 |       -1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1516 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1517 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1518 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1519 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1520 | 
 | 
|---|
 | 1521 |       // left wing start top
 | 
|---|
 | 1522 |       -0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1523 |       -1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1524 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1525 |       -0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1526 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1527 |       -0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1528 | 
 | 
|---|
 | 1529 |       // left wing start front
 | 
|---|
 | 1530 |       -0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1531 |       -0.5f,    0.0f,   -0.3f,
 | 
|---|
 | 1532 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1533 |       -0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1534 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1535 |       -1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1536 | 
 | 
|---|
 | 1537 |       // left wing start bottom
 | 
|---|
 | 1538 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1539 |       -1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1540 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1541 |       -0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1542 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1543 |       -0.5f,    0.0f,   -0.3f,
 | 
|---|
 | 1544 | 
 | 
|---|
 | 1545 |       // left wing end outside
 | 
|---|
 | 1546 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1547 |       -2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1548 |       -1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1549 | 
 | 
|---|
 | 1550 |       // left wing end top
 | 
|---|
 | 1551 |       -1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1552 |       -2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1553 |       -1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1554 | 
 | 
|---|
 | 1555 |       // left wing end front
 | 
|---|
 | 1556 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1557 |       -2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1558 |       -1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1559 | 
 | 
|---|
 | 1560 |       // left wing end bottom
 | 
|---|
 | 1561 |       -1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1562 |       -2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1563 |       -1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1564 | 
 | 
|---|
 | 1565 |       // right wing start back
 | 
|---|
 | 1566 |       1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1567 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1568 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1569 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1570 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1571 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1572 | 
 | 
|---|
 | 1573 |       // right wing start top
 | 
|---|
 | 1574 |       1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1575 |       0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1576 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1577 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1578 |       0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1579 |       0.5f,    0.3f,    0.0f,
 | 
|---|
 | 1580 | 
 | 
|---|
 | 1581 |       // right wing start front
 | 
|---|
 | 1582 |       0.5f,    0.0f,   -0.3f,
 | 
|---|
 | 1583 |       0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1584 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1585 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1586 |       0.5f,    0.3f,   -0.3f,
 | 
|---|
 | 1587 |       1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1588 | 
 | 
|---|
 | 1589 |       // right wing start bottom
 | 
|---|
 | 1590 |       1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1591 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1592 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1593 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1594 |       0.5f,    0.0f,    0.0f,
 | 
|---|
 | 1595 |       0.5f,    0.0f,   -0.3f,
 | 
|---|
 | 1596 | 
 | 
|---|
 | 1597 |       // right wing end outside
 | 
|---|
 | 1598 |       2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1599 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1600 |       1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1601 | 
 | 
|---|
 | 1602 |       // right wing end top
 | 
|---|
 | 1603 |       2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1604 |       1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1605 |       1.5f,    0.3f,    0.0f,
 | 
|---|
 | 1606 | 
 | 
|---|
 | 1607 |       // right wing end front
 | 
|---|
 | 1608 |       2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1609 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1610 |       1.3f,    0.3f,   -0.3f,
 | 
|---|
 | 1611 | 
 | 
|---|
 | 1612 |       // right wing end bottom
 | 
|---|
 | 1613 |       2.2f,    0.15f,  -0.8f,
 | 
|---|
 | 1614 |       1.5f,    0.0f,    0.0f,
 | 
|---|
 | 1615 |       1.3f,    0.0f,   -0.3f,
 | 
|---|
 | 1616 |    };
 | 
|---|
 | 1617 |    ship->colors = {
 | 
|---|
 | 1618 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1619 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1620 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1621 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1622 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1623 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1624 | 
 | 
|---|
 | 1625 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1626 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1627 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1628 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1629 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1630 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [b73cb3b] | 1631 | 
 | 
|---|
| [1f3d32b] | 1632 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1633 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1634 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1635 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1636 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1637 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [5c9d193] | 1638 | 
 | 
|---|
| [1f3d32b] | 1639 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1640 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1641 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1642 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1643 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1644 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [5c9d193] | 1645 | 
 | 
|---|
| [1f3d32b] | 1646 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1647 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1648 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1649 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1650 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1651 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [5c9d193] | 1652 | 
 | 
|---|
| [1f3d32b] | 1653 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1654 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1655 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [5c9d193] | 1656 | 
 | 
|---|
| [1f3d32b] | 1657 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1658 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1659 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [f7d35da] | 1660 | 
 | 
|---|
| [1f3d32b] | 1661 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1662 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1663 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1664 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1665 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1666 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [33a9664] | 1667 | 
 | 
|---|
| [1f3d32b] | 1668 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1669 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1670 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1671 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1672 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1673 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [33a9664] | 1674 | 
 | 
|---|
| [1f3d32b] | 1675 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1676 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1677 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1678 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1679 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1680 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [d12d003] | 1681 | 
 | 
|---|
| [1f3d32b] | 1682 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1683 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1684 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1685 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1686 |       0.0f, 0.0f, 1.0f,
 | 
|---|
 | 1687 |       0.0f, 0.0f, 1.0f,
 | 
|---|
| [b73cb3b] | 1688 | 
 | 
|---|
| [1f3d32b] | 1689 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1690 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1691 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [c1ca5b5] | 1692 | 
 | 
|---|
| [1f3d32b] | 1693 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1694 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1695 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [3d06b4e] | 1696 | 
 | 
|---|
| [1f3d32b] | 1697 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1698 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1699 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1700 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1701 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1702 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [0d5c100] | 1703 | 
 | 
|---|
| [1f3d32b] | 1704 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1705 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1706 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1707 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1708 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1709 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [cffca4d] | 1710 | 
 | 
|---|
| [1f3d32b] | 1711 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1712 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1713 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1714 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1715 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1716 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [cffca4d] | 1717 | 
 | 
|---|
| [1f3d32b] | 1718 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1719 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1720 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1721 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1722 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1723 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [cffca4d] | 1724 | 
 | 
|---|
| [1f3d32b] | 1725 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1726 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1727 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [95595de] | 1728 | 
 | 
|---|
| [1f3d32b] | 1729 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1730 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1731 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [cffca4d] | 1732 | 
 | 
|---|
| [1f3d32b] | 1733 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1734 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1735 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [c3c3158] | 1736 | 
 | 
|---|
| [1f3d32b] | 1737 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1738 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1739 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [c3c3158] | 1740 | 
 | 
|---|
| [1f3d32b] | 1741 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1742 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1743 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1744 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1745 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1746 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [fabed35] | 1747 | 
 | 
|---|
| [1f3d32b] | 1748 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1749 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1750 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1751 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1752 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1753 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [fabed35] | 1754 | 
 | 
|---|
| [1f3d32b] | 1755 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1756 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1757 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1758 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1759 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1760 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [c3c3158] | 1761 | 
 | 
|---|
| [1f3d32b] | 1762 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1763 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1764 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1765 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1766 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1767 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [c3c3158] | 1768 | 
 | 
|---|
| [1f3d32b] | 1769 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1770 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1771 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [3d06b4e] | 1772 | 
 | 
|---|
| [1f3d32b] | 1773 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1774 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1775 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [3d06b4e] | 1776 | 
 | 
|---|
| [1f3d32b] | 1777 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1778 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1779 |       0.0f, 0.0f, 0.3f,
 | 
|---|
| [3d06b4e] | 1780 | 
 | 
|---|
| [1f3d32b] | 1781 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1782 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1783 |       0.0f, 0.0f, 0.3f,
 | 
|---|
 | 1784 |    };
 | 
|---|
 | 1785 |    ship->texcoords = { 0.0f };
 | 
|---|
| [3d06b4e] | 1786 | 
 | 
|---|
| [1f3d32b] | 1787 |    mat4 T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
 | 
|---|
 | 1788 |    mat4 R_model(1.0f);
 | 
|---|
 | 1789 |    ship->model_base = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
 | 
|---|
| [3d06b4e] | 1790 | 
 | 
|---|
| [1f3d32b] | 1791 |    ship->translate_mat = T_model;
 | 
|---|
| [3d06b4e] | 1792 | 
 | 
|---|
| [1f3d32b] | 1793 |    initObject(ship);
 | 
|---|
| [3d06b4e] | 1794 | 
 | 
|---|
| [1f3d32b] | 1795 |    return ship;
 | 
|---|
| [3d06b4e] | 1796 | }
 | 
|---|
 | 1797 | 
 | 
|---|
| [3effd81] | 1798 | /* LASER RENDERING/POSITIONING ALGORITHM
 | 
|---|
 | 1799 |  * -Draw a thin rectangle for the laser beam, using the specified width and endpoints
 | 
|---|
 | 1800 |  * -Texture the beam with a grayscale partially transparent image
 | 
|---|
 | 1801 |  * -In the shader, blend the image with a color to support lasers of different colors
 | 
|---|
 | 1802 |  *
 | 
|---|
 | 1803 |  * The flat part of the textured rectangle needs to always face the camera, so the laser's width is constant
 | 
|---|
 | 1804 |  * This is done as follows:
 | 
|---|
 | 1805 | * -Determine the length of the laser based on the start and end points
 | 
|---|
 | 1806 | * -Draw a rectangle along the z-axis and rotated upwards along the y-axis, with the correct final length and width
 | 
|---|
 | 1807 | * -Rotate the beam around the z-axis by the correct angle, sot that in its final position, the flat part faces the camera
 | 
|---|
 | 1808 | * -Rotate the beam along the x-axis and then along the y-axis and then translate it to put it into its final position
 | 
|---|
 | 1809 | */
 | 
|---|
| [8316333] | 1810 | // TODO: Make the color parameter have an effect
 | 
|---|
| [dd9771c] | 1811 | Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width) {
 | 
|---|
| [1f3d32b] | 1812 |    Laser* obj = new Laser();
 | 
|---|
 | 1813 |    obj->type = TYPE_LASER;
 | 
|---|
 | 1814 |    obj->targetAsteroid = NULL;
 | 
|---|
| [b155f13] | 1815 | 
 | 
|---|
| [3effd81] | 1816 |    vec3 ray = end - start;
 | 
|---|
 | 1817 |    float length = glm::length(ray);
 | 
|---|
| [b155f13] | 1818 | 
 | 
|---|
| [1f3d32b] | 1819 |    obj->points = {
 | 
|---|
| [fd6f465] | 1820 |        width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1821 |       -width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1822 |       -width / 2, 0.0f, 0.0f,
 | 
|---|
 | 1823 |        width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1824 |       -width / 2, 0.0f, 0.0f,
 | 
|---|
 | 1825 |        width / 2, 0.0f, 0.0f,
 | 
|---|
 | 1826 |        width / 2, 0.0f, -length + width / 2,
 | 
|---|
 | 1827 |       -width / 2, 0.0f, -length + width / 2,
 | 
|---|
 | 1828 |       -width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1829 |        width / 2, 0.0f, -length + width / 2,
 | 
|---|
 | 1830 |       -width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1831 |        width / 2, 0.0f, -width / 2,
 | 
|---|
 | 1832 |        width / 2, 0.0f, -length,
 | 
|---|
 | 1833 |       -width / 2, 0.0f, -length,
 | 
|---|
 | 1834 |       -width / 2, 0.0f, -length + width / 2,
 | 
|---|
 | 1835 |        width / 2, 0.0f, -length,
 | 
|---|
 | 1836 |       -width / 2, 0.0f, -length + width / 2,
 | 
|---|
 | 1837 |        width / 2, 0.0f, -length + width / 2,
 | 
|---|
| [b155f13] | 1838 |    };
 | 
|---|
 | 1839 | 
 | 
|---|
| [1f3d32b] | 1840 |    obj->texcoords = {
 | 
|---|
| [9f9f9a7] | 1841 |       1.0f, 0.5f,
 | 
|---|
 | 1842 |       0.0f, 0.5f,
 | 
|---|
 | 1843 |       0.0f, 0.0f,
 | 
|---|
 | 1844 |       1.0f, 0.5f,
 | 
|---|
 | 1845 |       0.0f, 0.0f,
 | 
|---|
 | 1846 |       1.0f, 0.0f,
 | 
|---|
 | 1847 |       1.0f, 0.51f,
 | 
|---|
 | 1848 |       0.0f, 0.51f,
 | 
|---|
 | 1849 |       0.0f, 0.49f,
 | 
|---|
 | 1850 |       1.0f, 0.51f,
 | 
|---|
 | 1851 |       0.0f, 0.49f,
 | 
|---|
 | 1852 |       1.0f, 0.49f,
 | 
|---|
 | 1853 |       1.0f, 1.0f,
 | 
|---|
 | 1854 |       0.0f, 1.0f,
 | 
|---|
 | 1855 |       0.0f, 0.5f,
 | 
|---|
 | 1856 |       1.0f, 1.0f,
 | 
|---|
 | 1857 |       0.0f, 0.5f,
 | 
|---|
 | 1858 |       1.0f, 0.5f,
 | 
|---|
 | 1859 |    };
 | 
|---|
 | 1860 | 
 | 
|---|
| [3effd81] | 1861 |    float xAxisRotation = asin(ray.y / length);
 | 
|---|
 | 1862 |    float yAxisRotation = atan2(-ray.x, -ray.z);
 | 
|---|
 | 1863 | 
 | 
|---|
 | 1864 |    vec3 normal(rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) *
 | 
|---|
 | 1865 |                rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) *
 | 
|---|
 | 1866 |                vec4(0.0f, 1.0f, 0.0f, 1.0f));
 | 
|---|
 | 1867 | 
 | 
|---|
 | 1868 |    // To project point P onto line AB:
 | 
|---|
 | 1869 |    // projection = A + dot(AP,AB) / dot(AB,AB) * AB
 | 
|---|
 | 1870 |    vec3 projOnLaser = start + glm::dot(cam_pos-start, ray) / (length*length) * ray;
 | 
|---|
 | 1871 |    vec3 laserToCam = cam_pos - projOnLaser;
 | 
|---|
 | 1872 | 
 | 
|---|
 | 1873 |    float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
 | 
|---|
 | 1874 | 
 | 
|---|
| [1f3d32b] | 1875 |    obj->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
 | 
|---|
| [b155f13] | 1876 | 
 | 
|---|
| [8316333] | 1877 |    initObject(obj);
 | 
|---|
 | 1878 | 
 | 
|---|
| [1f3d32b] | 1879 |    obj->model_transform = rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) * obj->model_transform;
 | 
|---|
 | 1880 |    obj->model_transform = rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) * obj->model_transform;
 | 
|---|
 | 1881 |    obj->model_transform = translate(mat4(1.0f), start) * obj->model_transform;
 | 
|---|
| [612d1f6] | 1882 | 
 | 
|---|
| [8316333] | 1883 |    return obj;
 | 
|---|
| [b155f13] | 1884 | }
 | 
|---|
 | 1885 | 
 | 
|---|
| [7a55b49] | 1886 | ShaderModelGroup createModelGroup(GLuint shaderProgram) {
 | 
|---|
 | 1887 |    ShaderModelGroup smg;
 | 
|---|
 | 1888 | 
 | 
|---|
 | 1889 |    smg.shaderProgram = shaderProgram;
 | 
|---|
| [0414306] | 1890 |    glGenVertexArrays(1, &smg.vao);
 | 
|---|
 | 1891 |    smg.numPoints = 0;
 | 
|---|
| [7a55b49] | 1892 | 
 | 
|---|
 | 1893 |    return smg;
 | 
|---|
 | 1894 | }
 | 
|---|
 | 1895 | 
 | 
|---|
| [a926b79] | 1896 | // TODO: Add the code to resize the buffers here
 | 
|---|
 | 1897 | // addObjectToScene and removeObjectFromScene pretty much already do this.
 | 
|---|
 | 1898 | // However, when addObjectToScene resizes the buffers, it resizes them for all object types
 | 
|---|
 | 1899 | // It would be more efficient to only resize them for the object type in question
 | 
|---|
 | 1900 | 
 | 
|---|
| [7a55b49] | 1901 | void removeModelFromGroup(ShaderModelGroup& modelGroup, SceneObject& model) {
 | 
|---|
 | 1902 |    // TODO: Implement
 | 
|---|
 | 1903 | }
 | 
|---|
 | 1904 | 
 | 
|---|
 | 1905 | void addModelToGroup(ShaderModelGroup& modelGroup, SceneObject& model) {
 | 
|---|
 | 1906 |    // TODO: Implement
 | 
|---|
 | 1907 | }
 | 
|---|
 | 1908 | 
 | 
|---|
| [a0eb547] | 1909 | void defineModelGroupAttrib(ShaderModelGroup& modelGroup, string name, AttribType attribType,
 | 
|---|
 | 1910 |                   GLint size, GLenum type, size_t fieldOffset) {
 | 
|---|
 | 1911 |    if (type != GL_FLOAT && type != GL_UNSIGNED_INT) {
 | 
|---|
 | 1912 |       cout << "Unknown shader program attribute type: " << type << endl;
 | 
|---|
 | 1913 |       return;
 | 
|---|
 | 1914 |    }
 | 
|---|
 | 1915 | 
 | 
|---|
 | 1916 |    AttribInfo attribInfo;
 | 
|---|
 | 1917 | 
 | 
|---|
 | 1918 |    attribInfo.attribType = attribType;
 | 
|---|
 | 1919 |    attribInfo.index = modelGroup.attribs.size();
 | 
|---|
 | 1920 |    attribInfo.size = size;
 | 
|---|
 | 1921 |    attribInfo.type = type;
 | 
|---|
 | 1922 |    attribInfo.fieldOffset = fieldOffset;
 | 
|---|
 | 1923 | 
 | 
|---|
 | 1924 |    modelGroup.attribs[name] = attribInfo;
 | 
|---|
 | 1925 | }
 | 
|---|
 | 1926 | 
 | 
|---|
| [49db5fc] | 1927 | void defineModelGroupUniform(ShaderModelGroup& modelGroup, string name, AttribType attribType,
 | 
|---|
 | 1928 |                   GLint size, UniformType type, GLfloat* data) {
 | 
|---|
 | 1929 |    AttribInfo attribInfo;
 | 
|---|
 | 1930 | 
 | 
|---|
 | 1931 |    attribInfo.attribType = attribType;
 | 
|---|
 | 1932 |    attribInfo.size = size;
 | 
|---|
 | 1933 |    attribInfo.uniType = type;
 | 
|---|
 | 1934 |    attribInfo.data = data;
 | 
|---|
 | 1935 | 
 | 
|---|
 | 1936 |    modelGroup.attribs[name] = attribInfo;
 | 
|---|
 | 1937 | }
 | 
|---|
 | 1938 | 
 | 
|---|
| [a0eb547] | 1939 | void initModelGroupAttribs(ShaderModelGroup& modelGroup) {
 | 
|---|
 | 1940 |    glBindVertexArray(modelGroup.vao);
 | 
|---|
 | 1941 | 
 | 
|---|
 | 1942 |    map<string, AttribInfo>::iterator it;
 | 
|---|
 | 1943 |    for (it = modelGroup.attribs.begin(); it != modelGroup.attribs.end(); it++) {
 | 
|---|
| [49db5fc] | 1944 |       if (it->second.attribType == ATTRIB_UNIFORM) {
 | 
|---|
 | 1945 |          it->second.buffer = glGetUniformLocation(modelGroup.shaderProgram, it->first.c_str());
 | 
|---|
 | 1946 |       } else {
 | 
|---|
 | 1947 |          glEnableVertexAttribArray(it->second.index);
 | 
|---|
| [a0eb547] | 1948 | 
 | 
|---|
| [49db5fc] | 1949 |          glGenBuffers(1, &it->second.buffer);
 | 
|---|
 | 1950 |          glBindBuffer(GL_ARRAY_BUFFER, it->second.buffer);
 | 
|---|
| [a0eb547] | 1951 | 
 | 
|---|
| [49db5fc] | 1952 |          switch (it->second.type) {
 | 
|---|
 | 1953 |             case GL_FLOAT: {
 | 
|---|
 | 1954 |                glVertexAttribPointer(it->second.index, it->second.size, it->second.type, GL_FALSE, 0, NULL);
 | 
|---|
 | 1955 |                break;
 | 
|---|
 | 1956 |             }
 | 
|---|
 | 1957 |             case GL_UNSIGNED_INT: {
 | 
|---|
 | 1958 |                glVertexAttribIPointer(it->second.index, it->second.size, it->second.type, 0, NULL);
 | 
|---|
 | 1959 |                break;
 | 
|---|
 | 1960 |             }
 | 
|---|
| [a0eb547] | 1961 |          }
 | 
|---|
 | 1962 |       }
 | 
|---|
 | 1963 |    }
 | 
|---|
 | 1964 | }
 | 
|---|
 | 1965 | 
 | 
|---|
| [49db5fc] | 1966 | void bindUniformData(AttribInfo& attrib) {
 | 
|---|
 | 1967 |    switch(attrib.uniType) {
 | 
|---|
 | 1968 |       case UNIFORM_MATRIX_4F:
 | 
|---|
 | 1969 |          glUniformMatrix4fv(attrib.buffer, attrib.size, GL_FALSE, attrib.data);
 | 
|---|
 | 1970 |          break;
 | 
|---|
 | 1971 |       case UNIFORM_1F:
 | 
|---|
| [b220f78] | 1972 |          glUniform1fv(attrib.buffer, attrib.size, attrib.data);
 | 
|---|
| [49db5fc] | 1973 |          break;
 | 
|---|
 | 1974 |       case UNIFORM_3F:
 | 
|---|
 | 1975 |          glUniform3fv(attrib.buffer, attrib.size, attrib.data);
 | 
|---|
 | 1976 |          break;
 | 
|---|
| [b220f78] | 1977 |       case UNIFORM_NONE:
 | 
|---|
 | 1978 |          break;
 | 
|---|
 | 1979 |    }
 | 
|---|
 | 1980 | }
 | 
|---|
 | 1981 | 
 | 
|---|
 | 1982 | void bindUniformData(AttribInfo& attrib, GLfloat *data) {
 | 
|---|
 | 1983 |    switch(attrib.uniType) {
 | 
|---|
 | 1984 |       case UNIFORM_MATRIX_4F:
 | 
|---|
 | 1985 |          glUniformMatrix4fv(attrib.buffer, attrib.size, GL_FALSE, data);
 | 
|---|
 | 1986 |          break;
 | 
|---|
 | 1987 |       case UNIFORM_1F:
 | 
|---|
 | 1988 |          glUniform1fv(attrib.buffer, attrib.size, data);
 | 
|---|
 | 1989 |          break;
 | 
|---|
 | 1990 |       case UNIFORM_3F:
 | 
|---|
 | 1991 |          glUniform3fv(attrib.buffer, attrib.size, data);
 | 
|---|
 | 1992 |          break;
 | 
|---|
 | 1993 |       case UNIFORM_NONE:
 | 
|---|
 | 1994 |          break;
 | 
|---|
| [49db5fc] | 1995 |    }
 | 
|---|
 | 1996 | }
 | 
|---|
 | 1997 | 
 | 
|---|
| [a0eb547] | 1998 | /* The purpose of this function is to replace the use of sizeof() when calling
 | 
|---|
 | 1999 |  * function like glBufferSubData and using AttribInfo to get offsets and types
 | 
|---|
 | 2000 |  * I need instead of hardcoding them. I can't save a type like GLfloat, but I cam
 | 
|---|
 | 2001 |  * save GL_FLOAT and use this function to return sizeof(GLfloat) when GL_FLOAT is
 | 
|---|
 | 2002 |  * passed.
 | 
|---|
 | 2003 |  */
 | 
|---|
 | 2004 | size_t GLsizeof(GLenum type) {
 | 
|---|
 | 2005 |    switch (type) {
 | 
|---|
 | 2006 |       case GL_FLOAT:
 | 
|---|
 | 2007 |          return sizeof(GLfloat);
 | 
|---|
 | 2008 |       case GL_UNSIGNED_INT:
 | 
|---|
 | 2009 |          return sizeof(GLuint);
 | 
|---|
 | 2010 |       default:
 | 
|---|
 | 2011 |          cout << "Uknown GL type passed to GLsizeof: " << type << endl;
 | 
|---|
 | 2012 |          return 0;
 | 
|---|
 | 2013 |    }
 | 
|---|
 | 2014 | }
 | 
|---|
 | 2015 | 
 | 
|---|
 | 2016 | /* This function returns a reference to the first element of a given vector
 | 
|---|
 | 2017 |  * attribute in obj. The vector is assumed to hold GLfloats. If the same thing
 | 
|---|
 | 2018 |  * needs to be done later for vectors of other types, we could pass in a GLenum,
 | 
|---|
 | 2019 |  * and do something similar to GLsizeof
 | 
|---|
 | 2020 |  */
 | 
|---|
 | 2021 | GLvoid* getVectorAttribPtr(SceneObject& obj, size_t attribOffset) {
 | 
|---|
 | 2022 |    return (GLvoid*)(&(*(vector<GLfloat>*)((size_t)&obj + attribOffset))[0]);
 | 
|---|
 | 2023 | }
 | 
|---|
 | 2024 | 
 | 
|---|
 | 2025 | GLvoid* getScalarAttribPtr(SceneObject& obj, size_t attribOffset) {
 | 
|---|
 | 2026 |    return (GLvoid*)((size_t)&obj + attribOffset);
 | 
|---|
 | 2027 | }
 | 
|---|
 | 2028 | 
 | 
|---|
| [1f3d32b] | 2029 | void populateBuffers(vector<SceneObject*>& objects,
 | 
|---|
| [c3c3158] | 2030 |                   map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 2031 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [f97e638] | 2032 |                   GLuint ubo) {
 | 
|---|
| [0e0f851] | 2033 |    GLsizeiptr num_points = 0;
 | 
|---|
 | 2034 |    GLsizeiptr num_objects = 0;
 | 
|---|
| [0d5c100] | 2035 | 
 | 
|---|
| [c3c3158] | 2036 |    map<GLuint, unsigned int> shaderCounts;
 | 
|---|
| [0d5c100] | 2037 |    map<GLuint, unsigned int> shaderUboCounts;
 | 
|---|
| [93462c6] | 2038 | 
 | 
|---|
| [646f3f2] | 2039 |    map<GLuint, BufferInfo>::iterator shaderIt;
 | 
|---|
 | 2040 | 
 | 
|---|
 | 2041 |    for (shaderIt = shaderBufferInfo.begin(); shaderIt != shaderBufferInfo.end(); shaderIt++) {
 | 
|---|
 | 2042 |       shaderCounts[shaderIt->first] = 0;
 | 
|---|
 | 2043 |       shaderUboCounts[shaderIt->first] = 0;
 | 
|---|
 | 2044 |    }
 | 
|---|
 | 2045 | 
 | 
|---|
| [1f3d32b] | 2046 |    vector<SceneObject*>::iterator it;
 | 
|---|
| [0d5c100] | 2047 | 
 | 
|---|
| [92b1e90] | 2048 |    /* Find all shaders that need to be used and the number of objects and
 | 
|---|
| [c3c3158] | 2049 |    * number of points for each shader. Construct a map from shader id to count
 | 
|---|
 | 2050 |    * of points being drawn using that shader (for thw model matrix ubo, we
 | 
|---|
 | 2051 |    * need object counts instead). These will be used to get offsets into the
 | 
|---|
 | 2052 |    * vertex buffer for each shader.
 | 
|---|
 | 2053 |    */
 | 
|---|
| [1f3d32b] | 2054 |    for (it = objects.begin(); it != objects.end(); ) {
 | 
|---|
 | 2055 |       if ((*it)->deleted) {
 | 
|---|
 | 2056 |          delete *it;
 | 
|---|
| [c3c3158] | 2057 |          it = objects.erase(it);
 | 
|---|
| [0d5c100] | 2058 |       } else {
 | 
|---|
| [0e0f851] | 2059 |          num_points += (*it)->num_points;
 | 
|---|
 | 2060 |          num_objects++;
 | 
|---|
| [c3c3158] | 2061 | 
 | 
|---|
| [dd9771c] | 2062 |          shaderCounts[modelGroups[(*it)->type].shaderProgram] += (*it)->num_points;
 | 
|---|
 | 2063 |          shaderUboCounts[modelGroups[(*it)->type].shaderProgram]++;
 | 
|---|
| [c3c3158] | 2064 | 
 | 
|---|
 | 2065 |          it++;
 | 
|---|
| [e3ca955] | 2066 |       }
 | 
|---|
| [0d5c100] | 2067 |    }
 | 
|---|
 | 2068 | 
 | 
|---|
| [c3c3158] | 2069 |    // double the buffer sizes to leave room for new objects
 | 
|---|
| [0e0f851] | 2070 |    num_points *= 2;
 | 
|---|
 | 2071 |    num_objects *= 2;
 | 
|---|
| [c3c3158] | 2072 | 
 | 
|---|
| [646f3f2] | 2073 |    map<GLuint, unsigned int>::iterator shaderCountIt;
 | 
|---|
| [0d5c100] | 2074 |    unsigned int lastShaderCount = 0;
 | 
|---|
 | 2075 |    unsigned int lastShaderUboCount = 0;
 | 
|---|
 | 2076 | 
 | 
|---|
 | 2077 |    /*
 | 
|---|
| [c3c3158] | 2078 |    * The counts calculated above can be used to get the starting offset of
 | 
|---|
 | 2079 |    * each shader in the vertex buffer. Create a map of base offsets to mark
 | 
|---|
 | 2080 |    * where the data for the first object using a given shader begins. Also,
 | 
|---|
 | 2081 |    * create a map of current offsets to mark where to copy data for the next
 | 
|---|
 | 2082 |    * object being added.
 | 
|---|
 | 2083 |    */
 | 
|---|
| [646f3f2] | 2084 |    for (shaderCountIt = shaderCounts.begin(); shaderCountIt != shaderCounts.end(); shaderCountIt++) {
 | 
|---|
| [0e0f851] | 2085 |       // When populating the buffers, leave as much empty space as space taken up by existing objects
 | 
|---|
 | 2086 |       // to allow new objects to be added without immediately having to resize the buffers
 | 
|---|
| [646f3f2] | 2087 |       shaderBufferInfo[shaderCountIt->first].ubo_base = lastShaderUboCount * 2;
 | 
|---|
| [0d5c100] | 2088 | 
 | 
|---|
| [646f3f2] | 2089 |       shaderBufferInfo[shaderCountIt->first].ubo_offset = 0;
 | 
|---|
| [c3c3158] | 2090 | 
 | 
|---|
| [646f3f2] | 2091 |       shaderBufferInfo[shaderCountIt->first].ubo_capacity = shaderUboCounts[shaderCountIt->first] * 2;
 | 
|---|
| [0d5c100] | 2092 | 
 | 
|---|
| [646f3f2] | 2093 |       lastShaderCount += shaderCounts[shaderCountIt->first];
 | 
|---|
 | 2094 |       lastShaderUboCount += shaderUboCounts[shaderCountIt->first];
 | 
|---|
| [0d5c100] | 2095 |    }
 | 
|---|
 | 2096 | 
 | 
|---|
| [4c7cd57] | 2097 |    map<ObjectType, ShaderModelGroup>::iterator modelGroupIt;
 | 
|---|
| [a0eb547] | 2098 |    ShaderModelGroup* smg;
 | 
|---|
| [4c7cd57] | 2099 |    for (modelGroupIt = modelGroups.begin(); modelGroupIt != modelGroups.end(); modelGroupIt++) {
 | 
|---|
| [a0eb547] | 2100 |       smg = &modelGroups[modelGroupIt->first];
 | 
|---|
 | 2101 | 
 | 
|---|
 | 2102 |       smg->numPoints = 0;
 | 
|---|
 | 2103 |       smg->vboCapacity = shaderCounts[smg->shaderProgram] * 2;
 | 
|---|
| [a926b79] | 2104 | 
 | 
|---|
| [c55614a] | 2105 |       map<string, AttribInfo>::iterator attrIt;
 | 
|---|
 | 2106 |       for (attrIt = smg->attribs.begin(); attrIt != smg->attribs.end(); attrIt++) {
 | 
|---|
 | 2107 |          if (attrIt->second.attribType != ATTRIB_UNIFORM) {
 | 
|---|
 | 2108 |             glBindBuffer(GL_ARRAY_BUFFER, attrIt->second.buffer);
 | 
|---|
 | 2109 |             glBufferData(GL_ARRAY_BUFFER, smg->vboCapacity * GLsizeof(attrIt->second.type) * attrIt->second.size, NULL, GL_DYNAMIC_DRAW);
 | 
|---|
 | 2110 |          }
 | 
|---|
| [a0eb547] | 2111 |       }
 | 
|---|
| [4c7cd57] | 2112 |    }
 | 
|---|
| [0414306] | 2113 | 
 | 
|---|
| [f97e638] | 2114 |    // Allocate the ubo using the counts calculated above
 | 
|---|
| [0d5c100] | 2115 | 
 | 
|---|
| [c3c3158] | 2116 |    glBindBuffer(GL_UNIFORM_BUFFER, ubo);
 | 
|---|
| [0e0f851] | 2117 |    glBufferData(GL_UNIFORM_BUFFER, num_objects * sizeof(mat4), NULL, GL_DYNAMIC_DRAW);
 | 
|---|
| [0d5c100] | 2118 | 
 | 
|---|
 | 2119 |    for (it = objects.begin(); it != objects.end(); it++) {
 | 
|---|
| [49db5fc] | 2120 |       copyObjectDataToBuffers(**it, shaderBufferInfo, modelGroups, ubo);
 | 
|---|
| [c3c3158] | 2121 |    }
 | 
|---|
 | 2122 | }
 | 
|---|
| [0d5c100] | 2123 | 
 | 
|---|
| [c3c3158] | 2124 | void copyObjectDataToBuffers(SceneObject& obj,
 | 
|---|
 | 2125 |                   map<GLuint, BufferInfo>& shaderBufferInfo,
 | 
|---|
| [0414306] | 2126 |                   map<ObjectType, ShaderModelGroup>& modelGroups,
 | 
|---|
| [49db5fc] | 2127 |                   GLuint ubo) {
 | 
|---|
| [dd9771c] | 2128 |    BufferInfo* bufferInfo = &shaderBufferInfo[modelGroups[obj.type].shaderProgram];
 | 
|---|
| [0d5c100] | 2129 | 
 | 
|---|
| [dc19a39] | 2130 |    obj.vertex_vbo_offset = modelGroups[obj.type].numPoints;
 | 
|---|
| [c3c3158] | 2131 |    obj.ubo_offset = bufferInfo->ubo_base + bufferInfo->ubo_offset;
 | 
|---|
| [0d5c100] | 2132 | 
 | 
|---|
| [dc19a39] | 2133 |    ShaderModelGroup& smg = modelGroups[obj.type];
 | 
|---|
| [0d5c100] | 2134 | 
 | 
|---|
| [dc19a39] | 2135 |    for (map<string, AttribInfo>::iterator it = smg.attribs.begin(); it != smg.attribs.end(); it++) {
 | 
|---|
 | 2136 |       glBindBuffer(GL_ARRAY_BUFFER, it->second.buffer);
 | 
|---|
| [fd6f465] | 2137 | 
 | 
|---|
| [7e10667] | 2138 |       switch (it->second.attribType) {
 | 
|---|
 | 2139 |          case ATTRIB_POINT_VARYING:
 | 
|---|
 | 2140 |             glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * GLsizeof(it->second.type) * it->second.size,
 | 
|---|
 | 2141 |                obj.num_points * GLsizeof(it->second.type) * it->second.size, getVectorAttribPtr(obj, it->second.fieldOffset));
 | 
|---|
 | 2142 |             break;
 | 
|---|
 | 2143 |          case ATTRIB_OBJECT_VARYING:
 | 
|---|
 | 2144 |             for (unsigned int i = 0; i < obj.num_points; i++) {
 | 
|---|
 | 2145 |                glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * GLsizeof(it->second.type) * it->second.size,
 | 
|---|
 | 2146 |                   GLsizeof(it->second.type) * it->second.size, getScalarAttribPtr(obj, it->second.fieldOffset));
 | 
|---|
 | 2147 |             }
 | 
|---|
 | 2148 |             break;
 | 
|---|
 | 2149 |          case ATTRIB_UNIFORM:
 | 
|---|
 | 2150 |             break;
 | 
|---|
| [646f3f2] | 2151 |       }
 | 
|---|
| [dc19a39] | 2152 |    }
 | 
|---|
| [fd6f465] | 2153 | 
 | 
|---|
| [7e10667] | 2154 |    obj.model_mat = obj.model_transform * obj.model_base;
 | 
|---|
| [25b47d7] | 2155 | 
 | 
|---|
| [dc19a39] | 2156 |    glBindBuffer(GL_UNIFORM_BUFFER, ubo);
 | 
|---|
 | 2157 |    glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
 | 
|---|
| [646f3f2] | 2158 | 
 | 
|---|
| [dc19a39] | 2159 |    if (obj.type == TYPE_ASTEROID) {
 | 
|---|
 | 2160 |       glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
 | 
|---|
 | 2161 | 
 | 
|---|
 | 2162 |       ostringstream oss;
 | 
|---|
 | 2163 |       oss << "hp[" << obj.ubo_offset << "]";
 | 
|---|
| [7e10667] | 2164 |       glUniform1f(glGetUniformLocation(modelGroups[TYPE_ASTEROID].shaderProgram, oss.str().c_str()), ((Asteroid&)obj).hp);
 | 
|---|
 | 2165 |    } else if (obj.type == TYPE_EXPLOSION) {
 | 
|---|
 | 2166 |       glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
 | 
|---|
 | 2167 | 
 | 
|---|
 | 2168 |       ostringstream oss;
 | 
|---|
 | 2169 |       oss << "explosion_start_time[" << obj.ubo_offset << "]";
 | 
|---|
 | 2170 |       glUniform1f(glGetUniformLocation(modelGroups[TYPE_EXPLOSION].shaderProgram, oss.str().c_str()), ((ParticleEffect&)obj).startTime);
 | 
|---|
| [25b47d7] | 2171 |    }
 | 
|---|
| [0e0f851] | 2172 | 
 | 
|---|
| [b62c109] | 2173 |    modelGroups[obj.type].numPoints += obj.num_points;
 | 
|---|
| [c3c3158] | 2174 |    bufferInfo->ubo_offset++;
 | 
|---|
| [0d5c100] | 2175 | }
 | 
|---|
| [93462c6] | 2176 | 
 | 
|---|
| [5c403fe] | 2177 | void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo) {
 | 
|---|
| [fabed35] | 2178 |    if (obj.deleted) return;
 | 
|---|
 | 2179 | 
 | 
|---|
| [3d06b4e] | 2180 |    obj.model_transform = transform * obj.model_transform;
 | 
|---|
| [5c403fe] | 2181 |    obj.model_mat = obj.model_transform * obj.model_base;
 | 
|---|
 | 2182 | 
 | 
|---|
| [95595de] | 2183 |    obj.bounding_center = vec3(transform * vec4(obj.bounding_center, 1.0f));
 | 
|---|
 | 2184 | 
 | 
|---|
| [5c403fe] | 2185 |    glBindBuffer(GL_UNIFORM_BUFFER, ubo);
 | 
|---|
 | 2186 |    glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
 | 
|---|
 | 2187 | }
 | 
|---|
 | 2188 | 
 | 
|---|
| [1f3d32b] | 2189 | void translateLaser(Laser* laser, const vec3& translation, GLuint ubo) {
 | 
|---|
| [e9347b4] | 2190 |    // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
 | 
|---|
| [612d1f6] | 2191 |    // and then re-used here
 | 
|---|
 | 2192 | 
 | 
|---|
| [1f3d32b] | 2193 |    vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
 | 2194 |    vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[38], 1.0f));
 | 
|---|
| [612d1f6] | 2195 | 
 | 
|---|
 | 2196 |    vec3 ray = end - start;
 | 
|---|
 | 2197 |    float length = glm::length(ray);
 | 
|---|
 | 2198 | 
 | 
|---|
 | 2199 |    float xAxisRotation = asin(ray.y / length);
 | 
|---|
 | 2200 |    float yAxisRotation = atan2(-ray.x, -ray.z);
 | 
|---|
 | 2201 | 
 | 
|---|
 | 2202 |    vec3 normal(rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) *
 | 
|---|
 | 2203 |       rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) *
 | 
|---|
 | 2204 |       vec4(0.0f, 1.0f, 0.0f, 1.0f));
 | 
|---|
 | 2205 | 
 | 
|---|
 | 2206 |    // To project point P onto line AB:
 | 
|---|
 | 2207 |    // projection = A + dot(AP,AB) / dot(AB,AB) * AB
 | 
|---|
 | 2208 |    vec3 projOnLaser = start + glm::dot(cam_pos - start, ray) / (length*length) * ray;
 | 
|---|
 | 2209 |    vec3 laserToCam = cam_pos - projOnLaser;
 | 
|---|
 | 2210 | 
 | 
|---|
 | 2211 |    float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
 | 
|---|
 | 2212 | 
 | 
|---|
| [1f3d32b] | 2213 |    laser->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
 | 
|---|
| [612d1f6] | 2214 | 
 | 
|---|
| [1f3d32b] | 2215 |    transformObject(*laser, translate(mat4(1.0f), translation), ubo);
 | 
|---|
| [612d1f6] | 2216 | }
 | 
|---|
 | 2217 | 
 | 
|---|
| [a0eb547] | 2218 | void updateLaserTarget(Laser* laser, vector<SceneObject*>& objects, ShaderModelGroup& laserSmg, GLuint asteroid_sp) {
 | 
|---|
| [e9347b4] | 2219 |    // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
 | 
|---|
 | 2220 |    // and then re-used here
 | 
|---|
 | 2221 | 
 | 
|---|
| [1f3d32b] | 2222 |    vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
 | 
|---|
 | 2223 |    vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[2] + laser->points[20], 1.0f));
 | 
|---|
| [e9347b4] | 2224 | 
 | 
|---|
 | 2225 |    vec3 intersection(0.0f), closestIntersection(0.0f);
 | 
|---|
| [1f3d32b] | 2226 |    Asteroid* closestAsteroid = NULL;
 | 
|---|
| [e9347b4] | 2227 | 
 | 
|---|
| [1f3d32b] | 2228 |    for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
 | 
|---|
 | 2229 |       if ((*it)->type == TYPE_ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {
 | 
|---|
| [e9347b4] | 2230 |          // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points
 | 
|---|
 | 2231 |          if (closestAsteroid == NULL || intersection.z > closestIntersection.z) {
 | 
|---|
 | 2232 |             // TODO: At this point, find the real intersection of the laser with one of the asteroid's sides
 | 
|---|
| [1f3d32b] | 2233 |             closestAsteroid = (Asteroid*)*it;
 | 
|---|
| [e9347b4] | 2234 |             closestIntersection = intersection;
 | 
|---|
 | 2235 |          }
 | 
|---|
 | 2236 |       }
 | 
|---|
 | 2237 |    }
 | 
|---|
 | 2238 | 
 | 
|---|
| [1f3d32b] | 2239 |    float width = laser->points[0] - laser->points[2];
 | 
|---|
 | 2240 | 
 | 
|---|
 | 2241 |    if (laser->targetAsteroid != closestAsteroid) {
 | 
|---|
 | 2242 |       if (laser->targetAsteroid != NULL) {
 | 
|---|
 | 2243 |          if (laser == leftLaser) {
 | 
|---|
 | 2244 |             leftLaserEffect->deleted = true;
 | 
|---|
 | 2245 |          } else if (laser == rightLaser) {
 | 
|---|
 | 2246 |             rightLaserEffect->deleted = true;
 | 
|---|
 | 2247 |          }
 | 
|---|
 | 2248 |       }
 | 
|---|
 | 2249 | 
 | 
|---|
 | 2250 |       EffectOverTime* eot = NULL;
 | 
|---|
| [e9347b4] | 2251 | 
 | 
|---|
| [1f3d32b] | 2252 |       if (closestAsteroid != NULL) {
 | 
|---|
| [25b47d7] | 2253 |          eot = new EffectOverTime(closestAsteroid->hp, -20.0f, closestAsteroid);
 | 
|---|
| [1f3d32b] | 2254 |          effects.push_back(eot);
 | 
|---|
 | 2255 |       }
 | 
|---|
 | 2256 | 
 | 
|---|
 | 2257 |       if (laser == leftLaser) {
 | 
|---|
 | 2258 |          leftLaserEffect = eot;
 | 
|---|
 | 2259 |       } else if (laser == rightLaser) {
 | 
|---|
 | 2260 |          rightLaserEffect = eot;
 | 
|---|
 | 2261 |       }
 | 
|---|
 | 2262 |    }
 | 
|---|
 | 2263 |    laser->targetAsteroid = closestAsteroid;
 | 
|---|
 | 2264 | 
 | 
|---|
 | 2265 |    float length = 5.24f; // I think this was to make sure the laser went past the end of the screen
 | 
|---|
| [e9347b4] | 2266 |    if (closestAsteroid != NULL) {
 | 
|---|
 | 2267 |       length = glm::length(closestIntersection - start);
 | 
|---|
| [0e0f851] | 2268 | 
 | 
|---|
| [a0eb547] | 2269 |       // TODO: Find a more generic way of updating the asteroid hp than in updateLaserTarget
 | 
|---|
| [0e0f851] | 2270 | 
 | 
|---|
 | 2271 |       glUseProgram(asteroid_sp);
 | 
|---|
| [25b47d7] | 2272 | 
 | 
|---|
 | 2273 |       ostringstream oss;
 | 
|---|
 | 2274 |       oss << "hp[" << closestAsteroid->ubo_offset << "]";
 | 
|---|
 | 2275 |       glUniform1f(glGetUniformLocation(asteroid_sp, oss.str().c_str()), closestAsteroid->hp);
 | 
|---|
| [e9347b4] | 2276 |    }
 | 
|---|
 | 2277 | 
 | 
|---|
| [1f3d32b] | 2278 |    laser->points[20] = -length + width / 2;
 | 
|---|
 | 2279 |    laser->points[23] = -length + width / 2;
 | 
|---|
 | 2280 |    laser->points[29] = -length + width / 2;
 | 
|---|
 | 2281 |    laser->points[38] = -length;
 | 
|---|
 | 2282 |    laser->points[41] = -length;
 | 
|---|
 | 2283 |    laser->points[44] = -length + width / 2;
 | 
|---|
 | 2284 |    laser->points[47] = -length;
 | 
|---|
 | 2285 |    laser->points[50] = -length + width / 2;
 | 
|---|
 | 2286 |    laser->points[53] = -length + width / 2;
 | 
|---|
| [e9347b4] | 2287 | 
 | 
|---|
| [a0eb547] | 2288 |    AttribInfo* attrib = &laserSmg.attribs["vertex_position"];
 | 
|---|
 | 2289 |    glBindBuffer(GL_ARRAY_BUFFER, attrib->buffer);
 | 
|---|
 | 2290 |    glBufferSubData(GL_ARRAY_BUFFER, laser->vertex_vbo_offset * GLsizeof(attrib->type) * attrib->size,
 | 
|---|
 | 2291 |       laser->num_points * GLsizeof(attrib->type) * attrib->size, getVectorAttribPtr(*laser, attrib->fieldOffset));
 | 
|---|
| [e9347b4] | 2292 | }
 | 
|---|
 | 2293 | 
 | 
|---|
 | 2294 | bool getLaserAndAsteroidIntersection(vec3& start, vec3& end, SceneObject& asteroid, vec3& intersection) {
 | 
|---|
 | 2295 |    /*
 | 
|---|
 | 2296 |    ### LINE EQUATIONS ###
 | 
|---|
 | 2297 |    x = x1 + u * (x2 - x1)
 | 
|---|
 | 2298 |    y = y1 + u * (y2 - y1)
 | 
|---|
 | 2299 |    z = z1 + u * (z2 - z1)
 | 
|---|
 | 2300 | 
 | 
|---|
 | 2301 |    ### SPHERE EQUATION ###
 | 
|---|
 | 2302 |    (x - x3)^2 + (y - y3)^2 + (z - z3)^2 = r^2
 | 
|---|
 | 2303 | 
 | 
|---|
 | 2304 |    ### QUADRATIC EQUATION TO SOLVE ###
 | 
|---|
 | 2305 |    a*u^2 + b*u + c = 0
 | 
|---|
 | 2306 |    WHERE THE CONSTANTS ARE
 | 
|---|
 | 2307 |    a = (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2
 | 
|---|
 | 2308 |    b = 2*( (x2 - x1)*(x1 - x3) + (y2 - y1)*(y1 - y3) + (z2 - z1)*(z1 - z3) )
 | 
|---|
 | 2309 |    c = x3^2 + y3^2 + z3^2 + x1^2 + y1^2 + z1^2 - 2(x3*x1 + y3*y1 + z3*z1) - r^2
 | 
|---|
 | 2310 | 
 | 
|---|
 | 2311 |    u = (-b +- sqrt(b^2 - 4*a*c)) / 2a
 | 
|---|
 | 2312 | 
 | 
|---|
 | 2313 |    If the value under the root is >= 0, we got an intersection
 | 
|---|
 | 2314 |    If the value > 0, there are two solutions. Take the one closer to 0, since that's the
 | 
|---|
 | 2315 |    one closer to the laser start point
 | 
|---|
 | 2316 |    */
 | 
|---|
 | 2317 | 
 | 
|---|
 | 2318 |    vec3& center = asteroid.bounding_center;
 | 
|---|
 | 2319 | 
 | 
|---|
 | 2320 |    float a = pow(end.x-start.x, 2) + pow(end.y-start.y, 2) + pow(end.z-start.z, 2);
 | 
|---|
 | 2321 |    float b = 2*((start.x-end.x)*(start.x-center.x) + (end.y-start.y)*(start.y-center.y) + (end.z-start.z)*(start.z-center.z));
 | 
|---|
 | 2322 |    float c = pow(center.x, 2) + pow(center.y, 2) + pow(center.z, 2) + pow(start.x, 2) + pow(start.y, 2) + pow(start.z, 2) - 2*(center.x*start.x + center.y*start.y + center.z*start.z) - pow(asteroid.bounding_radius, 2);
 | 
|---|
 | 2323 |    float discriminant = pow(b, 2) - 4*a*c;
 | 
|---|
 | 2324 | 
 | 
|---|
 | 2325 |    if (discriminant >= 0.0f) {
 | 
|---|
 | 2326 |       // In this case, the negative root will always give the point closer to the laser start point
 | 
|---|
 | 2327 |       float u = (-b - sqrt(discriminant)) / (2 * a);
 | 
|---|
 | 2328 | 
 | 
|---|
 | 2329 |       // Check that the intersection is within the line segment corresponding to the laser
 | 
|---|
 | 2330 |       if (0.0f <= u && u <= 1.0f) {
 | 
|---|
 | 2331 |          intersection = start + u * (end - start);
 | 
|---|
 | 2332 |          return true;
 | 
|---|
 | 2333 |       }
 | 
|---|
 | 2334 |    }
 | 
|---|
 | 2335 | 
 | 
|---|
 | 2336 |    return false;
 | 
|---|
 | 2337 | }
 | 
|---|
 | 2338 | 
 | 
|---|
| [7e10667] | 2339 | void renderScene(map<ObjectType, ShaderModelGroup>& modelGroups, GLuint ubo) {
 | 
|---|
| [93462c6] | 2340 | 
 | 
|---|
| [4c7cd57] | 2341 |    glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
 | 
|---|
 | 2342 |    glBindVertexArray(modelGroups[TYPE_SHIP].vao);
 | 
|---|
| [93462c6] | 2343 | 
 | 
|---|
| [a926b79] | 2344 |    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_SHIP].numPoints);
 | 
|---|
| [93462c6] | 2345 | 
 | 
|---|
| [0414306] | 2346 |    glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
 | 
|---|
 | 2347 |    glBindVertexArray(modelGroups[TYPE_ASTEROID].vao);
 | 
|---|
| [0e0f851] | 2348 | 
 | 
|---|
| [14e6918] | 2349 |    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_ASTEROID].numPoints);
 | 
|---|
| [0e0f851] | 2350 | 
 | 
|---|
| [9f9f9a7] | 2351 |    glEnable(GL_BLEND);
 | 
|---|
 | 2352 | 
 | 
|---|
| [b62c109] | 2353 |    glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
 | 
|---|
 | 2354 |    glBindVertexArray(modelGroups[TYPE_LASER].vao);
 | 
|---|
| [b155f13] | 2355 | 
 | 
|---|
| [a9d191a] | 2356 |    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_LASER].numPoints);
 | 
|---|
| [9f9f9a7] | 2357 | 
 | 
|---|
| [0414306] | 2358 |    glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
 | 
|---|
 | 2359 |    glBindVertexArray(modelGroups[TYPE_EXPLOSION].vao);
 | 
|---|
| [db06984] | 2360 | 
 | 
|---|
 | 2361 |    glEnable(GL_PROGRAM_POINT_SIZE);
 | 
|---|
 | 2362 | 
 | 
|---|
| [0414306] | 2363 |    glDrawArrays(GL_POINTS, 0, modelGroups[TYPE_EXPLOSION].numPoints);
 | 
|---|
| [db06984] | 2364 | 
 | 
|---|
 | 2365 |    glDisable(GL_PROGRAM_POINT_SIZE);
 | 
|---|
 | 2366 |    glDisable(GL_BLEND);
 | 
|---|
| [b155f13] | 2367 | }
 | 
|---|
 | 2368 | 
 | 
|---|
| [c4c205e] | 2369 | void renderSceneGui(map<string, vector<UIValue>> valueLists) {
 | 
|---|
| [c1ca5b5] | 2370 |    ImGui_ImplGlfwGL3_NewFrame();
 | 
|---|
 | 2371 | 
 | 
|---|
 | 2372 |    // 1. Show a simple window.
 | 
|---|
 | 2373 |    // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
 | 
|---|
| [5b3462b] | 2374 |    /*
 | 
|---|
| [c1ca5b5] | 2375 |    {
 | 
|---|
 | 2376 |       static float f = 0.0f;
 | 
|---|
 | 2377 |       static int counter = 0;
 | 
|---|
 | 2378 |       ImGui::Text("Hello, world!");                           // Display some text (you can use a format string too)
 | 
|---|
 | 2379 |       ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f    
 | 
|---|
 | 2380 |       ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
 | 
|---|
 | 2381 | 
 | 
|---|
 | 2382 |       ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our windows open/close state
 | 
|---|
 | 2383 |       ImGui::Checkbox("Another Window", &show_another_window);
 | 
|---|
 | 2384 | 
 | 
|---|
 | 2385 |       if (ImGui::Button("Button"))                            // Buttons return true when clicked (NB: most widgets return true when edited/activated)
 | 
|---|
 | 2386 |          counter++;
 | 
|---|
 | 2387 |       ImGui::SameLine();
 | 
|---|
 | 2388 |       ImGui::Text("counter = %d", counter);
 | 
|---|
 | 2389 | 
 | 
|---|
 | 2390 |       ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
 | 
|---|
 | 2391 |    }
 | 
|---|
| [5b3462b] | 2392 |    */
 | 
|---|
| [c1ca5b5] | 2393 | 
 | 
|---|
| [5b3462b] | 2394 |    {
 | 
|---|
| [1f3d32b] | 2395 |       ImGui::SetNextWindowSize(ImVec2(95, 46), ImGuiCond_Once);
 | 
|---|
| [5b3462b] | 2396 |       ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once);
 | 
|---|
| [f0cc877] | 2397 |       ImGui::Begin("WndStats", NULL,
 | 
|---|
 | 2398 |          ImGuiWindowFlags_NoTitleBar |
 | 
|---|
 | 2399 |          ImGuiWindowFlags_NoResize |
 | 
|---|
 | 2400 |          ImGuiWindowFlags_NoMove);
 | 
|---|
| [c4c205e] | 2401 | 
 | 
|---|
 | 2402 |       renderGuiValueList(valueLists["stats value list"]);
 | 
|---|
 | 2403 | 
 | 
|---|
| [c1ca5b5] | 2404 |       ImGui::End();
 | 
|---|
 | 2405 |    }
 | 
|---|
 | 2406 | 
 | 
|---|
| [5b3462b] | 2407 |    {
 | 
|---|
 | 2408 |       ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once);
 | 
|---|
| [c4c205e] | 2409 |       ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once);
 | 
|---|
| [f0cc877] | 2410 |       ImGui::Begin("WndMenubar", NULL,
 | 
|---|
 | 2411 |          ImGuiWindowFlags_NoTitleBar |
 | 
|---|
| [5b3462b] | 2412 |          ImGuiWindowFlags_NoResize |
 | 
|---|
 | 2413 |          ImGuiWindowFlags_NoMove);
 | 
|---|
| [93462c6] | 2414 |       ImGui::InvisibleButton("", ImVec2(155, 18));
 | 
|---|
| [5b3462b] | 2415 |       ImGui::SameLine();
 | 
|---|
| [93462c6] | 2416 |       if (ImGui::Button("Main Menu")) {
 | 
|---|
 | 2417 |          events.push(EVENT_GO_TO_MAIN_MENU);
 | 
|---|
| [5b3462b] | 2418 |       }
 | 
|---|
 | 2419 |       ImGui::End();
 | 
|---|
| [c1ca5b5] | 2420 |    }
 | 
|---|
 | 2421 | 
 | 
|---|
| [c4c205e] | 2422 |    {
 | 
|---|
 | 2423 |       ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_Once);
 | 
|---|
 | 2424 |       ImGui::SetNextWindowPos(ImVec2(430, 60), ImGuiCond_Once);
 | 
|---|
 | 2425 |       ImGui::Begin("WndDebug", NULL,
 | 
|---|
 | 2426 |          ImGuiWindowFlags_NoTitleBar |
 | 
|---|
 | 2427 |          ImGuiWindowFlags_NoResize |
 | 
|---|
 | 2428 |          ImGuiWindowFlags_NoMove);
 | 
|---|
 | 2429 | 
 | 
|---|
 | 2430 |       renderGuiValueList(valueLists["debug value list"]);
 | 
|---|
 | 2431 | 
 | 
|---|
 | 2432 |       ImGui::End();
 | 
|---|
 | 2433 |    }
 | 
|---|
 | 2434 | 
 | 
|---|
| [93462c6] | 2435 |    ImGui::Render();
 | 
|---|
 | 2436 |    ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
 | 
|---|
 | 2437 | }
 | 
|---|
 | 2438 | 
 | 
|---|
 | 2439 | void renderMainMenu() {
 | 
|---|
 | 2440 | }
 | 
|---|
 | 2441 | 
 | 
|---|
 | 2442 | void renderMainMenuGui() {
 | 
|---|
 | 2443 |    ImGui_ImplGlfwGL3_NewFrame();
 | 
|---|
 | 2444 | 
 | 
|---|
| [f0cc877] | 2445 |    {
 | 
|---|
 | 2446 |       int padding = 4;
 | 
|---|
 | 2447 |       ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once);
 | 
|---|
| [e6bc0f4] | 2448 |       ImGui::SetNextWindowSize(ImVec2(windowWidth + 2 * padding, windowHeight + 2 * padding), ImGuiCond_Always);
 | 
|---|
| [f0cc877] | 2449 |       ImGui::Begin("WndMain", NULL,
 | 
|---|
 | 2450 |          ImGuiWindowFlags_NoTitleBar |
 | 
|---|
 | 2451 |          ImGuiWindowFlags_NoResize |
 | 
|---|
 | 2452 |          ImGuiWindowFlags_NoMove);
 | 
|---|
| [93462c6] | 2453 | 
 | 
|---|
 | 2454 |       ImGui::InvisibleButton("", ImVec2(10, 80));
 | 
|---|
 | 2455 |       ImGui::InvisibleButton("", ImVec2(285, 18));
 | 
|---|
 | 2456 |       ImGui::SameLine();
 | 
|---|
 | 2457 |       if (ImGui::Button("New Game")) {
 | 
|---|
 | 2458 |          events.push(EVENT_GO_TO_GAME);
 | 
|---|
 | 2459 |       }
 | 
|---|
 | 2460 | 
 | 
|---|
 | 2461 |       ImGui::InvisibleButton("", ImVec2(10, 15));
 | 
|---|
 | 2462 |       ImGui::InvisibleButton("", ImVec2(300, 18));
 | 
|---|
 | 2463 |       ImGui::SameLine();
 | 
|---|
 | 2464 |       if (ImGui::Button("Quit")) {
 | 
|---|
 | 2465 |          events.push(EVENT_QUIT);
 | 
|---|
 | 2466 |       }
 | 
|---|
 | 2467 | 
 | 
|---|
| [f0cc877] | 2468 |       ImGui::End();
 | 
|---|
 | 2469 |    }
 | 
|---|
 | 2470 | 
 | 
|---|
| [c1ca5b5] | 2471 |    ImGui::Render();
 | 
|---|
 | 2472 |    ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
 | 
|---|
 | 2473 | }
 | 
|---|
| [cf2d1e5] | 2474 | 
 | 
|---|
| [a9d191a] | 2475 | void initGuiValueLists(map<string, vector<UIValue>> valueLists) {
 | 
|---|
 | 2476 |    valueLists["stats value list"] = vector<UIValue>();
 | 
|---|
 | 2477 |    valueLists["debug value list"] = vector<UIValue>();
 | 
|---|
 | 2478 | }
 | 
|---|
 | 2479 | 
 | 
|---|
| [c4c205e] | 2480 | void renderGuiValueList(vector<UIValue>& values) {
 | 
|---|
 | 2481 |    float maxWidth = 0.0f;
 | 
|---|
 | 2482 |    float cursorStartPos = ImGui::GetCursorPosX();
 | 
|---|
 | 2483 | 
 | 
|---|
 | 2484 |    for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) {
 | 
|---|
 | 2485 |       float textWidth = ImGui::CalcTextSize(it->label.c_str()).x;
 | 
|---|
 | 2486 | 
 | 
|---|
 | 2487 |       if (maxWidth < textWidth)
 | 
|---|
 | 2488 |          maxWidth = textWidth;
 | 
|---|
 | 2489 |    }
 | 
|---|
 | 2490 | 
 | 
|---|
 | 2491 |    stringstream ss;
 | 
|---|
 | 2492 | 
 | 
|---|
 | 2493 |    for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) {
 | 
|---|
 | 2494 |       ss.str("");
 | 
|---|
 | 2495 |       ss.clear();
 | 
|---|
 | 2496 | 
 | 
|---|
 | 2497 |       switch (it->type) {
 | 
|---|
 | 2498 |          case UIVALUE_INT:
 | 
|---|
 | 2499 |             ss << it->label << ": " << *(unsigned int*)it->value;
 | 
|---|
 | 2500 |             break;
 | 
|---|
 | 2501 |          case UIVALUE_DOUBLE:
 | 
|---|
 | 2502 |             ss << it->label << ": " << *(double*)it->value;
 | 
|---|
 | 2503 |             break;
 | 
|---|
 | 2504 |       }
 | 
|---|
 | 2505 | 
 | 
|---|
 | 2506 |       float textWidth = ImGui::CalcTextSize(it->label.c_str()).x;
 | 
|---|
 | 2507 | 
 | 
|---|
 | 2508 |       ImGui::SetCursorPosX(cursorStartPos + maxWidth - textWidth);
 | 
|---|
 | 2509 |       ImGui::Text("%s", ss.str().c_str());
 | 
|---|
 | 2510 |    }
 | 
|---|
 | 2511 | }
 | 
|---|
 | 2512 | 
 | 
|---|
| [dd9771c] | 2513 | Asteroid* createAsteroid(vec3 pos) {
 | 
|---|
| [1f3d32b] | 2514 |    Asteroid* obj = new Asteroid();
 | 
|---|
 | 2515 |    obj->type = TYPE_ASTEROID;
 | 
|---|
| [646f3f2] | 2516 |    obj->hp = 10.0f;
 | 
|---|
| [cf2d1e5] | 2517 | 
 | 
|---|
| [1f3d32b] | 2518 |    obj->points = {
 | 
|---|
| [cf2d1e5] | 2519 |       // front
 | 
|---|
 | 2520 |       1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2521 |       -1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2522 |       -1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2523 |       1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2524 |       -1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2525 |       1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2526 | 
 | 
|---|
 | 2527 |       // top
 | 
|---|
 | 2528 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2529 |       -1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2530 |       -1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2531 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2532 |       -1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2533 |       1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2534 | 
 | 
|---|
 | 2535 |       // bottom
 | 
|---|
 | 2536 |       1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2537 |       -1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2538 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2539 |       1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2540 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2541 |       1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2542 | 
 | 
|---|
 | 2543 |       // back
 | 
|---|
 | 2544 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2545 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2546 |       -1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2547 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2548 |       1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2549 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2550 | 
 | 
|---|
 | 2551 |       // right
 | 
|---|
 | 2552 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2553 |       1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2554 |       1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2555 |       1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2556 |       1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2557 |       1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2558 | 
 | 
|---|
 | 2559 |       // left
 | 
|---|
 | 2560 |       -1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2561 |       -1.0f,  1.0f, -1.0f,
 | 
|---|
 | 2562 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2563 |       -1.0f,  1.0f,  1.0f,
 | 
|---|
 | 2564 |       -1.0f, -1.0f, -1.0f,
 | 
|---|
 | 2565 |       -1.0f, -1.0f,  1.0f,
 | 
|---|
 | 2566 |    };
 | 
|---|
| [1f3d32b] | 2567 |    obj->colors = {
 | 
|---|
| [cf2d1e5] | 2568 |       // front
 | 
|---|
| [25b47d7] | 2569 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2570 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2571 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2572 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2573 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2574 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2575 | 
 | 
|---|
 | 2576 |       // top
 | 
|---|
| [25b47d7] | 2577 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2578 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2579 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2580 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2581 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2582 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2583 | 
 | 
|---|
 | 2584 |       // bottom
 | 
|---|
| [25b47d7] | 2585 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2586 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2587 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2588 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2589 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2590 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2591 | 
 | 
|---|
 | 2592 |       // back
 | 
|---|
| [25b47d7] | 2593 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2594 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2595 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2596 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2597 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2598 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2599 | 
 | 
|---|
 | 2600 |       // right
 | 
|---|
| [25b47d7] | 2601 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2602 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2603 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2604 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2605 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2606 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2607 | 
 | 
|---|
 | 2608 |       // left
 | 
|---|
| [25b47d7] | 2609 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2610 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2611 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2612 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2613 |       0.4f, 0.4f, 0.4f,
 | 
|---|
 | 2614 |       0.4f, 0.4f, 0.4f,
 | 
|---|
| [cf2d1e5] | 2615 |    };
 | 
|---|
| [1f3d32b] | 2616 |    obj->texcoords = { 0.0f };
 | 
|---|
| [cf2d1e5] | 2617 | 
 | 
|---|
| [dba67b2] | 2618 |    mat4 T = translate(mat4(1.0f), pos);
 | 
|---|
 | 2619 |    mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));
 | 
|---|
| [1f3d32b] | 2620 |    obj->model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
 | 
|---|
| [cf2d1e5] | 2621 | 
 | 
|---|
| [1f3d32b] | 2622 |    obj->translate_mat = T;
 | 
|---|
| [95595de] | 2623 | 
 | 
|---|
| [8316333] | 2624 |    initObject(obj);
 | 
|---|
| [e9347b4] | 2625 |    // This accounts for the scaling in model_base.
 | 
|---|
 | 2626 |    // Dividing by 8 instead of 10 since the bounding radius algorithm
 | 
|---|
 | 2627 |    // under-calculates the true value.
 | 
|---|
 | 2628 |    // TODO: Once the intersection check with the sides of the asteroid is done,
 | 
|---|
 | 2629 |    // this can be removed.
 | 
|---|
| [1f3d32b] | 2630 |    obj->bounding_radius /= 8.0f;
 | 
|---|
 | 2631 | 
 | 
|---|
 | 2632 |    return obj;
 | 
|---|
| [cf2d1e5] | 2633 | }
 | 
|---|
| [5527206] | 2634 | 
 | 
|---|
| [7e10667] | 2635 | // TODO: Maybe pass in startTime instead of calling glfwGetTime() here
 | 
|---|
 | 2636 | ParticleEffect* createExplosion(mat4 model_mat) {
 | 
|---|
| [dc19a39] | 2637 |    ParticleEffect* obj = new ParticleEffect();
 | 
|---|
| [646f3f2] | 2638 | 
 | 
|---|
| [7e10667] | 2639 |    obj->type = TYPE_EXPLOSION;
 | 
|---|
| [646f3f2] | 2640 | 
 | 
|---|
 | 2641 |    initObject(obj);
 | 
|---|
| [7e10667] | 2642 | 
 | 
|---|
| [646f3f2] | 2643 |    obj->num_points = EXPLOSION_PARTICLE_COUNT;
 | 
|---|
| [7e10667] | 2644 |    obj->model_base = model_mat;
 | 
|---|
 | 2645 |    obj->startTime = glfwGetTime();
 | 
|---|
 | 2646 |    obj->duration = 0.5f; // This is also hard-coded in the shader. TODO; Pass this to the shader in an indexable ubo.
 | 
|---|
 | 2647 | 
 | 
|---|
 | 2648 |    obj->particleVelocities.clear();
 | 
|---|
 | 2649 |    obj->particleTimes.clear();
 | 
|---|
 | 2650 |    float t_accum = 0.0f; // start time
 | 
|---|
 | 2651 | 
 | 
|---|
 | 2652 |    for (int i = 0; i < EXPLOSION_PARTICLE_COUNT; i++) {
 | 
|---|
 | 2653 |       obj->particleTimes.push_back(t_accum);
 | 
|---|
 | 2654 |       t_accum += 0.01f;
 | 
|---|
 | 2655 | 
 | 
|---|
 | 2656 |       float randx = ((float)rand() / (float)RAND_MAX) - 0.5f;
 | 
|---|
 | 2657 |       float randy = ((float)rand() / (float)RAND_MAX) - 0.5f;
 | 
|---|
 | 2658 |       obj->particleVelocities.push_back(randx);
 | 
|---|
 | 2659 |       obj->particleVelocities.push_back(randy);
 | 
|---|
 | 2660 |       obj->particleVelocities.push_back(0.0f);
 | 
|---|
 | 2661 |    }
 | 
|---|
| [646f3f2] | 2662 | 
 | 
|---|
 | 2663 |    return obj;
 | 
|---|
 | 2664 | }
 | 
|---|
 | 2665 | 
 | 
|---|
| [5527206] | 2666 | float getRandomNum(float low, float high) {
 | 
|---|
| [b220f78] | 2667 |    return low + ((float)rand() / RAND_MAX) * (high-low);
 | 
|---|
| [8e8aed6] | 2668 | }
 | 
|---|