source: opengl-game/new-game.cpp@ 2b0214c

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

-Comment out the code for showing selected objects in a different color
-Increase the damage lasers deal to asteroids
-Remove asteroids from the scene when they're destroyed

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