source: opengl-game/new-game.cpp@ 7a55b49

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

Create the ShaderModelGroup struct and start moving info required for rendering explosions into an instance of it

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