source: opengl-game/new-game.cpp@ 612d1f6

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

As a laser moves, update its rotation so it always faces the camera.

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