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

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

-Dynamically allocate SceneObjectsto make it easier to support subclassing
them
-Create Asteroid and Laser subclasses
-Implement a system to allow arbitrary changes to values over time
-Use this system to deal damage to asteroids whenever a laser is focused
on them

  • Property mode set to 100644
File size: 71.2 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 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
461 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
462
463 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
464 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
465
466 GLuint texture_vao = 0;
467 glGenVertexArrays(1, &texture_vao);
468 glBindVertexArray(texture_vao);
469
470 glEnableVertexAttribArray(0);
471 glEnableVertexAttribArray(1);
472 glEnableVertexAttribArray(2);
473 glEnableVertexAttribArray(3);
474
475 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
476 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
477
478 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
479 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
480
481 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
482 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
483
484 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
485 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
486
487 GLuint laser_vao = 0;
488 glGenVertexArrays(1, &laser_vao);
489 glBindVertexArray(laser_vao);
490
491 glEnableVertexAttribArray(0);
492 glEnableVertexAttribArray(1);
493 glEnableVertexAttribArray(2);
494
495 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
496 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
497
498 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
499 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
500
501 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
502 glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, 0, 0);
503
504 float cam_speed = 1.0f;
505 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
506 float cam_pitch_speed = 60.0f*ONE_DEG_IN_RAD;
507
508 // glm::lookAt can create the view matrix
509 // glm::perspective can create the projection matrix
510
511 mat4 T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
512 mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
513 mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
514 mat4 R = pitch_mat * yaw_mat;
515 view_mat = R*T;
516
517 // TODO: Create a function to construct the projection matrix
518 // (Maybe I should just use glm::perspective, after making sure it matches what I have now)
519 float fov = 67.0f * ONE_DEG_IN_RAD;
520 float aspect = (float)width / (float)height;
521
522 float range = tan(fov * 0.5f) * NEAR_CLIP;
523 float Sx = NEAR_CLIP / (range * aspect);
524 float Sy = NEAR_CLIP / range;
525 float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
526 float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
527
528 float proj_arr[] = {
529 Sx, 0.0f, 0.0f, 0.0f,
530 0.0f, Sy, 0.0f, 0.0f,
531 0.0f, 0.0f, Sz, -1.0f,
532 0.0f, 0.0f, Pz, 0.0f,
533 };
534 proj_mat = make_mat4(proj_arr);
535
536 GLuint ub_binding_point = 0;
537
538 // TODO: Replace test_loc and mat_loc with more descriptive names
539 GLuint view_test_loc = glGetUniformLocation(color_sp, "view");
540 GLuint proj_test_loc = glGetUniformLocation(color_sp, "proj");
541 GLuint color_sp_ub_index = glGetUniformBlockIndex(color_sp, "models");
542
543 GLuint view_mat_loc = glGetUniformLocation(texture_sp, "view");
544 GLuint proj_mat_loc = glGetUniformLocation(texture_sp, "proj");
545 GLuint texture_sp_ub_index = glGetUniformBlockIndex(texture_sp, "models");
546
547 GLuint laser_view_mat_loc = glGetUniformLocation(laser_sp, "view");
548 GLuint laser_proj_mat_loc = glGetUniformLocation(laser_sp, "proj");
549 GLuint laser_color_loc = glGetUniformLocation(laser_sp, "laser_color");
550 GLuint laser_sp_ub_index = glGetUniformBlockIndex(laser_sp, "models");
551
552
553 glUseProgram(color_sp);
554 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
555 glUniformMatrix4fv(proj_test_loc, 1, GL_FALSE, value_ptr(proj_mat));
556
557 glUniformBlockBinding(color_sp, color_sp_ub_index, ub_binding_point);
558 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
559
560
561 glUseProgram(texture_sp);
562 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
563 glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
564
565 glUniformBlockBinding(texture_sp, texture_sp_ub_index, ub_binding_point);
566 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
567
568
569 glUseProgram(laser_sp);
570 glUniformMatrix4fv(laser_view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
571 glUniformMatrix4fv(laser_proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
572 glUniform3f(laser_color_loc, 0.2f, 1.0f, 0.2f);
573
574 glUniformBlockBinding(laser_sp, laser_sp_ub_index, ub_binding_point);
575 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
576
577
578 bool cam_moved = false;
579
580 int frame_count = 0;
581 double elapsed_seconds_fps = 0.0f;
582 double elapsed_seconds_spawn = 0.0f;
583 double previous_seconds = glfwGetTime();
584
585 // This draws wireframes. Useful for seeing separate faces and occluded objects.
586 //glPolygonMode(GL_FRONT, GL_LINE);
587
588 // disable vsync to see real framerate
589 //glfwSwapInterval(0);
590
591 State curState = STATE_MAIN_MENU;
592
593 while (!glfwWindowShouldClose(window) && isRunning) {
594 double current_seconds = glfwGetTime();
595 double elapsed_seconds = current_seconds - previous_seconds;
596 previous_seconds = current_seconds;
597
598 elapsed_seconds_fps += elapsed_seconds;
599 if (elapsed_seconds_fps > 0.25f) {
600 fps = (double)frame_count / elapsed_seconds_fps;
601
602 frame_count = 0;
603 elapsed_seconds_fps = 0.0f;
604 }
605
606 frame_count++;
607
608 // Handle events
609
610 clickedObject = NULL;
611
612 // reset the all key states to KEY_STATE_UNCHANGED (something the GLFW key callback can never return)
613 // so that GLFW_PRESS and GLFW_RELEASE are only detected once
614 // TODO: Change this if we ever need to act on GLFW_REPEAT (which is when a key is held down
615 // continuously for a period of time)
616 fill(key_state, key_state + NUM_KEYS, KEY_STATE_UNCHANGED);
617
618 glfwPollEvents();
619
620 while (!events.empty()) {
621 switch (events.front()) {
622 case EVENT_GO_TO_MAIN_MENU:
623 curState = STATE_MAIN_MENU;
624 break;
625 case EVENT_GO_TO_GAME:
626 curState = STATE_GAME;
627 break;
628 case EVENT_QUIT:
629 isRunning = false;
630 break;
631 }
632 events.pop();
633 }
634
635 if (curState == STATE_GAME) {
636
637 elapsed_seconds_spawn += elapsed_seconds;
638 if (elapsed_seconds_spawn > 0.5f) {
639 SceneObject* obj = createAsteroid(vec3(getRandomNum(-1.3f, 1.3f), -1.2f, getRandomNum(-5.5f, -4.5f)), color_sp);
640 addObjectToScene(obj, shaderBufferInfo,
641 points_vbo,
642 colors_vbo,
643 selected_colors_vbo,
644 texcoords_vbo,
645 normals_vbo,
646 ubo,
647 model_mat_idx_vbo);
648
649 elapsed_seconds_spawn -= 0.5f;
650 }
651
652 /*
653 if (clickedObject == &objects[0]) {
654 selectedObject = &objects[0];
655 }
656 if (clickedObject == &objects[1]) {
657 selectedObject = &objects[1];
658 }
659 */
660
661 /*
662 if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
663 transformObject(objects[1], translate(mat4(1.0f), vec3(0.3f, 0.0f, 0.0f)), ubo);
664 }
665 if (key_down[GLFW_KEY_RIGHT]) {
666 transformObject(objects[2], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
667 }
668 if (key_down[GLFW_KEY_LEFT]) {
669 transformObject(objects[2], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
670 }
671 */
672
673 if (key_down[GLFW_KEY_RIGHT]) {
674 transformObject(*objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
675
676 if (leftLaser != NULL && !leftLaser->deleted) {
677 translateLaser(leftLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
678 }
679 if (rightLaser != NULL && !rightLaser->deleted) {
680 translateLaser(rightLaser, vec3(0.01f, 0.0f, 0.0f), ubo);
681 }
682 }
683 if (key_down[GLFW_KEY_LEFT]) {
684 transformObject(*objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
685
686 if (leftLaser != NULL && !leftLaser->deleted) {
687 translateLaser(leftLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
688 }
689 if (rightLaser != NULL && !rightLaser->deleted) {
690 translateLaser(rightLaser, vec3(-0.01f, 0.0f, 0.0f), ubo);
691 }
692 }
693
694 if (key_state[GLFW_KEY_Z] == GLFW_PRESS) {
695 vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
696
697 leftLaser = createLaser(vec3(-0.21f, -1.19f, 1.76f)+offset, vec3(-0.21f, -1.19f, -3.0f)+offset,
698 vec3(0.0f, 1.0f, 0.0f), 0.03f, laser_sp);
699 addObjectToScene(leftLaser, shaderBufferInfo,
700 points_vbo,
701 colors_vbo,
702 selected_colors_vbo,
703 texcoords_vbo,
704 normals_vbo,
705 ubo,
706 model_mat_idx_vbo);
707 } else if (key_state[GLFW_KEY_Z] == GLFW_RELEASE) {
708 removeObjectFromScene(*leftLaser, ubo);
709 }
710
711 if (key_state[GLFW_KEY_X] == GLFW_PRESS) {
712 vec3 offset(objects[0]->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
713
714 rightLaser = createLaser(vec3(0.21f, -1.19f, 1.76f) + offset, vec3(0.21f, -1.19f, -3.0f) + offset,
715 vec3(0.0f, 1.0f, 0.0f), 0.03f, laser_sp);
716 addObjectToScene(rightLaser, shaderBufferInfo,
717 points_vbo,
718 colors_vbo,
719 selected_colors_vbo,
720 texcoords_vbo,
721 normals_vbo,
722 ubo,
723 model_mat_idx_vbo);
724 } else if (key_state[GLFW_KEY_X] == GLFW_RELEASE) {
725 removeObjectFromScene(*rightLaser, ubo);
726 }
727
728 // this code moves the asteroids
729 for (int i = 0; i < objects.size(); i++) {
730 if (objects[i]->type == TYPE_ASTEROID && !objects[i]->deleted) {
731 transformObject(*objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
732
733 vec3 obj_center = vec3(view_mat * vec4(objects[i]->bounding_center, 1.0f));
734
735 if ((obj_center.z - objects[i]->bounding_radius) > -NEAR_CLIP) {
736 removeObjectFromScene(*objects[i], ubo);
737 }
738 }
739 }
740
741 if (leftLaser != NULL && !leftLaser->deleted) {
742 updateLaserTarget(leftLaser, objects, points_vbo);
743 }
744 if (rightLaser != NULL && !rightLaser->deleted) {
745 updateLaserTarget(rightLaser, objects, points_vbo);
746 }
747 }
748
749 for (vector<EffectOverTime*>::iterator it = effects.begin(); it != effects.end(); ) {
750 if ((*it)->deleted || (*it)->effectedObject->deleted) {
751 delete *it;
752 it = effects.erase(it);
753 } else {
754 EffectOverTime* eot = *it;
755 eot->effectedValue = eot->startValue + (current_seconds - eot->startTime) * eot->changePerSecond;
756
757 it++;
758 }
759 }
760
761 if (key_state[GLFW_KEY_ESCAPE] == GLFW_PRESS) {
762 glfwSetWindowShouldClose(window, 1);
763 }
764
765 float dist = cam_speed * elapsed_seconds;
766 if (key_down[GLFW_KEY_A]) {
767 vec3 dir = vec3(inverse(R) * vec4(-1.0f, 0.0f, 0.0f, 1.0f));
768 cam_pos += dir * dist;
769
770 cam_moved = true;
771 }
772 if (key_down[GLFW_KEY_D]) {
773 vec3 dir = vec3(inverse(R) * vec4(1.0f, 0.0f, 0.0f, 1.0f));
774 cam_pos += dir * dist;
775
776 cam_moved = true;
777 }
778 if (key_down[GLFW_KEY_W]) {
779 vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, -1.0f, 1.0f));
780 cam_pos += dir * dist;
781
782 cam_moved = true;
783 }
784 if (key_down[GLFW_KEY_S]) {
785 vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, 1.0f, 1.0f));
786 cam_pos += dir * dist;
787
788 cam_moved = true;
789 }
790 /*
791 if (key_down[GLFW_KEY_LEFT]) {
792 cam_yaw += cam_yaw_speed * elapsed_seconds;
793 cam_moved = true;
794 }
795 if (key_down[GLFW_KEY_RIGHT]) {
796 cam_yaw -= cam_yaw_speed * elapsed_seconds;
797 cam_moved = true;
798 }
799 if (key_down[GLFW_KEY_UP]) {
800 cam_pitch += cam_pitch_speed * elapsed_seconds;
801 cam_moved = true;
802 }
803 if (key_down[GLFW_KEY_DOWN]) {
804 cam_pitch -= cam_pitch_speed * elapsed_seconds;
805 cam_moved = true;
806 }
807 */
808 if (cam_moved && false) { // disable camera movement
809 T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
810
811 mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
812 mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
813 R = pitch_mat * yaw_mat;
814
815 view_mat = R * T;
816
817 //printVector("cam pos", cam_pos);
818
819 glUseProgram(color_sp);
820 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
821
822 glUseProgram(texture_sp);
823 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
824
825 glUseProgram(laser_sp);
826 glUniformMatrix4fv(laser_view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
827
828 cam_moved = false;
829 }
830
831 // Render scene
832
833 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
834
835 switch (curState) {
836 case STATE_MAIN_MENU:
837 renderMainMenu();
838 renderMainMenuGui();
839 break;
840 case STATE_GAME:
841 renderScene(shaderBufferInfo,
842 color_sp, texture_sp, laser_sp,
843 color_vao, texture_vao, laser_vao,
844 colors_vbo, selected_colors_vbo,
845 selectedObject);
846 renderSceneGui();
847 break;
848 }
849
850 glfwSwapBuffers(window);
851 }
852
853 ImGui_ImplGlfwGL3_Shutdown();
854 ImGui::DestroyContext();
855
856 glfwDestroyWindow(window);
857 glfwTerminate();
858
859 // free memory
860
861 for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
862 delete *it;
863 }
864
865 return 0;
866}
867
868void glfw_error_callback(int error, const char* description) {
869 gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
870}
871
872void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
873 double mouse_x, mouse_y;
874 glfwGetCursorPos(window, &mouse_x, &mouse_y);
875
876 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
877 cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
878 selectedObject = NULL;
879
880 float x = (2.0f*mouse_x) / width - 1.0f;
881 float y = 1.0f - (2.0f*mouse_y) / height;
882
883 cout << "x: " << x << ", y: " << y << endl;
884
885 vec4 ray_clip = vec4(x, y, -1.0f, 1.0f);
886 vec4 ray_eye = inverse(proj_mat) * ray_clip;
887 ray_eye = vec4(vec2(ray_eye), -1.0f, 1.0f);
888 vec4 ray_world = inverse(view_mat) * ray_eye;
889
890 vec4 click_point;
891 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
892 SceneObject* closest_object = NULL;
893
894 for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
895 if ((*it)->type == TYPE_LASER) continue;
896 for (unsigned int p_idx = 0; p_idx < (*it)->points.size(); p_idx += 9) {
897 if (faceClicked(
898 {
899 vec3((*it)->points[p_idx], (*it)->points[p_idx + 1], (*it)->points[p_idx + 2]),
900 vec3((*it)->points[p_idx + 3], (*it)->points[p_idx + 4], (*it)->points[p_idx + 5]),
901 vec3((*it)->points[p_idx + 6], (*it)->points[p_idx + 7], (*it)->points[p_idx + 8]),
902 },
903 *it, ray_world, vec4(cam_pos, 1.0f), click_point
904 )) {
905 click_point = view_mat * click_point;
906
907 if (-NEAR_CLIP >= click_point.z && click_point.z > -FAR_CLIP && click_point.z > closest_point.z) {
908 closest_point = vec3(click_point);
909 closest_object = *it;
910 }
911 }
912 }
913 }
914
915 if (closest_object == NULL) {
916 cout << "No object was clicked" << endl;
917 } else {
918 clickedObject = closest_object;
919 cout << "Clicked object: " << clickedObject->id << endl;
920 }
921 }
922}
923
924void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
925 key_state[key] = action;
926
927 // should be true for GLFW_PRESS and GLFW_REPEAT
928 key_down[key] = (action != GLFW_RELEASE);
929}
930
931
932GLuint loadShader(GLenum type, string file) {
933 cout << "Loading shader from file " << file << endl;
934
935 ifstream shaderFile(file);
936 GLuint shaderId = 0;
937
938 if (shaderFile.is_open()) {
939 string line, shaderString;
940
941 while(getline(shaderFile, line)) {
942 shaderString += line + "\n";
943 }
944 shaderFile.close();
945 const char* shaderCString = shaderString.c_str();
946
947 shaderId = glCreateShader(type);
948 glShaderSource(shaderId, 1, &shaderCString, NULL);
949 glCompileShader(shaderId);
950
951 cout << "Loaded successfully" << endl;
952 } else {
953 cout << "Failed to load the file" << endl;
954 }
955
956 return shaderId;
957}
958
959GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
960 GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
961 GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
962
963 GLuint shader_program = glCreateProgram();
964 glAttachShader(shader_program, vs);
965 glAttachShader(shader_program, fs);
966
967 glLinkProgram(shader_program);
968
969 return shader_program;
970}
971
972unsigned char* loadImage(string file_name, int* x, int* y) {
973 int n;
974 int force_channels = 4; // This forces RGBA (4 bytes per pixel)
975 unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
976
977 int width_in_bytes = *x * 4;
978 unsigned char *top = NULL;
979 unsigned char *bottom = NULL;
980 unsigned char temp = 0;
981 int half_height = *y / 2;
982
983 // flip image upside-down to account for OpenGL treating lower-left as (0, 0)
984 for (int row = 0; row < half_height; row++) {
985 top = image_data + row * width_in_bytes;
986 bottom = image_data + (*y - row - 1) * width_in_bytes;
987 for (int col = 0; col < width_in_bytes; col++) {
988 temp = *top;
989 *top = *bottom;
990 *bottom = temp;
991 top++;
992 bottom++;
993 }
994 }
995
996 if (!image_data) {
997 fprintf(stderr, "ERROR: could not load %s\n", file_name.c_str());
998 }
999
1000 // Not Power-of-2 check
1001 if ((*x & (*x - 1)) != 0 || (*y & (*y - 1)) != 0) {
1002 fprintf(stderr, "WARNING: texture %s is not power-of-2 dimensions\n", file_name.c_str());
1003 }
1004
1005 return image_data;
1006}
1007
1008bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point) {
1009 // LINE EQUATION: P = O + Dt
1010 // O = cam
1011 // D = ray_world
1012
1013 // PLANE EQUATION: P dot n + d = 0
1014 // n is the normal vector
1015 // d is the offset from the origin
1016
1017 // Take the cross-product of two vectors on the plane to get the normal
1018 vec3 v1 = points[1] - points[0];
1019 vec3 v2 = points[2] - points[0];
1020
1021 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);
1022
1023 vec3 local_ray = vec3(inverse(obj->model_mat) * world_ray);
1024 vec3 local_cam = vec3(inverse(obj->model_mat) * cam);
1025
1026 local_ray = local_ray - local_cam;
1027
1028 float d = -glm::dot(points[0], normal);
1029 float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
1030
1031 vec3 intersection = local_cam + t*local_ray;
1032
1033 if (insideTriangle(intersection, points)) {
1034 click_point = obj->model_mat * vec4(intersection, 1.0f);
1035 return true;
1036 } else {
1037 return false;
1038 }
1039}
1040
1041bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
1042 vec3 v21 = triangle_points[1] - triangle_points[0];
1043 vec3 v31 = triangle_points[2] - triangle_points[0];
1044 vec3 pv1 = p - triangle_points[0];
1045
1046 float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
1047 float x = (pv1.x-y*v31.x) / v21.x;
1048
1049 return x > 0.0f && y > 0.0f && x+y < 1.0f;
1050}
1051
1052void printVector(string label, vec3& v) {
1053 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
1054}
1055
1056void print4DVector(string label, vec4& v) {
1057 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << "," << v.w << ")" << endl;
1058}
1059
1060void initObject(SceneObject* obj) {
1061 // Each objects must have at least 3 points, so the size of
1062 // the points array must be a positive multiple of 9
1063 if (obj->points.size() == 0 || (obj->points.size() % 9) != 0) {
1064 // TODO: Maybe throw some kind of error here instead
1065 return;
1066 }
1067
1068 obj->id = objects.size(); // currently unused
1069 obj->num_points = obj->points.size() / 3;
1070 obj->model_transform = mat4(1.0f);
1071 obj->deleted = false;
1072
1073 obj->normals.reserve(obj->points.size());
1074 for (int i = 0; i < obj->points.size(); i += 9) {
1075 vec3 point1 = vec3(obj->points[i], obj->points[i + 1], obj->points[i + 2]);
1076 vec3 point2 = vec3(obj->points[i + 3], obj->points[i + 4], obj->points[i + 5]);
1077 vec3 point3 = vec3(obj->points[i + 6], obj->points[i + 7], obj->points[i + 8]);
1078
1079 vec3 normal = normalize(cross(point2 - point1, point3 - point1));
1080
1081 // Add the same normal for all 3 points
1082 for (int j = 0; j < 3; j++) {
1083 obj->normals.push_back(normal.x);
1084 obj->normals.push_back(normal.y);
1085 obj->normals.push_back(normal.z);
1086 }
1087 }
1088
1089 if (obj->type != TYPE_LASER) {
1090 calculateObjectBoundingBox(obj);
1091
1092 obj->bounding_center = vec3(obj->translate_mat * vec4(obj->bounding_center, 1.0f));
1093 }
1094}
1095
1096void addObjectToScene(SceneObject* obj,
1097 map<GLuint, BufferInfo>& shaderBufferInfo,
1098 GLuint points_vbo,
1099 GLuint colors_vbo,
1100 GLuint selected_colors_vbo,
1101 GLuint texcoords_vbo,
1102 GLuint normals_vbo,
1103 GLuint ubo,
1104 GLuint model_mat_idx_vbo) {
1105 objects.push_back(obj);
1106
1107 BufferInfo* bufferInfo = &shaderBufferInfo[obj->shader_program];
1108
1109 // Check if the buffers aren't large enough to fit the new object and, if so, call
1110 // populateBuffers() to resize and repopupulate them
1111 if (bufferInfo->vbo_capacity < (bufferInfo->ubo_offset + obj->num_points) ||
1112 bufferInfo->ubo_capacity < (bufferInfo->ubo_offset + 1)) {
1113
1114 if (leftLaser != NULL && leftLaser->deleted) {
1115 leftLaser = NULL;
1116 }
1117 if (rightLaser != NULL && rightLaser->deleted) {
1118 rightLaser = NULL;
1119 }
1120
1121 populateBuffers(objects, shaderBufferInfo,
1122 points_vbo,
1123 colors_vbo,
1124 selected_colors_vbo,
1125 texcoords_vbo,
1126 normals_vbo,
1127 ubo,
1128 model_mat_idx_vbo);
1129 } else {
1130 copyObjectDataToBuffers(*objects.back(), shaderBufferInfo,
1131 points_vbo,
1132 colors_vbo,
1133 selected_colors_vbo,
1134 texcoords_vbo,
1135 normals_vbo,
1136 ubo,
1137 model_mat_idx_vbo);
1138 }
1139}
1140
1141void removeObjectFromScene(SceneObject& obj, GLuint ubo) {
1142 if (!obj.deleted) {
1143 // Move the object outside the render bounds of the scene so it doesn't get rendered
1144 // TODO: Find a better way of hiding the object until the next time buffers are repopulated
1145 transformObject(obj, translate(mat4(1.0f), vec3(0.0f, 0.0f, FAR_CLIP * 1000.0f)), ubo);
1146 obj.deleted = true;
1147 }
1148}
1149
1150void calculateObjectBoundingBox(SceneObject* obj) {
1151 GLfloat min_x = obj->points[0];
1152 GLfloat max_x = obj->points[0];
1153 GLfloat min_y = obj->points[1];
1154 GLfloat max_y = obj->points[1];
1155 GLfloat min_z = obj->points[2];
1156 GLfloat max_z = obj->points[2];
1157
1158 // start from the second point
1159 for (int i = 3; i < obj->points.size(); i += 3) {
1160 if (min_x > obj->points[i]) {
1161 min_x = obj->points[i];
1162 }
1163 else if (max_x < obj->points[i]) {
1164 max_x = obj->points[i];
1165 }
1166
1167 if (min_y > obj->points[i + 1]) {
1168 min_y = obj->points[i + 1];
1169 }
1170 else if (max_y < obj->points[i + 1]) {
1171 max_y = obj->points[i + 1];
1172 }
1173
1174 if (min_z > obj->points[i + 2]) {
1175 min_z = obj->points[i + 2];
1176 }
1177 else if (max_z < obj->points[i + 2]) {
1178 max_z = obj->points[i + 2];
1179 }
1180 }
1181
1182 obj->bounding_center = vec3((min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f, (min_z + max_z) / 2.0f);
1183
1184 GLfloat radius_x = max_x - obj->bounding_center.x;
1185 GLfloat radius_y = max_y - obj->bounding_center.y;
1186 GLfloat radius_z = max_z - obj->bounding_center.z;
1187
1188 // TODO: This actually underestimates the radius. Might need to be fixed at some point.
1189 // TODO: Does not take into account any scaling in the model matrix
1190 obj->bounding_radius = radius_x;
1191 if (obj->bounding_radius < radius_y)
1192 obj->bounding_radius = radius_y;
1193 if (obj->bounding_radius < radius_z)
1194 obj->bounding_radius = radius_z;
1195
1196 for (int i = 0; i < obj->points.size(); i += 3) {
1197 obj->points[i] -= obj->bounding_center.x;
1198 obj->points[i + 1] -= obj->bounding_center.y;
1199 obj->points[i + 2] -= obj->bounding_center.z;
1200 }
1201
1202 obj->bounding_center = vec3(0.0f, 0.0f, 0.0f);
1203}
1204
1205SceneObject* createShip(GLuint shader) {
1206 SceneObject* ship = new SceneObject();
1207
1208 ship->type = TYPE_SHIP;
1209 ship->shader_program = shader;
1210
1211 ship->points = {
1212 //back
1213 -0.5f, 0.3f, 0.0f,
1214 -0.5f, 0.0f, 0.0f,
1215 0.5f, 0.0f, 0.0f,
1216 -0.5f, 0.3f, 0.0f,
1217 0.5f, 0.0f, 0.0f,
1218 0.5f, 0.3f, 0.0f,
1219
1220 // left back
1221 -0.5f, 0.3f, -2.0f,
1222 -0.5f, 0.0f, -2.0f,
1223 -0.5f, 0.0f, 0.0f,
1224 -0.5f, 0.3f, -2.0f,
1225 -0.5f, 0.0f, 0.0f,
1226 -0.5f, 0.3f, 0.0f,
1227
1228 // right back
1229 0.5f, 0.3f, 0.0f,
1230 0.5f, 0.0f, 0.0f,
1231 0.5f, 0.0f, -2.0f,
1232 0.5f, 0.3f, 0.0f,
1233 0.5f, 0.0f, -2.0f,
1234 0.5f, 0.3f, -2.0f,
1235
1236 // left mid
1237 -0.25f, 0.3f, -3.0f,
1238 -0.25f, 0.0f, -3.0f,
1239 -0.5f, 0.0f, -2.0f,
1240 -0.25f, 0.3f, -3.0f,
1241 -0.5f, 0.0f, -2.0f,
1242 -0.5f, 0.3f, -2.0f,
1243
1244 // right mid
1245 0.5f, 0.3f, -2.0f,
1246 0.5f, 0.0f, -2.0f,
1247 0.25f, 0.0f, -3.0f,
1248 0.5f, 0.3f, -2.0f,
1249 0.25f, 0.0f, -3.0f,
1250 0.25f, 0.3f, -3.0f,
1251
1252 // left front
1253 0.0f, 0.0f, -3.5f,
1254 -0.25f, 0.0f, -3.0f,
1255 -0.25f, 0.3f, -3.0f,
1256
1257 // right front
1258 0.25f, 0.3f, -3.0f,
1259 0.25f, 0.0f, -3.0f,
1260 0.0f, 0.0f, -3.5f,
1261
1262 // top back
1263 -0.5f, 0.3f, -2.0f,
1264 -0.5f, 0.3f, 0.0f,
1265 0.5f, 0.3f, 0.0f,
1266 -0.5f, 0.3f, -2.0f,
1267 0.5f, 0.3f, 0.0f,
1268 0.5f, 0.3f, -2.0f,
1269
1270 // bottom back
1271 -0.5f, 0.0f, 0.0f,
1272 -0.5f, 0.0f, -2.0f,
1273 0.5f, 0.0f, 0.0f,
1274 0.5f, 0.0f, 0.0f,
1275 -0.5f, 0.0f, -2.0f,
1276 0.5f, 0.0f, -2.0f,
1277
1278 // top mid
1279 -0.25f, 0.3f, -3.0f,
1280 -0.5f, 0.3f, -2.0f,
1281 0.5f, 0.3f, -2.0f,
1282 -0.25f, 0.3f, -3.0f,
1283 0.5f, 0.3f, -2.0f,
1284 0.25f, 0.3f, -3.0f,
1285
1286 // bottom mid
1287 -0.5f, 0.0f, -2.0f,
1288 -0.25f, 0.0f, -3.0f,
1289 0.5f, 0.0f, -2.0f,
1290 0.5f, 0.0f, -2.0f,
1291 -0.25f, 0.0f, -3.0f,
1292 0.25f, 0.0f, -3.0f,
1293
1294 // top front
1295 -0.25f, 0.3f, -3.0f,
1296 0.25f, 0.3f, -3.0f,
1297 0.0f, 0.0f, -3.5f,
1298
1299 // bottom front
1300 0.25f, 0.0f, -3.0f,
1301 -0.25f, 0.0f, -3.0f,
1302 0.0f, 0.0f, -3.5f,
1303
1304 // left wing start back
1305 -1.5f, 0.3f, 0.0f,
1306 -1.5f, 0.0f, 0.0f,
1307 -0.5f, 0.0f, 0.0f,
1308 -1.5f, 0.3f, 0.0f,
1309 -0.5f, 0.0f, 0.0f,
1310 -0.5f, 0.3f, 0.0f,
1311
1312 // left wing start top
1313 -0.5f, 0.3f, -0.3f,
1314 -1.3f, 0.3f, -0.3f,
1315 -1.5f, 0.3f, 0.0f,
1316 -0.5f, 0.3f, -0.3f,
1317 -1.5f, 0.3f, 0.0f,
1318 -0.5f, 0.3f, 0.0f,
1319
1320 // left wing start front
1321 -0.5f, 0.3f, -0.3f,
1322 -0.5f, 0.0f, -0.3f,
1323 -1.3f, 0.0f, -0.3f,
1324 -0.5f, 0.3f, -0.3f,
1325 -1.3f, 0.0f, -0.3f,
1326 -1.3f, 0.3f, -0.3f,
1327
1328 // left wing start bottom
1329 -0.5f, 0.0f, 0.0f,
1330 -1.5f, 0.0f, 0.0f,
1331 -1.3f, 0.0f, -0.3f,
1332 -0.5f, 0.0f, 0.0f,
1333 -1.3f, 0.0f, -0.3f,
1334 -0.5f, 0.0f, -0.3f,
1335
1336 // left wing end outside
1337 -1.5f, 0.3f, 0.0f,
1338 -2.2f, 0.15f, -0.8f,
1339 -1.5f, 0.0f, 0.0f,
1340
1341 // left wing end top
1342 -1.3f, 0.3f, -0.3f,
1343 -2.2f, 0.15f, -0.8f,
1344 -1.5f, 0.3f, 0.0f,
1345
1346 // left wing end front
1347 -1.3f, 0.0f, -0.3f,
1348 -2.2f, 0.15f, -0.8f,
1349 -1.3f, 0.3f, -0.3f,
1350
1351 // left wing end bottom
1352 -1.5f, 0.0f, 0.0f,
1353 -2.2f, 0.15f, -0.8f,
1354 -1.3f, 0.0f, -0.3f,
1355
1356 // right wing start back
1357 1.5f, 0.0f, 0.0f,
1358 1.5f, 0.3f, 0.0f,
1359 0.5f, 0.0f, 0.0f,
1360 0.5f, 0.0f, 0.0f,
1361 1.5f, 0.3f, 0.0f,
1362 0.5f, 0.3f, 0.0f,
1363
1364 // right wing start top
1365 1.3f, 0.3f, -0.3f,
1366 0.5f, 0.3f, -0.3f,
1367 1.5f, 0.3f, 0.0f,
1368 1.5f, 0.3f, 0.0f,
1369 0.5f, 0.3f, -0.3f,
1370 0.5f, 0.3f, 0.0f,
1371
1372 // right wing start front
1373 0.5f, 0.0f, -0.3f,
1374 0.5f, 0.3f, -0.3f,
1375 1.3f, 0.0f, -0.3f,
1376 1.3f, 0.0f, -0.3f,
1377 0.5f, 0.3f, -0.3f,
1378 1.3f, 0.3f, -0.3f,
1379
1380 // right wing start bottom
1381 1.5f, 0.0f, 0.0f,
1382 0.5f, 0.0f, 0.0f,
1383 1.3f, 0.0f, -0.3f,
1384 1.3f, 0.0f, -0.3f,
1385 0.5f, 0.0f, 0.0f,
1386 0.5f, 0.0f, -0.3f,
1387
1388 // right wing end outside
1389 2.2f, 0.15f, -0.8f,
1390 1.5f, 0.3f, 0.0f,
1391 1.5f, 0.0f, 0.0f,
1392
1393 // right wing end top
1394 2.2f, 0.15f, -0.8f,
1395 1.3f, 0.3f, -0.3f,
1396 1.5f, 0.3f, 0.0f,
1397
1398 // right wing end front
1399 2.2f, 0.15f, -0.8f,
1400 1.3f, 0.0f, -0.3f,
1401 1.3f, 0.3f, -0.3f,
1402
1403 // right wing end bottom
1404 2.2f, 0.15f, -0.8f,
1405 1.5f, 0.0f, 0.0f,
1406 1.3f, 0.0f, -0.3f,
1407 };
1408 ship->colors = {
1409 0.0f, 0.0f, 0.3f,
1410 0.0f, 0.0f, 0.3f,
1411 0.0f, 0.0f, 0.3f,
1412 0.0f, 0.0f, 0.3f,
1413 0.0f, 0.0f, 0.3f,
1414 0.0f, 0.0f, 0.3f,
1415
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, 1.0f,
1445 0.0f, 0.0f, 1.0f,
1446 0.0f, 0.0f, 1.0f,
1447
1448 0.0f, 0.0f, 1.0f,
1449 0.0f, 0.0f, 1.0f,
1450 0.0f, 0.0f, 1.0f,
1451
1452 0.0f, 0.0f, 1.0f,
1453 0.0f, 0.0f, 1.0f,
1454 0.0f, 0.0f, 1.0f,
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, 0.3f,
1481 0.0f, 0.0f, 0.3f,
1482 0.0f, 0.0f, 0.3f,
1483
1484 0.0f, 0.0f, 0.3f,
1485 0.0f, 0.0f, 0.3f,
1486 0.0f, 0.0f, 0.3f,
1487
1488 0.0f, 0.0f, 0.3f,
1489 0.0f, 0.0f, 0.3f,
1490 0.0f, 0.0f, 0.3f,
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
1520 0.0f, 0.0f, 0.3f,
1521 0.0f, 0.0f, 0.3f,
1522 0.0f, 0.0f, 0.3f,
1523
1524 0.0f, 0.0f, 0.3f,
1525 0.0f, 0.0f, 0.3f,
1526 0.0f, 0.0f, 0.3f,
1527
1528 0.0f, 0.0f, 0.3f,
1529 0.0f, 0.0f, 0.3f,
1530 0.0f, 0.0f, 0.3f,
1531
1532 0.0f, 0.0f, 0.3f,
1533 0.0f, 0.0f, 0.3f,
1534 0.0f, 0.0f, 0.3f,
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
1564 0.0f, 0.0f, 0.3f,
1565 0.0f, 0.0f, 0.3f,
1566 0.0f, 0.0f, 0.3f,
1567
1568 0.0f, 0.0f, 0.3f,
1569 0.0f, 0.0f, 0.3f,
1570 0.0f, 0.0f, 0.3f,
1571
1572 0.0f, 0.0f, 0.3f,
1573 0.0f, 0.0f, 0.3f,
1574 0.0f, 0.0f, 0.3f,
1575 };
1576 ship->texcoords = { 0.0f };
1577 ship->selected_colors = { 0.0f };
1578
1579 mat4 T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
1580 mat4 R_model(1.0f);
1581 ship->model_base = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
1582
1583 ship->translate_mat = T_model;
1584
1585 initObject(ship);
1586
1587 return ship;
1588}
1589
1590/* LASER RENDERING/POSITIONING ALGORITHM
1591 * -Draw a thin rectangle for the laser beam, using the specified width and endpoints
1592 * -Texture the beam with a grayscale partially transparent image
1593 * -In the shader, blend the image with a color to support lasers of different colors
1594 *
1595 * The flat part of the textured rectangle needs to always face the camera, so the laser's width is constant
1596 * This is done as follows:
1597* -Determine the length of the laser based on the start and end points
1598* -Draw a rectangle along the z-axis and rotated upwards along the y-axis, with the correct final length and width
1599* -Rotate the beam around the z-axis by the correct angle, sot that in its final position, the flat part faces the camera
1600* -Rotate the beam along the x-axis and then along the y-axis and then translate it to put it into its final position
1601*/
1602// TODO: Make the color parameter have an effect
1603// TODO: Come up with a better way of passing the object back than copying it
1604Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width, GLuint laser_sp) {
1605 Laser* obj = new Laser();
1606 obj->type = TYPE_LASER;
1607 obj->targetAsteroid = NULL;
1608 obj->shader_program = laser_sp;
1609
1610 vec3 ray = end - start;
1611 float length = glm::length(ray);
1612
1613 obj->points = {
1614 width / 2, 0.0f, -width / 2,
1615 -width / 2, 0.0f, -width / 2,
1616 -width / 2, 0.0f, 0.0f,
1617 width / 2, 0.0f, -width / 2,
1618 -width / 2, 0.0f, 0.0f,
1619 width / 2, 0.0f, 0.0f,
1620 width / 2, 0.0f, -length + width / 2,
1621 -width / 2, 0.0f, -length + width / 2,
1622 -width / 2, 0.0f, -width / 2,
1623 width / 2, 0.0f, -length + width / 2,
1624 -width / 2, 0.0f, -width / 2,
1625 width / 2, 0.0f, -width / 2,
1626 width / 2, 0.0f, -length,
1627 -width / 2, 0.0f, -length,
1628 -width / 2, 0.0f, -length + width / 2,
1629 width / 2, 0.0f, -length,
1630 -width / 2, 0.0f, -length + width / 2,
1631 width / 2, 0.0f, -length + width / 2,
1632 };
1633
1634 obj->texcoords = {
1635 1.0f, 0.5f,
1636 0.0f, 0.5f,
1637 0.0f, 0.0f,
1638 1.0f, 0.5f,
1639 0.0f, 0.0f,
1640 1.0f, 0.0f,
1641 1.0f, 0.51f,
1642 0.0f, 0.51f,
1643 0.0f, 0.49f,
1644 1.0f, 0.51f,
1645 0.0f, 0.49f,
1646 1.0f, 0.49f,
1647 1.0f, 1.0f,
1648 0.0f, 1.0f,
1649 0.0f, 0.5f,
1650 1.0f, 1.0f,
1651 0.0f, 0.5f,
1652 1.0f, 0.5f,
1653 };
1654
1655 float xAxisRotation = asin(ray.y / length);
1656 float yAxisRotation = atan2(-ray.x, -ray.z);
1657
1658 vec3 normal(rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) *
1659 rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) *
1660 vec4(0.0f, 1.0f, 0.0f, 1.0f));
1661
1662 // To project point P onto line AB:
1663 // projection = A + dot(AP,AB) / dot(AB,AB) * AB
1664 vec3 projOnLaser = start + glm::dot(cam_pos-start, ray) / (length*length) * ray;
1665 vec3 laserToCam = cam_pos - projOnLaser;
1666
1667 float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
1668
1669 obj->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
1670
1671 initObject(obj);
1672
1673 obj->model_transform = rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) * obj->model_transform;
1674 obj->model_transform = rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) * obj->model_transform;
1675 obj->model_transform = translate(mat4(1.0f), start) * obj->model_transform;
1676
1677 return obj;
1678}
1679
1680void initializeBuffers(
1681 GLuint* points_vbo,
1682 GLuint* colors_vbo,
1683 GLuint* selected_colors_vbo,
1684 GLuint* texcoords_vbo,
1685 GLuint* normals_vbo,
1686 GLuint* ubo,
1687 GLuint* model_mat_idx_vbo) {
1688 *points_vbo = 0;
1689 glGenBuffers(1, points_vbo);
1690
1691 *colors_vbo = 0;
1692 glGenBuffers(1, colors_vbo);
1693
1694 *selected_colors_vbo = 0;
1695 glGenBuffers(1, selected_colors_vbo);
1696
1697 *texcoords_vbo = 0;
1698 glGenBuffers(1, texcoords_vbo);
1699
1700 *normals_vbo = 0;
1701 glGenBuffers(1, normals_vbo);
1702
1703 *ubo = 0;
1704 glGenBuffers(1, ubo);
1705
1706 *model_mat_idx_vbo = 0;
1707 glGenBuffers(1, model_mat_idx_vbo);
1708}
1709
1710void populateBuffers(vector<SceneObject*>& objects,
1711 map<GLuint, BufferInfo>& shaderBufferInfo,
1712 GLuint points_vbo,
1713 GLuint colors_vbo,
1714 GLuint selected_colors_vbo,
1715 GLuint texcoords_vbo,
1716 GLuint normals_vbo,
1717 GLuint ubo,
1718 GLuint model_mat_idx_vbo) {
1719 GLsizeiptr points_buffer_size = 0;
1720 GLsizeiptr textures_buffer_size = 0;
1721 GLsizeiptr ubo_buffer_size = 0;
1722 GLsizeiptr model_mat_idx_buffer_size = 0;
1723
1724 map<GLuint, unsigned int> shaderCounts;
1725 map<GLuint, unsigned int> shaderUboCounts;
1726
1727 vector<SceneObject*>::iterator it;
1728
1729 /* Find all shaders that need to be used and the number of objects and
1730 * number of points for each shader. Construct a map from shader id to count
1731 * of points being drawn using that shader (for thw model matrix ubo, we
1732 * need object counts instead). These will be used to get offsets into the
1733 * vertex buffer for each shader.
1734 */
1735 for (it = objects.begin(); it != objects.end(); ) {
1736 if ((*it)->deleted) {
1737 delete *it;
1738 it = objects.erase(it);
1739 } else {
1740 points_buffer_size += (*it)->num_points * sizeof(GLfloat) * 3;
1741 textures_buffer_size += (*it)->num_points * sizeof(GLfloat) * 2;
1742 ubo_buffer_size += 16 * sizeof(GLfloat);
1743 model_mat_idx_buffer_size += (*it)->num_points * sizeof(GLuint);
1744
1745 if (shaderCounts.count((*it)->shader_program) == 0) {
1746 shaderCounts[(*it)->shader_program] = (*it)->num_points;
1747 shaderUboCounts[(*it)->shader_program] = 1;
1748 } else {
1749 shaderCounts[(*it)->shader_program] += (*it)->num_points;
1750 shaderUboCounts[(*it)->shader_program]++;
1751 }
1752
1753 it++;
1754 }
1755 }
1756
1757 // double the buffer sizes to leave room for new objects
1758 points_buffer_size *= 2;
1759 textures_buffer_size *= 2;
1760 ubo_buffer_size *= 2;
1761 model_mat_idx_buffer_size *= 2;
1762
1763 map<GLuint, unsigned int>::iterator shaderIt;
1764 unsigned int lastShaderCount = 0;
1765 unsigned int lastShaderUboCount = 0;
1766
1767 /*
1768 * The counts calculated above can be used to get the starting offset of
1769 * each shader in the vertex buffer. Create a map of base offsets to mark
1770 * where the data for the first object using a given shader begins. Also,
1771 * create a map of current offsets to mark where to copy data for the next
1772 * object being added.
1773 */
1774 for (shaderIt = shaderCounts.begin(); shaderIt != shaderCounts.end(); shaderIt++) {
1775 shaderBufferInfo[shaderIt->first].vbo_base = lastShaderCount * 2;
1776 shaderBufferInfo[shaderIt->first].ubo_base = lastShaderUboCount * 2;
1777
1778 /*
1779 cout << "shader: " << shaderIt->first << endl;
1780 cout << "point counts: " << shaderCounts[shaderIt->first] << endl;
1781 cout << "object counts: " << shaderUboCounts[shaderIt->first] << endl;
1782 cout << "vbo_base: " << shaderBufferInfo[shaderIt->first].vbo_base << endl;
1783 cout << "ubo_base: " << shaderBufferInfo[shaderIt->first].ubo_base << endl;
1784 */
1785
1786 shaderBufferInfo[shaderIt->first].vbo_offset = 0;
1787 shaderBufferInfo[shaderIt->first].ubo_offset = 0;
1788
1789 shaderBufferInfo[shaderIt->first].vbo_capacity = shaderCounts[shaderIt->first] * 2;
1790 shaderBufferInfo[shaderIt->first].ubo_capacity = shaderUboCounts[shaderIt->first] * 2;
1791
1792 lastShaderCount += shaderCounts[shaderIt->first];
1793 lastShaderUboCount += shaderUboCounts[shaderIt->first];
1794 }
1795
1796 // Allocate all the buffers using the counts calculated above
1797
1798 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
1799 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1800
1801 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1802 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1803
1804 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1805 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1806
1807 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
1808 glBufferData(GL_ARRAY_BUFFER, textures_buffer_size, NULL, GL_DYNAMIC_DRAW);
1809
1810 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
1811 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1812
1813 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1814 glBufferData(GL_UNIFORM_BUFFER, ubo_buffer_size, NULL, GL_DYNAMIC_DRAW);
1815
1816 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
1817 glBufferData(GL_ARRAY_BUFFER, model_mat_idx_buffer_size, NULL, GL_DYNAMIC_DRAW);
1818
1819 for (it = objects.begin(); it != objects.end(); it++) {
1820 copyObjectDataToBuffers(**it, shaderBufferInfo,
1821 points_vbo,
1822 colors_vbo,
1823 selected_colors_vbo,
1824 texcoords_vbo,
1825 normals_vbo,
1826 ubo,
1827 model_mat_idx_vbo);
1828 }
1829}
1830
1831void copyObjectDataToBuffers(SceneObject& obj,
1832 map<GLuint, BufferInfo>& shaderBufferInfo,
1833 GLuint points_vbo,
1834 GLuint colors_vbo,
1835 GLuint selected_colors_vbo,
1836 GLuint texcoords_vbo,
1837 GLuint normals_vbo,
1838 GLuint ubo,
1839 GLuint model_mat_idx_vbo) {
1840 BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
1841
1842 obj.vertex_vbo_offset = bufferInfo->vbo_base + bufferInfo->vbo_offset;
1843 obj.ubo_offset = bufferInfo->ubo_base + bufferInfo->ubo_offset;
1844
1845 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
1846 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.points.size() * sizeof(GLfloat), &obj.points[0]);
1847
1848 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
1849 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 2, obj.texcoords.size() * sizeof(GLfloat), &obj.texcoords[0]);
1850
1851 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
1852 for (int i = 0; i < obj.num_points; i++) {
1853 glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * sizeof(GLuint), sizeof(GLuint), &obj.ubo_offset);
1854 }
1855
1856 if (obj.type != TYPE_LASER) {
1857 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1858 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.colors.size() * sizeof(GLfloat), &obj.colors[0]);
1859
1860 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1861 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.selected_colors.size() * sizeof(GLfloat), &obj.selected_colors[0]);
1862
1863 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
1864 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.normals.size() * sizeof(GLfloat), &obj.normals[0]);
1865 }
1866
1867 obj.model_mat = obj.model_transform * obj.model_base;
1868 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1869 glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
1870
1871 bufferInfo->vbo_offset += obj.num_points;
1872 bufferInfo->ubo_offset++;
1873}
1874
1875void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo) {
1876 if (obj.deleted) return;
1877
1878 obj.model_transform = transform * obj.model_transform;
1879 obj.model_mat = obj.model_transform * obj.model_base;
1880
1881 obj.bounding_center = vec3(transform * vec4(obj.bounding_center, 1.0f));
1882
1883 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1884 glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
1885}
1886
1887void translateLaser(Laser* laser, const vec3& translation, GLuint ubo) {
1888 // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
1889 // and then re-used here
1890
1891 mat4 new_model_transform = translate(mat4(1.0f), translation) * laser->model_transform;
1892
1893 vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
1894 vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[38], 1.0f));
1895
1896 vec3 ray = end - start;
1897 float length = glm::length(ray);
1898
1899 float xAxisRotation = asin(ray.y / length);
1900 float yAxisRotation = atan2(-ray.x, -ray.z);
1901
1902 vec3 normal(rotate(mat4(1.0f), yAxisRotation, vec3(0.0f, 1.0f, 0.0f)) *
1903 rotate(mat4(1.0f), xAxisRotation, vec3(1.0f, 0.0f, 0.0f)) *
1904 vec4(0.0f, 1.0f, 0.0f, 1.0f));
1905
1906 // To project point P onto line AB:
1907 // projection = A + dot(AP,AB) / dot(AB,AB) * AB
1908 vec3 projOnLaser = start + glm::dot(cam_pos - start, ray) / (length*length) * ray;
1909 vec3 laserToCam = cam_pos - projOnLaser;
1910
1911 float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
1912
1913 laser->model_base = rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
1914
1915 transformObject(*laser, translate(mat4(1.0f), translation), ubo);
1916}
1917
1918void updateLaserTarget(Laser* laser, vector<SceneObject*>& objects, GLuint points_vbo) {
1919 // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
1920 // and then re-used here
1921
1922 vec3 start = vec3(laser->model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
1923 vec3 end = vec3(laser->model_transform * vec4(0.0f, 0.0f, laser->points[2] + laser->points[20], 1.0f));
1924
1925 vec3 intersection(0.0f), closestIntersection(0.0f);
1926 Asteroid* closestAsteroid = NULL;
1927
1928 for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
1929 if ((*it)->type == TYPE_ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {
1930 // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points
1931 if (closestAsteroid == NULL || intersection.z > closestIntersection.z) {
1932 // TODO: At this point, find the real intersection of the laser with one of the asteroid's sides
1933 closestAsteroid = (Asteroid*)*it;
1934 closestIntersection = intersection;
1935 }
1936 }
1937 }
1938
1939 float width = laser->points[0] - laser->points[2];
1940
1941 if (laser->targetAsteroid != closestAsteroid) {
1942 if (laser->targetAsteroid != NULL) {
1943 if (laser == leftLaser) {
1944 leftLaserEffect->deleted = true;
1945 } else if (laser == rightLaser) {
1946 rightLaserEffect->deleted = true;
1947 }
1948 }
1949
1950 EffectOverTime* eot = NULL;
1951
1952 if (closestAsteroid != NULL) {
1953 eot = new EffectOverTime(closestAsteroid->hp, -5, closestAsteroid);
1954 effects.push_back(eot);
1955 }
1956
1957 if (laser == leftLaser) {
1958 leftLaserEffect = eot;
1959 } else if (laser == rightLaser) {
1960 rightLaserEffect = eot;
1961 }
1962 }
1963 laser->targetAsteroid = closestAsteroid;
1964
1965 float length = 5.24f; // I think this was to make sure the laser went past the end of the screen
1966 if (closestAsteroid != NULL) {
1967 length = glm::length(closestIntersection - start);
1968 }
1969
1970 laser->points[20] = -length + width / 2;
1971 laser->points[23] = -length + width / 2;
1972 laser->points[29] = -length + width / 2;
1973 laser->points[38] = -length;
1974 laser->points[41] = -length;
1975 laser->points[44] = -length + width / 2;
1976 laser->points[47] = -length;
1977 laser->points[50] = -length + width / 2;
1978 laser->points[53] = -length + width / 2;
1979
1980 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
1981 glBufferSubData(GL_ARRAY_BUFFER, laser->vertex_vbo_offset * sizeof(GLfloat) * 3, laser->points.size() * sizeof(GLfloat), &laser->points[0]);
1982}
1983
1984bool getLaserAndAsteroidIntersection(vec3& start, vec3& end, SceneObject& asteroid, vec3& intersection) {
1985 /*
1986 ### LINE EQUATIONS ###
1987 x = x1 + u * (x2 - x1)
1988 y = y1 + u * (y2 - y1)
1989 z = z1 + u * (z2 - z1)
1990
1991 ### SPHERE EQUATION ###
1992 (x - x3)^2 + (y - y3)^2 + (z - z3)^2 = r^2
1993
1994 ### QUADRATIC EQUATION TO SOLVE ###
1995 a*u^2 + b*u + c = 0
1996 WHERE THE CONSTANTS ARE
1997 a = (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2
1998 b = 2*( (x2 - x1)*(x1 - x3) + (y2 - y1)*(y1 - y3) + (z2 - z1)*(z1 - z3) )
1999 c = x3^2 + y3^2 + z3^2 + x1^2 + y1^2 + z1^2 - 2(x3*x1 + y3*y1 + z3*z1) - r^2
2000
2001 u = (-b +- sqrt(b^2 - 4*a*c)) / 2a
2002
2003 If the value under the root is >= 0, we got an intersection
2004 If the value > 0, there are two solutions. Take the one closer to 0, since that's the
2005 one closer to the laser start point
2006 */
2007
2008 vec3& center = asteroid.bounding_center;
2009
2010 float a = pow(end.x-start.x, 2) + pow(end.y-start.y, 2) + pow(end.z-start.z, 2);
2011 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));
2012 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);
2013 float discriminant = pow(b, 2) - 4*a*c;
2014
2015 if (discriminant >= 0.0f) {
2016 // In this case, the negative root will always give the point closer to the laser start point
2017 float u = (-b - sqrt(discriminant)) / (2 * a);
2018
2019 // Check that the intersection is within the line segment corresponding to the laser
2020 if (0.0f <= u && u <= 1.0f) {
2021 intersection = start + u * (end - start);
2022 return true;
2023 }
2024 }
2025
2026 return false;
2027}
2028
2029void renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
2030 GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
2031 GLuint color_vao, GLuint texture_vao, GLuint laser_vao,
2032 GLuint colors_vbo, GLuint selected_colors_vbo,
2033 SceneObject* selectedObject) {
2034
2035 glUseProgram(color_sp);
2036 glBindVertexArray(color_vao);
2037
2038 if (selectedObject != NULL) {
2039 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
2040 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
2041
2042 glDrawArrays(GL_TRIANGLES, selectedObject->vertex_vbo_offset, selectedObject->num_points);
2043 }
2044
2045 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
2046 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
2047
2048 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[color_sp].vbo_base, shaderBufferInfo[color_sp].vbo_offset);
2049
2050 glUseProgram(texture_sp);
2051 glBindVertexArray(texture_vao);
2052
2053 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[texture_sp].vbo_base, shaderBufferInfo[texture_sp].vbo_offset);
2054
2055 glEnable(GL_BLEND);
2056
2057 glUseProgram(laser_sp);
2058 glBindVertexArray(laser_vao);
2059
2060 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[laser_sp].vbo_base, shaderBufferInfo[laser_sp].vbo_offset);
2061
2062 glDisable(GL_BLEND);
2063}
2064
2065void renderSceneGui() {
2066 ImGui_ImplGlfwGL3_NewFrame();
2067
2068 // 1. Show a simple window.
2069 // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
2070 /*
2071 {
2072 static float f = 0.0f;
2073 static int counter = 0;
2074 ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
2075 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
2076 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
2077
2078 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state
2079 ImGui::Checkbox("Another Window", &show_another_window);
2080
2081 if (ImGui::Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated)
2082 counter++;
2083 ImGui::SameLine();
2084 ImGui::Text("counter = %d", counter);
2085
2086 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
2087 }
2088 */
2089
2090 stringstream ss;
2091 ss << "FPS: " << fps;
2092
2093 {
2094 ImGui::SetNextWindowSize(ImVec2(95, 46), ImGuiCond_Once);
2095 ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once);
2096 ImGui::Begin("WndStats", NULL,
2097 ImGuiWindowFlags_NoTitleBar |
2098 ImGuiWindowFlags_NoResize |
2099 ImGuiWindowFlags_NoMove);
2100 ImGui::Text("Score: ???");
2101 ImGui::Text(ss.str().c_str());
2102 ImGui::End();
2103 }
2104
2105 {
2106 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once);
2107 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once);
2108 ImGui::Begin("WndMenubar", NULL,
2109 ImGuiWindowFlags_NoTitleBar |
2110 ImGuiWindowFlags_NoResize |
2111 ImGuiWindowFlags_NoMove);
2112 ImGui::InvisibleButton("", ImVec2(155, 18));
2113 ImGui::SameLine();
2114 if (ImGui::Button("Main Menu")) {
2115 events.push(EVENT_GO_TO_MAIN_MENU);
2116 }
2117 ImGui::End();
2118 }
2119
2120 ImGui::Render();
2121 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
2122}
2123
2124void renderMainMenu() {
2125}
2126
2127void renderMainMenuGui() {
2128 ImGui_ImplGlfwGL3_NewFrame();
2129
2130 {
2131 int padding = 4;
2132 ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once);
2133 ImGui::SetNextWindowSize(ImVec2(width + 2 * padding, height + 2 * padding), ImGuiCond_Once);
2134 ImGui::Begin("WndMain", NULL,
2135 ImGuiWindowFlags_NoTitleBar |
2136 ImGuiWindowFlags_NoResize |
2137 ImGuiWindowFlags_NoMove);
2138
2139 ImGui::InvisibleButton("", ImVec2(10, 80));
2140 ImGui::InvisibleButton("", ImVec2(285, 18));
2141 ImGui::SameLine();
2142 if (ImGui::Button("New Game")) {
2143 events.push(EVENT_GO_TO_GAME);
2144 }
2145
2146 ImGui::InvisibleButton("", ImVec2(10, 15));
2147 ImGui::InvisibleButton("", ImVec2(300, 18));
2148 ImGui::SameLine();
2149 if (ImGui::Button("Quit")) {
2150 events.push(EVENT_QUIT);
2151 }
2152
2153 ImGui::End();
2154 }
2155
2156 ImGui::Render();
2157 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
2158}
2159
2160Asteroid* createAsteroid(vec3 pos, GLuint shader) {
2161 Asteroid* obj = new Asteroid();
2162 obj->type = TYPE_ASTEROID;
2163 obj->hp = 10.0f;
2164 obj->shader_program = shader;
2165
2166 obj->points = {
2167 // front
2168 1.0f, 1.0f, 1.0f,
2169 -1.0f, 1.0f, 1.0f,
2170 -1.0f, -1.0f, 1.0f,
2171 1.0f, 1.0f, 1.0f,
2172 -1.0f, -1.0f, 1.0f,
2173 1.0f, -1.0f, 1.0f,
2174
2175 // top
2176 1.0f, 1.0f, -1.0f,
2177 -1.0f, 1.0f, -1.0f,
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
2183 // bottom
2184 1.0f, -1.0f, 1.0f,
2185 -1.0f, -1.0f, 1.0f,
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
2191 // back
2192 1.0f, 1.0f, -1.0f,
2193 -1.0f, -1.0f, -1.0f,
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
2199 // right
2200 1.0f, 1.0f, -1.0f,
2201 1.0f, 1.0f, 1.0f,
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
2207 // left
2208 -1.0f, 1.0f, 1.0f,
2209 -1.0f, 1.0f, -1.0f,
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 };
2215 obj->colors = {
2216 // front
2217 0.8f, 0.0f, 0.0f,
2218 0.8f, 0.0f, 0.0f,
2219 0.8f, 0.0f, 0.0f,
2220 0.8f, 0.0f, 0.0f,
2221 0.8f, 0.0f, 0.0f,
2222 0.8f, 0.0f, 0.0f,
2223
2224 // top
2225 0.8f, 0.0f, 0.0f,
2226 0.8f, 0.0f, 0.0f,
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
2232 // bottom
2233 0.8f, 0.0f, 0.0f,
2234 0.8f, 0.0f, 0.0f,
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
2240 // back
2241 0.8f, 0.0f, 0.0f,
2242 0.8f, 0.0f, 0.0f,
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
2248 // right
2249 0.8f, 0.0f, 0.0f,
2250 0.8f, 0.0f, 0.0f,
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
2256 // left
2257 0.8f, 0.0f, 0.0f,
2258 0.8f, 0.0f, 0.0f,
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 };
2264 obj->texcoords = { 0.0f };
2265 obj->selected_colors = { 0.0f };
2266
2267 mat4 T = translate(mat4(1.0f), pos);
2268 mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));
2269 obj->model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
2270
2271 obj->translate_mat = T;
2272
2273 initObject(obj);
2274 // This accounts for the scaling in model_base.
2275 // Dividing by 8 instead of 10 since the bounding radius algorithm
2276 // under-calculates the true value.
2277 // TODO: Once the intersection check with the sides of the asteroid is done,
2278 // this can be removed.
2279 obj->bounding_radius /= 8.0f;
2280
2281 return obj;
2282}
2283
2284float getRandomNum(float low, float high) {
2285 return low + ((float)rand()/RAND_MAX) * (high-low);
2286}
Note: See TracBrowser for help on using the repository browser.