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

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

Refactor the scene object creation functions, make the initial two laser move with the ship, and add new lasers when the user presses Z or X.

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