source: opengl-game/new-game.cpp@ e9347b4

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

Implement an algorithm to find the closest object in a laser's path and
shorten the laser so it ends at the intersection point with that object.

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