source: opengl-game/new-game.cpp@ dd9771c

feature/imgui-sdl points-test
Last change on this file since dd9771c was dd9771c, checked in by Dmitry Portnoy <dmp1488@…>, 6 years ago

Remove SceneObject.shader_program and use the object type to get the shader program from the ShaderModelGroup map instead

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