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

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

Make the left and right lasers fire while the Z and X keys are held down, respectively. Keep the laser indices up-to-date as scene objects get removed.

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