source: opengl-game/new-game.cpp@ 1e3dddf

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

Display an actual score, which gets incremented every time the player destroys an asteroid.

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