source: opengl-game/new-game.cpp@ 3d96d13

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

Merge branch 'master' of medievaltech.com:opengl-game

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