source: opengl-game/new-game.cpp@ 9f9f9a7

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

Improve the laser rendering algorithm by using a translucent white texture that gets blended with am arbitrary color.

  • Property mode set to 100644
File size: 63.4 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
36/* LASERS TODO:
37 * -Allow lasers that face any direction
38 * -Make the lasers rotate to always face the camera
39 * -Use textures to draw lasers
40 * -The textures should be grayscale and have transparency
41 * -The laser shader should take an input color to blend with the texture to give the lasers color
42 * -DONE
43 * -The lasers should be SceneObjects and drawn like all other objects
44 * -DONE
45 * -Make lasers shoot from the ends of the ship's wings when the user presses a button and disappear after a second or so
46 *
47 * NOTE: Asteroid movement currently depends on framerate, fix this in a generic/reusable way
48 */
49
50enum State {
51 STATE_MAIN_MENU,
52 STATE_GAME,
53};
54
55enum Event {
56 EVENT_GO_TO_MAIN_MENU,
57 EVENT_GO_TO_GAME,
58 EVENT_QUIT,
59};
60
61enum ObjectType {
62 TYPE_SHIP,
63 TYPE_ASTEROID,
64 TYPE_LASER,
65};
66
67struct SceneObject {
68 unsigned int id;
69 ObjectType type;
70
71 // Currently, model_transform should only have translate, and rotation and scale need to be done in model_base since
72 // they need to be done when the object is at the origin. I should change this to have separate scale, rotate, and translate
73 // matrices for each object that can be updated independently and then applied to the object in that order.
74 mat4 model_mat, model_base, model_transform;
75 mat4 translate_mat; // beginning of doing what's mentioned above
76 GLuint shader_program;
77 unsigned int num_points;
78 GLuint vertex_vbo_offset;
79 GLuint ubo_offset;
80 vector<GLfloat> points;
81 vector<GLfloat> colors;
82 vector<GLfloat> texcoords;
83 vector<GLfloat> normals;
84 vector<GLfloat> selected_colors;
85 bool deleted;
86 vec3 bounding_center;
87 GLfloat bounding_radius;
88};
89
90struct BufferInfo {
91 unsigned int vbo_base;
92 unsigned int vbo_offset;
93 unsigned int vbo_capacity;
94 unsigned int ubo_base;
95 unsigned int ubo_offset;
96 unsigned int ubo_capacity;
97};
98
99void glfw_error_callback(int error, const char* description);
100
101void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
102void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
103
104bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point);
105bool insideTriangle(vec3 p, array<vec3, 3> triangle_points);
106
107GLuint loadShader(GLenum type, string file);
108GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath);
109unsigned char* loadImage(string file_name, int* x, int* y);
110
111void printVector(string label, vec3 v);
112void print4DVector(string label, vec4 v);
113
114void addObjectToSceneDuringInit(SceneObject& obj);
115void addObjectToScene(SceneObject& obj, map<GLuint, BufferInfo>& shaderBufferInfo,
116 GLuint points_vbo,
117 GLuint colors_vbo,
118 GLuint selected_colors_vbo,
119 GLuint texcoords_vbo,
120 GLuint normals_vbo,
121 GLuint ubo,
122 GLuint model_mat_idx_vbo);
123void removeObjectFromScene(SceneObject& obj, GLuint ubo);
124
125void calculateObjectBoundingBox(SceneObject& obj);
126
127void addLaserToScene(SceneObject& obj, vec3 start, vec3 end, vec3 color, GLfloat width);
128
129void initializeBuffers(
130 GLuint* points_vbo,
131 GLuint* colors_vbo,
132 GLuint* selected_colors_vbo,
133 GLuint* texcoords_vbo,
134 GLuint* normals_vbo,
135 GLuint* ubo,
136 GLuint* model_mat_idx_vbo);
137
138void populateBuffers(vector<SceneObject>& objects,
139 map<GLuint, BufferInfo>& shaderBufferInfo,
140 GLuint points_vbo,
141 GLuint colors_vbo,
142 GLuint selected_colors_vbo,
143 GLuint texcoords_vbo,
144 GLuint normals_vbo,
145 GLuint ubo,
146 GLuint model_mat_idx_vbo);
147
148void copyObjectDataToBuffers(SceneObject& obj,
149 map<GLuint, BufferInfo>& shaderBufferInfo,
150 GLuint points_vbo,
151 GLuint colors_vbo,
152 GLuint selected_colors_vbo,
153 GLuint texcoords_vbo,
154 GLuint normals_vbo,
155 GLuint ubo,
156 GLuint model_mat_idx_vbo);
157
158void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo);
159
160void renderMainMenu();
161void renderMainMenuGui();
162
163void renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
164 GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
165 GLuint color_vao, GLuint texture_vao,
166 GLuint colors_vbo, GLuint selected_colors_vbo,
167 SceneObject* selectedObject);
168void renderSceneGui();
169
170void spawnAsteroid(vec3 pos, GLuint shader,
171 map<GLuint, BufferInfo>& shaderBufferInfo,
172 GLuint points_vbo,
173 GLuint colors_vbo,
174 GLuint selected_colors_vbo,
175 GLuint texcoords_vbo,
176 GLuint normals_vbo,
177 GLuint ubo,
178 GLuint model_mat_idx_vbo);
179
180float getRandomNum(float low, float high);
181
182#define NUM_KEYS (512)
183#define ONE_DEG_IN_RAD ((2.0f * M_PI) / 360.0f) // 0.017444444 (maybe make this a const instead)
184
185const int KEY_STATE_UNCHANGED = -1;
186const bool FULLSCREEN = false;
187const bool SHOW_FPS = false;
188const bool DISABLE_VSYNC = false; // disable vsync to see real framerate
189unsigned int MAX_UNIFORMS = 0; // Requires OpenGL constants only available at runtime, so it can't be const
190
191int key_state[NUM_KEYS];
192bool key_pressed[NUM_KEYS];
193
194int width = 640;
195int height = 480;
196
197double fps;
198
199vec3 cam_pos;
200
201mat4 view_mat;
202mat4 proj_mat;
203
204// TODO: Consider using a list instead since it will make element deletion more efficient
205vector<SceneObject> objects;
206queue<Event> events;
207
208SceneObject* clickedObject = NULL;
209SceneObject* selectedObject = NULL;
210
211float NEAR_CLIP = 0.1f;
212float FAR_CLIP = 100.0f;
213
214// TODO: Should really have some array or struct of UI-related variables
215bool isRunning = true;
216
217ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
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 SceneObject obj;
399 mat4 T_model, R_model;
400
401 // TODO: Confirm there's nothing I need from the commented out models and delete them
402 // (Check to make sure the textured square is drawn correctly)
403
404 /*
405 // triangle
406 obj = SceneObject();
407 obj.shader_program = color_sp;
408 obj.points = {
409 0.0f, 0.5f, 0.0f,
410 -0.5f, -0.5f, 0.0f,
411 0.5f, -0.5f, 0.0f,
412 0.5f, -0.5f, 0.0f,
413 -0.5f, -0.5f, 0.0f,
414 0.0f, 0.5f, 0.0f,
415 };
416 obj.colors = {
417 1.0f, 0.0f, 0.0f,
418 0.0f, 0.0f, 1.0f,
419 0.0f, 1.0f, 0.0f,
420 0.0f, 1.0f, 0.0f,
421 0.0f, 0.0f, 1.0f,
422 1.0f, 0.0f, 0.0f,
423 };
424 obj.texcoords = { 0.0f };
425 obj.selected_colors = {
426 0.0f, 1.0f, 0.0f,
427 0.0f, 1.0f, 0.0f,
428 0.0f, 1.0f, 0.0f,
429 0.0f, 1.0f, 0.0f,
430 0.0f, 1.0f, 0.0f,
431 0.0f, 1.0f, 0.0f,
432 };
433
434 T_model = translate(mat4(1.0f), vec3(0.45f, -1.5f, 0.0f));
435 R_model = rotate(mat4(1.0f), 0.0f, vec3(0.0f, 1.0f, 0.0f));
436 obj.model_base = T_model*R_model;
437
438 addObjectToSceneDuringInit(obj);
439
440 // square
441 obj = SceneObject();
442 obj.shader_program = texture_sp;
443 obj.points = {
444 0.5f, 0.5f, 0.0f,
445 -0.5f, 0.5f, 0.0f,
446 -0.5f, -0.5f, 0.0f,
447 0.5f, 0.5f, 0.0f,
448 -0.5f, -0.5f, 0.0f,
449 0.5f, -0.5f, 0.0f,
450 };
451 obj.colors = { 0.0f };
452 obj.texcoords = {
453 1.0f, 1.0f,
454 0.0f, 1.0f,
455 0.0f, 0.0f,
456 1.0f, 1.0f,
457 0.0f, 0.0f,
458 1.0f, 0.0f
459 };
460 obj.selected_colors = {
461 0.0f, 0.6f, 0.9f,
462 0.0f, 0.6f, 0.9f,
463 0.0f, 0.6f, 0.9f,
464 0.0f, 0.6f, 0.9f,
465 0.0f, 0.6f, 0.9f,
466 0.0f, 0.6f, 0.9f,
467 };
468
469 T_model = translate(mat4(1.0f), vec3(-0.5f, -1.5f, -1.00f));
470 R_model = rotate(mat4(1.0f), 0.5f, vec3(0.0f, 1.0f, 0.0f));
471 obj.model_base = T_model*R_model;
472
473 addObjectToSceneDuringInit(obj);
474 */
475
476 // player ship
477 obj = SceneObject();
478 obj.type = TYPE_SHIP;
479 obj.shader_program = color_sp;
480 obj.points = {
481 //back
482 -0.5f, 0.3f, 0.0f,
483 -0.5f, 0.0f, 0.0f,
484 0.5f, 0.0f, 0.0f,
485 -0.5f, 0.3f, 0.0f,
486 0.5f, 0.0f, 0.0f,
487 0.5f, 0.3f, 0.0f,
488
489 // left back
490 -0.5f, 0.3f, -2.0f,
491 -0.5f, 0.0f, -2.0f,
492 -0.5f, 0.0f, 0.0f,
493 -0.5f, 0.3f, -2.0f,
494 -0.5f, 0.0f, 0.0f,
495 -0.5f, 0.3f, 0.0f,
496
497 // right back
498 0.5f, 0.3f, 0.0f,
499 0.5f, 0.0f, 0.0f,
500 0.5f, 0.0f, -2.0f,
501 0.5f, 0.3f, 0.0f,
502 0.5f, 0.0f, -2.0f,
503 0.5f, 0.3f, -2.0f,
504
505 // left mid
506 -0.25f, 0.3f, -3.0f,
507 -0.25f, 0.0f, -3.0f,
508 -0.5f, 0.0f, -2.0f,
509 -0.25f, 0.3f, -3.0f,
510 -0.5f, 0.0f, -2.0f,
511 -0.5f, 0.3f, -2.0f,
512
513 // right mid
514 0.5f, 0.3f, -2.0f,
515 0.5f, 0.0f, -2.0f,
516 0.25f, 0.0f, -3.0f,
517 0.5f, 0.3f, -2.0f,
518 0.25f, 0.0f, -3.0f,
519 0.25f, 0.3f, -3.0f,
520
521 // left front
522 0.0f, 0.0f, -3.5f,
523 -0.25f, 0.0f, -3.0f,
524 -0.25f, 0.3f, -3.0f,
525
526 // right front
527 0.25f, 0.3f, -3.0f,
528 0.25f, 0.0f, -3.0f,
529 0.0f, 0.0f, -3.5f,
530
531 // top back
532 -0.5f, 0.3f, -2.0f,
533 -0.5f, 0.3f, 0.0f,
534 0.5f, 0.3f, 0.0f,
535 -0.5f, 0.3f, -2.0f,
536 0.5f, 0.3f, 0.0f,
537 0.5f, 0.3f, -2.0f,
538
539 // bottom back
540 -0.5f, 0.0f, 0.0f,
541 -0.5f, 0.0f, -2.0f,
542 0.5f, 0.0f, 0.0f,
543 0.5f, 0.0f, 0.0f,
544 -0.5f, 0.0f, -2.0f,
545 0.5f, 0.0f, -2.0f,
546
547 // top mid
548 -0.25f, 0.3f, -3.0f,
549 -0.5f, 0.3f, -2.0f,
550 0.5f, 0.3f, -2.0f,
551 -0.25f, 0.3f, -3.0f,
552 0.5f, 0.3f, -2.0f,
553 0.25f, 0.3f, -3.0f,
554
555 // bottom mid
556 -0.5f, 0.0f, -2.0f,
557 -0.25f, 0.0f, -3.0f,
558 0.5f, 0.0f, -2.0f,
559 0.5f, 0.0f, -2.0f,
560 -0.25f, 0.0f, -3.0f,
561 0.25f, 0.0f, -3.0f,
562
563 // top front
564 -0.25f, 0.3f, -3.0f,
565 0.25f, 0.3f, -3.0f,
566 0.0f, 0.0f, -3.5f,
567
568 // bottom front
569 0.25f, 0.0f, -3.0f,
570 -0.25f, 0.0f, -3.0f,
571 0.0f, 0.0f, -3.5f,
572
573 // left wing start back
574 -1.5f, 0.3f, 0.0f,
575 -1.5f, 0.0f, 0.0f,
576 -0.5f, 0.0f, 0.0f,
577 -1.5f, 0.3f, 0.0f,
578 -0.5f, 0.0f, 0.0f,
579 -0.5f, 0.3f, 0.0f,
580
581 // left wing start top
582 -0.5f, 0.3f, -0.3f,
583 -1.3f, 0.3f, -0.3f,
584 -1.5f, 0.3f, 0.0f,
585 -0.5f, 0.3f, -0.3f,
586 -1.5f, 0.3f, 0.0f,
587 -0.5f, 0.3f, 0.0f,
588
589 // left wing start front
590 -0.5f, 0.3f, -0.3f,
591 -0.5f, 0.0f, -0.3f,
592 -1.3f, 0.0f, -0.3f,
593 -0.5f, 0.3f, -0.3f,
594 -1.3f, 0.0f, -0.3f,
595 -1.3f, 0.3f, -0.3f,
596
597 // left wing start bottom
598 -0.5f, 0.0f, 0.0f,
599 -1.5f, 0.0f, 0.0f,
600 -1.3f, 0.0f, -0.3f,
601 -0.5f, 0.0f, 0.0f,
602 -1.3f, 0.0f, -0.3f,
603 -0.5f, 0.0f, -0.3f,
604
605 // left wing end outside
606 -1.5f, 0.3f, 0.0f,
607 -2.2f, 0.15f, -0.8f,
608 -1.5f, 0.0f, 0.0f,
609
610 // left wing end top
611 -1.3f, 0.3f, -0.3f,
612 -2.2f, 0.15f, -0.8f,
613 -1.5f, 0.3f, 0.0f,
614
615 // left wing end front
616 -1.3f, 0.0f, -0.3f,
617 -2.2f, 0.15f, -0.8f,
618 -1.3f, 0.3f, -0.3f,
619
620 // left wing end bottom
621 -1.5f, 0.0f, 0.0f,
622 -2.2f, 0.15f, -0.8f,
623 -1.3f, 0.0f, -0.3f,
624
625 // right wing start back
626 1.5f, 0.0f, 0.0f,
627 1.5f, 0.3f, 0.0f,
628 0.5f, 0.0f, 0.0f,
629 0.5f, 0.0f, 0.0f,
630 1.5f, 0.3f, 0.0f,
631 0.5f, 0.3f, 0.0f,
632
633 // right wing start top
634 1.3f, 0.3f, -0.3f,
635 0.5f, 0.3f, -0.3f,
636 1.5f, 0.3f, 0.0f,
637 1.5f, 0.3f, 0.0f,
638 0.5f, 0.3f, -0.3f,
639 0.5f, 0.3f, 0.0f,
640
641 // right wing start front
642 0.5f, 0.0f, -0.3f,
643 0.5f, 0.3f, -0.3f,
644 1.3f, 0.0f, -0.3f,
645 1.3f, 0.0f, -0.3f,
646 0.5f, 0.3f, -0.3f,
647 1.3f, 0.3f, -0.3f,
648
649 // right wing start bottom
650 1.5f, 0.0f, 0.0f,
651 0.5f, 0.0f, 0.0f,
652 1.3f, 0.0f, -0.3f,
653 1.3f, 0.0f, -0.3f,
654 0.5f, 0.0f, 0.0f,
655 0.5f, 0.0f, -0.3f,
656
657 // right wing end outside
658 2.2f, 0.15f, -0.8f,
659 1.5f, 0.3f, 0.0f,
660 1.5f, 0.0f, 0.0f,
661
662 // right wing end top
663 2.2f, 0.15f, -0.8f,
664 1.3f, 0.3f, -0.3f,
665 1.5f, 0.3f, 0.0f,
666
667 // right wing end front
668 2.2f, 0.15f, -0.8f,
669 1.3f, 0.0f, -0.3f,
670 1.3f, 0.3f, -0.3f,
671
672 // right wing end bottom
673 2.2f, 0.15f, -0.8f,
674 1.5f, 0.0f, 0.0f,
675 1.3f, 0.0f, -0.3f,
676 };
677 obj.colors = {
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 0.0f, 0.0f, 0.3f,
710 0.0f, 0.0f, 0.3f,
711 0.0f, 0.0f, 0.3f,
712
713 0.0f, 0.0f, 1.0f,
714 0.0f, 0.0f, 1.0f,
715 0.0f, 0.0f, 1.0f,
716
717 0.0f, 0.0f, 1.0f,
718 0.0f, 0.0f, 1.0f,
719 0.0f, 0.0f, 1.0f,
720
721 0.0f, 0.0f, 1.0f,
722 0.0f, 0.0f, 1.0f,
723 0.0f, 0.0f, 1.0f,
724 0.0f, 0.0f, 1.0f,
725 0.0f, 0.0f, 1.0f,
726 0.0f, 0.0f, 1.0f,
727
728 0.0f, 0.0f, 1.0f,
729 0.0f, 0.0f, 1.0f,
730 0.0f, 0.0f, 1.0f,
731 0.0f, 0.0f, 1.0f,
732 0.0f, 0.0f, 1.0f,
733 0.0f, 0.0f, 1.0f,
734
735 0.0f, 0.0f, 1.0f,
736 0.0f, 0.0f, 1.0f,
737 0.0f, 0.0f, 1.0f,
738 0.0f, 0.0f, 1.0f,
739 0.0f, 0.0f, 1.0f,
740 0.0f, 0.0f, 1.0f,
741
742 0.0f, 0.0f, 1.0f,
743 0.0f, 0.0f, 1.0f,
744 0.0f, 0.0f, 1.0f,
745 0.0f, 0.0f, 1.0f,
746 0.0f, 0.0f, 1.0f,
747 0.0f, 0.0f, 1.0f,
748
749 0.0f, 0.0f, 0.3f,
750 0.0f, 0.0f, 0.3f,
751 0.0f, 0.0f, 0.3f,
752
753 0.0f, 0.0f, 0.3f,
754 0.0f, 0.0f, 0.3f,
755 0.0f, 0.0f, 0.3f,
756
757 0.0f, 0.0f, 0.3f,
758 0.0f, 0.0f, 0.3f,
759 0.0f, 0.0f, 0.3f,
760 0.0f, 0.0f, 0.3f,
761 0.0f, 0.0f, 0.3f,
762 0.0f, 0.0f, 0.3f,
763
764 0.0f, 0.0f, 0.3f,
765 0.0f, 0.0f, 0.3f,
766 0.0f, 0.0f, 0.3f,
767 0.0f, 0.0f, 0.3f,
768 0.0f, 0.0f, 0.3f,
769 0.0f, 0.0f, 0.3f,
770
771 0.0f, 0.0f, 0.3f,
772 0.0f, 0.0f, 0.3f,
773 0.0f, 0.0f, 0.3f,
774 0.0f, 0.0f, 0.3f,
775 0.0f, 0.0f, 0.3f,
776 0.0f, 0.0f, 0.3f,
777
778 0.0f, 0.0f, 0.3f,
779 0.0f, 0.0f, 0.3f,
780 0.0f, 0.0f, 0.3f,
781 0.0f, 0.0f, 0.3f,
782 0.0f, 0.0f, 0.3f,
783 0.0f, 0.0f, 0.3f,
784
785 0.0f, 0.0f, 0.3f,
786 0.0f, 0.0f, 0.3f,
787 0.0f, 0.0f, 0.3f,
788
789 0.0f, 0.0f, 0.3f,
790 0.0f, 0.0f, 0.3f,
791 0.0f, 0.0f, 0.3f,
792
793 0.0f, 0.0f, 0.3f,
794 0.0f, 0.0f, 0.3f,
795 0.0f, 0.0f, 0.3f,
796
797 0.0f, 0.0f, 0.3f,
798 0.0f, 0.0f, 0.3f,
799 0.0f, 0.0f, 0.3f,
800
801 0.0f, 0.0f, 0.3f,
802 0.0f, 0.0f, 0.3f,
803 0.0f, 0.0f, 0.3f,
804 0.0f, 0.0f, 0.3f,
805 0.0f, 0.0f, 0.3f,
806 0.0f, 0.0f, 0.3f,
807
808 0.0f, 0.0f, 0.3f,
809 0.0f, 0.0f, 0.3f,
810 0.0f, 0.0f, 0.3f,
811 0.0f, 0.0f, 0.3f,
812 0.0f, 0.0f, 0.3f,
813 0.0f, 0.0f, 0.3f,
814
815 0.0f, 0.0f, 0.3f,
816 0.0f, 0.0f, 0.3f,
817 0.0f, 0.0f, 0.3f,
818 0.0f, 0.0f, 0.3f,
819 0.0f, 0.0f, 0.3f,
820 0.0f, 0.0f, 0.3f,
821
822 0.0f, 0.0f, 0.3f,
823 0.0f, 0.0f, 0.3f,
824 0.0f, 0.0f, 0.3f,
825 0.0f, 0.0f, 0.3f,
826 0.0f, 0.0f, 0.3f,
827 0.0f, 0.0f, 0.3f,
828
829 0.0f, 0.0f, 0.3f,
830 0.0f, 0.0f, 0.3f,
831 0.0f, 0.0f, 0.3f,
832
833 0.0f, 0.0f, 0.3f,
834 0.0f, 0.0f, 0.3f,
835 0.0f, 0.0f, 0.3f,
836
837 0.0f, 0.0f, 0.3f,
838 0.0f, 0.0f, 0.3f,
839 0.0f, 0.0f, 0.3f,
840
841 0.0f, 0.0f, 0.3f,
842 0.0f, 0.0f, 0.3f,
843 0.0f, 0.0f, 0.3f,
844 };
845 obj.texcoords = { 0.0f };
846 obj.selected_colors = { 0.0f };
847
848 T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
849 R_model = rotate(mat4(1.0f), 20.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 0.0f, 0.0f));
850 R_model = mat4(1.0f);
851 obj.model_base = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
852
853 obj.translate_mat = T_model;
854
855 addObjectToSceneDuringInit(obj);
856
857 obj = SceneObject();
858 obj.shader_program = laser_sp;
859
860 addLaserToScene(obj, vec3(0.34f, -2.0f, 1.6f), vec3(0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f);
861
862 obj = SceneObject();
863 obj.shader_program = laser_sp;
864
865 addLaserToScene(obj, vec3(-0.34f, -2.0f, 1.6f), vec3(-0.34f, -2.0f, -3.0f), vec3(0.0f, 1.0f, 0.0f), 0.04f);
866
867 vector<SceneObject>::iterator obj_it;
868
869 GLuint points_vbo, colors_vbo, selected_colors_vbo, texcoords_vbo,
870 normals_vbo, ubo, model_mat_idx_vbo;
871
872 initializeBuffers(
873 &points_vbo,
874 &colors_vbo,
875 &selected_colors_vbo,
876 &texcoords_vbo,
877 &normals_vbo,
878 &ubo,
879 &model_mat_idx_vbo);
880
881 populateBuffers(objects,
882 shaderBufferInfo,
883 points_vbo,
884 colors_vbo,
885 selected_colors_vbo,
886 texcoords_vbo,
887 normals_vbo,
888 ubo,
889 model_mat_idx_vbo);
890
891 GLuint color_vao = 0;
892 glGenVertexArrays(1, &color_vao);
893 glBindVertexArray(color_vao);
894
895 glEnableVertexAttribArray(0);
896 glEnableVertexAttribArray(1);
897 glEnableVertexAttribArray(2);
898 glEnableVertexAttribArray(3);
899
900 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
901 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
902
903 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
904 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
905
906 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
907 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
908
909 GLuint texture_vao = 0;
910 glGenVertexArrays(1, &texture_vao);
911 glBindVertexArray(texture_vao);
912
913 glEnableVertexAttribArray(0);
914 glEnableVertexAttribArray(1);
915 glEnableVertexAttribArray(2);
916 glEnableVertexAttribArray(3);
917
918 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
919 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
920
921 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
922 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
923
924 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
925 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
926
927 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
928 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
929
930 float cam_speed = 1.0f;
931 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
932 float cam_pitch_speed = 60.0f*ONE_DEG_IN_RAD;
933
934 // glm::lookAt can create the view matrix
935 // glm::perspective can create the projection matrix
936
937 cam_pos = vec3(0.0f, 0.0f, 2.0f);
938 //cam_pos = vec3(-2.1f, -1.5f, -1.5f); // Good position for checking ship faces
939 float cam_yaw = 0.0f * 2.0f * 3.14159f / 360.0f;
940 float cam_pitch = -50.0f * 2.0f * 3.14159f / 360.0f;
941
942 mat4 T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
943 mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
944 mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
945 mat4 R = pitch_mat * yaw_mat;
946 view_mat = R*T;
947
948 float fov = 67.0f * ONE_DEG_IN_RAD;
949 float aspect = (float)width / (float)height;
950
951 float range = tan(fov * 0.5f) * NEAR_CLIP;
952 float Sx = NEAR_CLIP / (range * aspect);
953 float Sy = NEAR_CLIP / range;
954 float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
955 float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
956
957 float proj_arr[] = {
958 Sx, 0.0f, 0.0f, 0.0f,
959 0.0f, Sy, 0.0f, 0.0f,
960 0.0f, 0.0f, Sz, -1.0f,
961 0.0f, 0.0f, Pz, 0.0f,
962 };
963 proj_mat = make_mat4(proj_arr);
964
965 GLuint ub_binding_point = 0;
966
967 GLuint view_test_loc = glGetUniformLocation(color_sp, "view");
968 GLuint proj_test_loc = glGetUniformLocation(color_sp, "proj");
969 GLuint color_sp_ub_index = glGetUniformBlockIndex(color_sp, "models");
970
971 GLuint view_mat_loc = glGetUniformLocation(texture_sp, "view");
972 GLuint proj_mat_loc = glGetUniformLocation(texture_sp, "proj");
973 GLuint texture_sp_ub_index = glGetUniformBlockIndex(texture_sp, "models");
974
975 GLuint laser_view_mat_loc = glGetUniformLocation(laser_sp, "view");
976 GLuint laser_proj_mat_loc = glGetUniformLocation(laser_sp, "proj");
977 GLuint laser_color_loc = glGetUniformLocation(laser_sp, "laser_color");
978
979 glUseProgram(color_sp);
980 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
981 glUniformMatrix4fv(proj_test_loc, 1, GL_FALSE, value_ptr(proj_mat));
982
983 glUniformBlockBinding(color_sp, color_sp_ub_index, ub_binding_point);
984 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
985
986 glUseProgram(texture_sp);
987 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
988 glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
989
990 glUniformBlockBinding(texture_sp, texture_sp_ub_index, ub_binding_point);
991 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
992
993
994 glUseProgram(laser_sp);
995 glUniformMatrix4fv(laser_view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
996 glUniformMatrix4fv(laser_proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
997 glUniform3f(laser_color_loc, 0.2f, 1.0f, 0.2f);
998
999 bool cam_moved = false;
1000
1001 int frame_count = 0;
1002 double elapsed_seconds_fps = 0.0f;
1003 double elapsed_seconds_spawn = 0.0f;
1004 double previous_seconds = glfwGetTime();
1005
1006 // This draws wireframes. Useful for seeing separate faces and occluded objects.
1007 //glPolygonMode(GL_FRONT, GL_LINE);
1008
1009 if (DISABLE_VSYNC && SHOW_FPS) {
1010 glfwSwapInterval(0);
1011 }
1012
1013 State curState = STATE_MAIN_MENU;
1014
1015 while (!glfwWindowShouldClose(window) && isRunning) {
1016 double current_seconds = glfwGetTime();
1017 double elapsed_seconds = current_seconds - previous_seconds;
1018 previous_seconds = current_seconds;
1019
1020 if (SHOW_FPS) {
1021 elapsed_seconds_fps += elapsed_seconds;
1022 if (elapsed_seconds_fps > 0.25f) {
1023 fps = (double)frame_count / elapsed_seconds_fps;
1024 cout << "FPS: " << fps << endl;
1025
1026 frame_count = 0;
1027 elapsed_seconds_fps = 0.0f;
1028 }
1029
1030 frame_count++;
1031 }
1032
1033 // Handle events
1034
1035 clickedObject = NULL;
1036
1037 // reset the all key states to KEY_STATE_UNCHANGED (something the GLFW key callback can never return)
1038 // so that GLFW_PRESS and GLFW_RELEASE are only detected once
1039 // TODO: Change this if we ever need to act on GLFW_REPEAT (which is when a key is held down
1040 // continuously for a period of time)
1041 fill(key_state, key_state + NUM_KEYS, KEY_STATE_UNCHANGED);
1042
1043 glfwPollEvents();
1044
1045 while (!events.empty()) {
1046 switch (events.front()) {
1047 case EVENT_GO_TO_MAIN_MENU:
1048 curState = STATE_MAIN_MENU;
1049 break;
1050 case EVENT_GO_TO_GAME:
1051 curState = STATE_GAME;
1052 break;
1053 case EVENT_QUIT:
1054 isRunning = false;
1055 break;
1056 }
1057 events.pop();
1058 }
1059
1060 if (curState == STATE_GAME) {
1061
1062 elapsed_seconds_spawn += elapsed_seconds;
1063 if (elapsed_seconds_spawn > 0.5f) {
1064 spawnAsteroid(vec3(getRandomNum(-1.3f, 1.3f), getRandomNum(-3.0f, -1.0f), getRandomNum(-5.5f, -4.5f)), color_sp,
1065 shaderBufferInfo,
1066 points_vbo,
1067 colors_vbo,
1068 selected_colors_vbo,
1069 texcoords_vbo,
1070 normals_vbo,
1071 ubo,
1072 model_mat_idx_vbo);
1073
1074 elapsed_seconds_spawn -= 0.5f;
1075 }
1076
1077 /*
1078 if (clickedObject == &objects[0]) {
1079 selectedObject = &objects[0];
1080 }
1081 if (clickedObject == &objects[1]) {
1082 selectedObject = &objects[1];
1083 }
1084 */
1085
1086 /*
1087 if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
1088 transformObject(objects[1], translate(mat4(1.0f), vec3(0.3f, 0.0f, 0.0f)), ubo);
1089 }
1090 if (key_pressed[GLFW_KEY_RIGHT]) {
1091 transformObject(objects[2], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
1092 }
1093 if (key_pressed[GLFW_KEY_LEFT]) {
1094 transformObject(objects[2], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
1095 }
1096 */
1097
1098 if (key_pressed[GLFW_KEY_RIGHT]) {
1099 transformObject(objects[0], translate(mat4(1.0f), vec3(0.01f, 0.0f, 0.0f)), ubo);
1100 }
1101 if (key_pressed[GLFW_KEY_LEFT]) {
1102 transformObject(objects[0], translate(mat4(1.0f), vec3(-0.01f, 0.0f, 0.0f)), ubo);
1103 }
1104
1105 // this code moves the asteroids
1106 for (int i = 0; i < objects.size(); i++) {
1107 if (objects[i].type == TYPE_ASTEROID && !objects[i].deleted) {
1108 transformObject(objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
1109
1110 vec3 obj_center = vec3(view_mat * vec4(objects[i].bounding_center, 1.0f));
1111
1112 if ((obj_center.z - objects[i].bounding_radius) > -NEAR_CLIP) {
1113 removeObjectFromScene(objects[i], ubo);
1114 }
1115 }
1116 }
1117
1118 if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
1119 removeObjectFromScene(objects[0], ubo);
1120 }
1121 }
1122
1123 if (key_state[GLFW_KEY_ESCAPE] == GLFW_PRESS) {
1124 glfwSetWindowShouldClose(window, 1);
1125 }
1126
1127 float dist = cam_speed * elapsed_seconds;
1128 if (key_pressed[GLFW_KEY_A]) {
1129 vec3 dir = vec3(inverse(R) * vec4(-1.0f, 0.0f, 0.0f, 1.0f));
1130 cam_pos += dir * dist;
1131
1132 cam_moved = true;
1133 }
1134 if (key_pressed[GLFW_KEY_D]) {
1135 vec3 dir = vec3(inverse(R) * vec4(1.0f, 0.0f, 0.0f, 1.0f));
1136 cam_pos += dir * dist;
1137
1138 cam_moved = true;
1139 }
1140 if (key_pressed[GLFW_KEY_W]) {
1141 vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, -1.0f, 1.0f));
1142 cam_pos += dir * dist;
1143
1144 cam_moved = true;
1145 }
1146 if (key_pressed[GLFW_KEY_S]) {
1147 vec3 dir = vec3(inverse(R) * vec4(0.0f, 0.0f, 1.0f, 1.0f));
1148 cam_pos += dir * dist;
1149
1150 cam_moved = true;
1151 }
1152 /*
1153 if (key_pressed[GLFW_KEY_LEFT]) {
1154 cam_yaw += cam_yaw_speed * elapsed_seconds;
1155 cam_moved = true;
1156 }
1157 if (key_pressed[GLFW_KEY_RIGHT]) {
1158 cam_yaw -= cam_yaw_speed * elapsed_seconds;
1159 cam_moved = true;
1160 }
1161 if (key_pressed[GLFW_KEY_UP]) {
1162 cam_pitch += cam_pitch_speed * elapsed_seconds;
1163 cam_moved = true;
1164 }
1165 if (key_pressed[GLFW_KEY_DOWN]) {
1166 cam_pitch -= cam_pitch_speed * elapsed_seconds;
1167 cam_moved = true;
1168 }
1169 */
1170 if (cam_moved) {
1171 T = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
1172
1173 mat4 yaw_mat = rotate(mat4(1.0f), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
1174 mat4 pitch_mat = rotate(mat4(1.0f), -cam_pitch, vec3(1.0f, 0.0f, 0.0f));
1175 R = pitch_mat * yaw_mat;
1176
1177 view_mat = R * T;
1178
1179 //printVector("cam pos", cam_pos);
1180
1181 glUseProgram(color_sp);
1182 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
1183
1184 glUseProgram(texture_sp);
1185 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
1186
1187 glUseProgram(laser_sp);
1188 glUniformMatrix4fv(laser_view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
1189
1190 cam_moved = false;
1191 }
1192
1193 // Render scene
1194
1195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1196
1197 switch (curState) {
1198 case STATE_MAIN_MENU:
1199 renderMainMenu();
1200 renderMainMenuGui();
1201 break;
1202 case STATE_GAME:
1203 renderScene(shaderBufferInfo,
1204 color_sp, texture_sp, laser_sp,
1205 color_vao, texture_vao,
1206 colors_vbo, selected_colors_vbo,
1207 selectedObject);
1208 renderSceneGui();
1209 break;
1210 }
1211
1212 glfwSwapBuffers(window);
1213 }
1214
1215 ImGui_ImplGlfwGL3_Shutdown();
1216 ImGui::DestroyContext();
1217
1218 glfwDestroyWindow(window);
1219 glfwTerminate();
1220
1221 return 0;
1222}
1223
1224void glfw_error_callback(int error, const char* description) {
1225 gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
1226}
1227
1228void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
1229 double mouse_x, mouse_y;
1230 glfwGetCursorPos(window, &mouse_x, &mouse_y);
1231
1232 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
1233 cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
1234 selectedObject = NULL;
1235
1236 float x = (2.0f*mouse_x) / width - 1.0f;
1237 float y = 1.0f - (2.0f*mouse_y) / height;
1238
1239 cout << "x: " << x << ", y: " << y << endl;
1240
1241 vec4 ray_clip = vec4(x, y, -1.0f, 1.0f);
1242 vec4 ray_eye = inverse(proj_mat) * ray_clip;
1243 ray_eye = vec4(vec2(ray_eye), -1.0f, 1.0f);
1244 vec4 ray_world = inverse(view_mat) * ray_eye;
1245
1246 vec4 cam_pos_temp = vec4(cam_pos, 1.0f);
1247
1248 vec4 click_point;
1249 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
1250 SceneObject* closest_object = NULL;
1251
1252 for (vector<SceneObject>::iterator it = objects.begin(); it != objects.end(); it++) {
1253 if (it->type == TYPE_LASER) continue;
1254 for (unsigned int p_idx = 0; p_idx < it->points.size(); p_idx += 9) {
1255 if (faceClicked(
1256 {
1257 vec3(it->points[p_idx], it->points[p_idx + 1], it->points[p_idx + 2]),
1258 vec3(it->points[p_idx + 3], it->points[p_idx + 4], it->points[p_idx + 5]),
1259 vec3(it->points[p_idx + 6], it->points[p_idx + 7], it->points[p_idx + 8]),
1260 },
1261 &*it, ray_world, cam_pos_temp, click_point
1262 )) {
1263 click_point = view_mat * click_point;
1264
1265 if (-NEAR_CLIP >= click_point.z && click_point.z > -FAR_CLIP && click_point.z > closest_point.z) {
1266 closest_point = vec3(click_point);
1267 closest_object = &*it;
1268 }
1269 }
1270 }
1271 }
1272
1273 if (closest_object == NULL) {
1274 cout << "No object was clicked" << endl;
1275 } else {
1276 clickedObject = closest_object;
1277 cout << "Clicked object: " << clickedObject->id << endl;
1278 }
1279 }
1280}
1281
1282void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
1283 key_state[key] = action;
1284
1285 // should be true for GLFW_PRESS and GLFW_REPEAT
1286 key_pressed[key] = (action != GLFW_RELEASE);
1287}
1288
1289
1290GLuint loadShader(GLenum type, string file) {
1291 cout << "Loading shader from file " << file << endl;
1292
1293 ifstream shaderFile(file);
1294 GLuint shaderId = 0;
1295
1296 if (shaderFile.is_open()) {
1297 string line, shaderString;
1298
1299 while(getline(shaderFile, line)) {
1300 shaderString += line + "\n";
1301 }
1302 shaderFile.close();
1303 const char* shaderCString = shaderString.c_str();
1304
1305 shaderId = glCreateShader(type);
1306 glShaderSource(shaderId, 1, &shaderCString, NULL);
1307 glCompileShader(shaderId);
1308
1309 cout << "Loaded successfully" << endl;
1310 } else {
1311 cout << "Failed to load the file" << endl;
1312 }
1313
1314 return shaderId;
1315}
1316
1317GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
1318 GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
1319 GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
1320
1321 GLuint shader_program = glCreateProgram();
1322 glAttachShader(shader_program, vs);
1323 glAttachShader(shader_program, fs);
1324
1325 glLinkProgram(shader_program);
1326
1327 return shader_program;
1328}
1329
1330unsigned char* loadImage(string file_name, int* x, int* y) {
1331 int n;
1332 int force_channels = 4; // This forces RGBA (4 bytes per pixel)
1333 unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
1334
1335 int width_in_bytes = *x * 4;
1336 unsigned char *top = NULL;
1337 unsigned char *bottom = NULL;
1338 unsigned char temp = 0;
1339 int half_height = *y / 2;
1340
1341 // flip image upside-down to account for OpenGL treating lower-left as (0, 0)
1342 for (int row = 0; row < half_height; row++) {
1343 top = image_data + row * width_in_bytes;
1344 bottom = image_data + (*y - row - 1) * width_in_bytes;
1345 for (int col = 0; col < width_in_bytes; col++) {
1346 temp = *top;
1347 *top = *bottom;
1348 *bottom = temp;
1349 top++;
1350 bottom++;
1351 }
1352 }
1353
1354 if (!image_data) {
1355 fprintf(stderr, "ERROR: could not load %s\n", file_name.c_str());
1356 }
1357
1358 // Not Power-of-2 check
1359 if ((*x & (*x - 1)) != 0 || (*y & (*y - 1)) != 0) {
1360 fprintf(stderr, "WARNING: texture %s is not power-of-2 dimensions\n", file_name.c_str());
1361 }
1362
1363 return image_data;
1364}
1365
1366bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point) {
1367 // LINE EQUATION: P = O + Dt
1368 // O = cam
1369 // D = ray_world
1370
1371 // PLANE EQUATION: P dot n + d = 0
1372 // n is the normal vector
1373 // d is the offset from the origin
1374
1375 // Take the cross-product of two vectors on the plane to get the normal
1376 vec3 v1 = points[1] - points[0];
1377 vec3 v2 = points[2] - points[0];
1378
1379 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);
1380
1381 vec3 local_ray = vec3(inverse(obj->model_mat) * world_ray);
1382 vec3 local_cam = vec3(inverse(obj->model_mat) * cam);
1383
1384 local_ray = local_ray - local_cam;
1385
1386 float d = -glm::dot(points[0], normal);
1387 float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
1388
1389 vec3 intersection = local_cam + t*local_ray;
1390
1391 if (insideTriangle(intersection, points)) {
1392 click_point = obj->model_mat * vec4(intersection, 1.0f);
1393 return true;
1394 } else {
1395 return false;
1396 }
1397}
1398
1399bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
1400 vec3 v21 = triangle_points[1] - triangle_points[0];
1401 vec3 v31 = triangle_points[2] - triangle_points[0];
1402 vec3 pv1 = p - triangle_points[0];
1403
1404 float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
1405 float x = (pv1.x-y*v31.x) / v21.x;
1406
1407 return x > 0.0f && y > 0.0f && x+y < 1.0f;
1408}
1409
1410void printVector(string label, vec3 v) {
1411 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
1412}
1413
1414void print4DVector(string label, vec4 v) {
1415 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << "," << v.w << ")" << endl;
1416}
1417
1418void addObjectToSceneDuringInit(SceneObject& obj) {
1419 // Each objects must have at least 3 points, so the size of
1420 // the points array must be a positive multiple of 9
1421 if (obj.points.size() == 0 || (obj.points.size() % 9) != 0) {
1422 return;
1423 }
1424
1425 obj.id = objects.size(); // currently unused
1426 obj.num_points = obj.points.size() / 3;
1427 obj.model_transform = mat4(1.0f);
1428 obj.deleted = false;
1429
1430 obj.normals.reserve(obj.points.size());
1431 for (int i = 0; i < obj.points.size(); i += 9) {
1432 vec3 point1 = vec3(obj.points[i], obj.points[i + 1], obj.points[i + 2]);
1433 vec3 point2 = vec3(obj.points[i + 3], obj.points[i + 4], obj.points[i + 5]);
1434 vec3 point3 = vec3(obj.points[i + 6], obj.points[i + 7], obj.points[i + 8]);
1435
1436 vec3 normal = normalize(cross(point2 - point1, point3 - point1));
1437
1438 // Add the same normal for all 3 points
1439 for (int j = 0; j < 3; j++) {
1440 obj.normals.push_back(normal.x);
1441 obj.normals.push_back(normal.y);
1442 obj.normals.push_back(normal.z);
1443 }
1444 }
1445
1446 calculateObjectBoundingBox(obj);
1447
1448 obj.bounding_center = vec3(obj.translate_mat * vec4(obj.bounding_center, 1.0f));
1449
1450 objects.push_back(obj);
1451}
1452
1453void addObjectToScene(SceneObject& obj,
1454 map<GLuint, BufferInfo>& shaderBufferInfo,
1455 GLuint points_vbo,
1456 GLuint colors_vbo,
1457 GLuint selected_colors_vbo,
1458 GLuint texcoords_vbo,
1459 GLuint normals_vbo,
1460 GLuint ubo,
1461 GLuint model_mat_idx_vbo) {
1462 addObjectToSceneDuringInit(obj);
1463
1464 BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
1465
1466 // Check if the buffers aren't large enough to fit the new object and, if so, call
1467 // populateBuffers() to resize and repopupulate them
1468 if (bufferInfo->vbo_capacity < (bufferInfo->ubo_offset + obj.num_points) ||
1469 bufferInfo->ubo_capacity < (bufferInfo->ubo_offset + 1)) {
1470 populateBuffers(objects, shaderBufferInfo,
1471 points_vbo,
1472 colors_vbo,
1473 selected_colors_vbo,
1474 texcoords_vbo,
1475 normals_vbo,
1476 ubo,
1477 model_mat_idx_vbo);
1478 } else {
1479 copyObjectDataToBuffers(objects.back(), shaderBufferInfo,
1480 points_vbo,
1481 colors_vbo,
1482 selected_colors_vbo,
1483 texcoords_vbo,
1484 normals_vbo,
1485 ubo,
1486 model_mat_idx_vbo);
1487 }
1488}
1489
1490void removeObjectFromScene(SceneObject& obj, GLuint ubo) {
1491 if (!obj.deleted) {
1492 // Move the object outside the render bounds of the scene so it doesn't get rendered
1493 // TODO: Find a better way of hiding the object until the next time buffers are repopulated
1494 transformObject(obj, translate(mat4(1.0f), vec3(0.0f, 0.0f, FAR_CLIP * 1000.0f)), ubo);
1495 obj.deleted = true;
1496 }
1497}
1498
1499void calculateObjectBoundingBox(SceneObject& obj) {
1500 GLfloat min_x = obj.points[0];
1501 GLfloat max_x = obj.points[0];
1502 GLfloat min_y = obj.points[1];
1503 GLfloat max_y = obj.points[1];
1504 GLfloat min_z = obj.points[2];
1505 GLfloat max_z = obj.points[2];
1506
1507 // start from the second point
1508 for (int i = 3; i < obj.points.size(); i += 3) {
1509 if (min_x > obj.points[i]) {
1510 min_x = obj.points[i];
1511 }
1512 else if (max_x < obj.points[i]) {
1513 max_x = obj.points[i];
1514 }
1515
1516 if (min_y > obj.points[i + 1]) {
1517 min_y = obj.points[i + 1];
1518 }
1519 else if (max_y < obj.points[i + 1]) {
1520 max_y = obj.points[i + 1];
1521 }
1522
1523 if (min_z > obj.points[i + 2]) {
1524 min_z = obj.points[i + 2];
1525 }
1526 else if (max_z < obj.points[i + 2]) {
1527 max_z = obj.points[i + 2];
1528 }
1529 }
1530
1531 obj.bounding_center = vec3((min_x + max_x) / 2.0f, (min_y + max_y) / 2.0f, (min_z + max_z) / 2.0f);
1532
1533 GLfloat radius_x = max_x - obj.bounding_center.x;
1534 GLfloat radius_y = max_y - obj.bounding_center.y;
1535 GLfloat radius_z = max_z - obj.bounding_center.z;
1536
1537 // This actually underestimates the radius. Might need to be fixed at some point.
1538 obj.bounding_radius = radius_x;
1539 if (obj.bounding_radius < radius_y)
1540 obj.bounding_radius = radius_y;
1541 if (obj.bounding_radius < radius_z)
1542 obj.bounding_radius = radius_z;
1543
1544 for (int i = 0; i < obj.points.size(); i += 3) {
1545 obj.points[i] -= obj.bounding_center.x;
1546 obj.points[i + 1] -= obj.bounding_center.y;
1547 obj.points[i + 2] -= obj.bounding_center.z;
1548 }
1549
1550 obj.bounding_center = vec3(0.0f, 0.0f, 0.0f);
1551}
1552
1553// currently only works correctly for lasers oriented along the z axis
1554void addLaserToScene(SceneObject& obj, vec3 start, vec3 end, vec3 color, GLfloat width) {
1555 obj.id = objects.size(); // currently unused
1556 obj.type = TYPE_LASER;
1557 obj.deleted = false;
1558
1559 // I really need to create a direction vector and add/subtract that from start and end
1560 // to get the right coords
1561 // Also need to multiply the width times a vector perpendicular to it
1562 vec3 dir = end - start;
1563
1564 obj.points = {
1565 start.x + width / 2, start.y, start.z - width / 2,
1566 start.x - width / 2, start.y, start.z - width / 2,
1567 start.x - width / 2, start.y, start.z,
1568 start.x + width / 2, start.y, start.z - width / 2,
1569 start.x - width / 2, start.y, start.z,
1570 start.x + width / 2, start.y, start.z,
1571 end.x + width / 2, end.y, end.z + width / 2,
1572 end.x - width / 2, end.y, end.z + width / 2,
1573 start.x - width / 2, start.y, start.z - width / 2,
1574 end.x + width / 2, end.y, end.z + width / 2,
1575 start.x - width / 2, start.y, start.z - width / 2,
1576 start.x + width / 2, start.y, start.z - width / 2,
1577 end.x + width / 2, end.y, end.z,
1578 end.x - width / 2, end.y, end.z,
1579 end.x - width / 2, end.y, end.z + width / 2,
1580 end.x + width / 2, end.y, end.z,
1581 end.x - width / 2, end.y, end.z + width / 2,
1582 end.x + width / 2, end.y, end.z + width / 2,
1583 };
1584
1585 vec3 end_color = vec3(1.0f, 0.0f, 0.0f); // temporary
1586 obj.colors = {
1587 end_color.x, end_color.y, end_color.z,
1588 end_color.x, end_color.y, end_color.z,
1589 end_color.x, end_color.y, end_color.z,
1590 end_color.x, end_color.y, end_color.z,
1591 end_color.x, end_color.y, end_color.z,
1592 end_color.x, end_color.y, end_color.z,
1593 color.x, color.y, color.z,
1594 color.x, color.y, color.z,
1595 color.x, color.y, color.z,
1596 color.x, color.y, color.z,
1597 color.x, color.y, color.z,
1598 color.x, color.y, color.z,
1599 end_color.x, end_color.y, end_color.z,
1600 end_color.x, end_color.y, end_color.z,
1601 end_color.x, end_color.y, end_color.z,
1602 end_color.x, end_color.y, end_color.z,
1603 end_color.x, end_color.y, end_color.z,
1604 end_color.x, end_color.y, end_color.z,
1605 };
1606
1607 obj.texcoords = {
1608 1.0f, 0.5f,
1609 0.0f, 0.5f,
1610 0.0f, 0.0f,
1611 1.0f, 0.5f,
1612 0.0f, 0.0f,
1613 1.0f, 0.0f,
1614 1.0f, 0.51f,
1615 0.0f, 0.51f,
1616 0.0f, 0.49f,
1617 1.0f, 0.51f,
1618 0.0f, 0.49f,
1619 1.0f, 0.49f,
1620 1.0f, 1.0f,
1621 0.0f, 1.0f,
1622 0.0f, 0.5f,
1623 1.0f, 1.0f,
1624 0.0f, 0.5f,
1625 1.0f, 0.5f,
1626 };
1627
1628 obj.num_points = obj.points.size() / 3;
1629
1630 objects.push_back(obj);
1631}
1632
1633void initializeBuffers(
1634 GLuint* points_vbo,
1635 GLuint* colors_vbo,
1636 GLuint* selected_colors_vbo,
1637 GLuint* texcoords_vbo,
1638 GLuint* normals_vbo,
1639 GLuint* ubo,
1640 GLuint* model_mat_idx_vbo) {
1641 *points_vbo = 0;
1642 glGenBuffers(1, points_vbo);
1643
1644 *colors_vbo = 0;
1645 glGenBuffers(1, colors_vbo);
1646
1647 *selected_colors_vbo = 0;
1648 glGenBuffers(1, selected_colors_vbo);
1649
1650 *texcoords_vbo = 0;
1651 glGenBuffers(1, texcoords_vbo);
1652
1653 *normals_vbo = 0;
1654 glGenBuffers(1, normals_vbo);
1655
1656 *ubo = 0;
1657 glGenBuffers(1, ubo);
1658
1659 *model_mat_idx_vbo = 0;
1660 glGenBuffers(1, model_mat_idx_vbo);
1661}
1662
1663void populateBuffers(vector<SceneObject>& objects,
1664 map<GLuint, BufferInfo>& shaderBufferInfo,
1665 GLuint points_vbo,
1666 GLuint colors_vbo,
1667 GLuint selected_colors_vbo,
1668 GLuint texcoords_vbo,
1669 GLuint normals_vbo,
1670 GLuint ubo,
1671 GLuint model_mat_idx_vbo) {
1672 GLsizeiptr points_buffer_size = 0;
1673 GLsizeiptr textures_buffer_size = 0;
1674 GLsizeiptr ubo_buffer_size = 0;
1675 GLsizeiptr model_mat_idx_buffer_size = 0;
1676
1677 map<GLuint, unsigned int> shaderCounts;
1678 map<GLuint, unsigned int> shaderUboCounts;
1679
1680 vector<SceneObject>::iterator it;
1681
1682 /* Find all shaders that need to be used and the number of objects and
1683 * number of points for each shader. Construct a map from shader id to count
1684 * of points being drawn using that shader (for thw model matrix ubo, we
1685 * need object counts instead). These will be used to get offsets into the
1686 * vertex buffer for each shader.
1687 */
1688 for (it = objects.begin(); it != objects.end();) {
1689 if (it->deleted) {
1690 it = objects.erase(it);
1691 } else {
1692 points_buffer_size += it->num_points * sizeof(GLfloat) * 3;
1693 textures_buffer_size += it->num_points * sizeof(GLfloat) * 2;
1694 ubo_buffer_size += 16 * sizeof(GLfloat);
1695 model_mat_idx_buffer_size += it->num_points * sizeof(GLuint);
1696
1697 if (shaderCounts.count(it->shader_program) == 0) {
1698 shaderCounts[it->shader_program] = it->num_points;
1699 shaderUboCounts[it->shader_program] = 1;
1700 } else {
1701 shaderCounts[it->shader_program] += it->num_points;
1702 shaderUboCounts[it->shader_program]++;
1703 }
1704
1705 it++;
1706 }
1707 }
1708
1709 // double the buffer sizes to leave room for new objects
1710 points_buffer_size *= 2;
1711 textures_buffer_size *= 2;
1712 ubo_buffer_size *= 2;
1713 model_mat_idx_buffer_size *= 2;
1714
1715 map<GLuint, unsigned int>::iterator shaderIt;
1716 unsigned int lastShaderCount = 0;
1717 unsigned int lastShaderUboCount = 0;
1718
1719 /*
1720 * The counts calculated above can be used to get the starting offset of
1721 * each shader in the vertex buffer. Create a map of base offsets to mark
1722 * where the data for the first object using a given shader begins. Also,
1723 * create a map of current offsets to mark where to copy data for the next
1724 * object being added.
1725 */
1726 for (shaderIt = shaderCounts.begin(); shaderIt != shaderCounts.end(); shaderIt++) {
1727 shaderBufferInfo[shaderIt->first].vbo_base = lastShaderCount * 2;
1728 shaderBufferInfo[shaderIt->first].ubo_base = lastShaderUboCount * 2;
1729
1730 cout << "shader: " << shaderIt->first << endl;
1731 cout << "point counts: " << shaderCounts[shaderIt->first] << endl;
1732 cout << "object counts: " << shaderUboCounts[shaderIt->first] << endl;
1733 cout << "vbo_base: " << shaderBufferInfo[shaderIt->first].vbo_base << endl;
1734 cout << "ubo_base: " << shaderBufferInfo[shaderIt->first].ubo_base << endl;
1735
1736 shaderBufferInfo[shaderIt->first].vbo_offset = 0;
1737 shaderBufferInfo[shaderIt->first].ubo_offset = 0;
1738
1739 shaderBufferInfo[shaderIt->first].vbo_capacity = shaderCounts[shaderIt->first] * 2;
1740 shaderBufferInfo[shaderIt->first].ubo_capacity = shaderUboCounts[shaderIt->first] * 2;
1741
1742 lastShaderCount += shaderCounts[shaderIt->first];
1743 lastShaderUboCount += shaderUboCounts[shaderIt->first];
1744 }
1745
1746 // Allocate all the buffers using the counts calculated above
1747
1748 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
1749 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1750
1751 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1752 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1753
1754 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1755 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1756
1757 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
1758 glBufferData(GL_ARRAY_BUFFER, textures_buffer_size, NULL, GL_DYNAMIC_DRAW);
1759
1760 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
1761 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1762
1763 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1764 glBufferData(GL_UNIFORM_BUFFER, ubo_buffer_size, NULL, GL_DYNAMIC_DRAW);
1765
1766 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
1767 glBufferData(GL_ARRAY_BUFFER, model_mat_idx_buffer_size, NULL, GL_DYNAMIC_DRAW);
1768
1769 for (it = objects.begin(); it != objects.end(); it++) {
1770 copyObjectDataToBuffers(*it, shaderBufferInfo,
1771 points_vbo,
1772 colors_vbo,
1773 selected_colors_vbo,
1774 texcoords_vbo,
1775 normals_vbo,
1776 ubo,
1777 model_mat_idx_vbo);
1778 }
1779}
1780
1781void copyObjectDataToBuffers(SceneObject& obj,
1782 map<GLuint, BufferInfo>& shaderBufferInfo,
1783 GLuint points_vbo,
1784 GLuint colors_vbo,
1785 GLuint selected_colors_vbo,
1786 GLuint texcoords_vbo,
1787 GLuint normals_vbo,
1788 GLuint ubo,
1789 GLuint model_mat_idx_vbo) {
1790 BufferInfo* bufferInfo = &shaderBufferInfo[obj.shader_program];
1791
1792 obj.vertex_vbo_offset = bufferInfo->vbo_base + bufferInfo->vbo_offset;
1793 obj.ubo_offset = bufferInfo->ubo_base + bufferInfo->ubo_offset;
1794
1795 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
1796 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.points.size() * sizeof(GLfloat), &obj.points[0]);
1797
1798 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1799 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.colors.size() * sizeof(GLfloat), &obj.colors[0]);
1800
1801
1802 if (obj.type != TYPE_LASER) {
1803 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1804 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.selected_colors.size() * sizeof(GLfloat), &obj.selected_colors[0]);
1805 }
1806
1807 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
1808 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 2, obj.texcoords.size() * sizeof(GLfloat), &obj.texcoords[0]);
1809
1810 if (obj.type != TYPE_LASER) {
1811 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
1812 glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * sizeof(GLfloat) * 3, obj.normals.size() * sizeof(GLfloat), &obj.normals[0]);
1813
1814 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
1815 for (int i = 0; i < obj.num_points; i++) {
1816 glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * sizeof(GLuint), sizeof(GLuint), &obj.ubo_offset);
1817 }
1818
1819 obj.model_mat = obj.model_transform * obj.model_base;
1820 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1821 glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
1822 }
1823
1824 bufferInfo->vbo_offset += obj.num_points;
1825 bufferInfo->ubo_offset++;
1826}
1827
1828void transformObject(SceneObject& obj, const mat4& transform, GLuint ubo) {
1829 obj.model_transform = transform * obj.model_transform;
1830 obj.model_mat = obj.model_transform * obj.model_base;
1831
1832 obj.bounding_center = vec3(transform * vec4(obj.bounding_center, 1.0f));
1833
1834 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1835 glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
1836}
1837
1838void renderScene(map<GLuint, BufferInfo>& shaderBufferInfo,
1839 GLuint color_sp, GLuint texture_sp, GLuint laser_sp,
1840 GLuint color_vao, GLuint texture_vao,
1841 GLuint colors_vbo, GLuint selected_colors_vbo,
1842 SceneObject* selectedObject) {
1843
1844 glUseProgram(color_sp);
1845 glBindVertexArray(color_vao);
1846
1847 if (selectedObject != NULL) {
1848 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1849 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
1850
1851 glDrawArrays(GL_TRIANGLES, selectedObject->vertex_vbo_offset, selectedObject->num_points);
1852 }
1853
1854 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1855 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
1856
1857 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[color_sp].vbo_base, shaderBufferInfo[color_sp].vbo_offset);
1858
1859 glUseProgram(texture_sp);
1860 glBindVertexArray(texture_vao);
1861
1862 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[texture_sp].vbo_base, shaderBufferInfo[texture_sp].vbo_offset);
1863
1864 glEnable(GL_BLEND);
1865
1866 glUseProgram(laser_sp);
1867 glBindVertexArray(texture_vao);
1868
1869 glDrawArrays(GL_TRIANGLES, shaderBufferInfo[laser_sp].vbo_base, shaderBufferInfo[laser_sp].vbo_offset);
1870
1871 glDisable(GL_BLEND);
1872}
1873
1874void renderSceneGui() {
1875 ImGui_ImplGlfwGL3_NewFrame();
1876
1877 // 1. Show a simple window.
1878 // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
1879 /*
1880 {
1881 static float f = 0.0f;
1882 static int counter = 0;
1883 ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
1884 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
1885 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
1886
1887 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state
1888 ImGui::Checkbox("Another Window", &show_another_window);
1889
1890 if (ImGui::Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated)
1891 counter++;
1892 ImGui::SameLine();
1893 ImGui::Text("counter = %d", counter);
1894
1895 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1896 }
1897 */
1898
1899 {
1900 ImGui::SetNextWindowSize(ImVec2(85, 22), ImGuiCond_Once);
1901 ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once);
1902 ImGui::Begin("WndStats", NULL,
1903 ImGuiWindowFlags_NoTitleBar |
1904 ImGuiWindowFlags_NoResize |
1905 ImGuiWindowFlags_NoMove);
1906 ImGui::Text("Score: ???");
1907 ImGui::End();
1908 }
1909
1910 {
1911 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once);
1912 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once);
1913 ImGui::Begin("WndMenubar", NULL,
1914 ImGuiWindowFlags_NoTitleBar |
1915 ImGuiWindowFlags_NoResize |
1916 ImGuiWindowFlags_NoMove);
1917 ImGui::InvisibleButton("", ImVec2(155, 18));
1918 ImGui::SameLine();
1919 if (ImGui::Button("Main Menu")) {
1920 events.push(EVENT_GO_TO_MAIN_MENU);
1921 }
1922 ImGui::End();
1923 }
1924
1925 ImGui::Render();
1926 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
1927}
1928
1929void renderMainMenu() {
1930}
1931
1932void renderMainMenuGui() {
1933 ImGui_ImplGlfwGL3_NewFrame();
1934
1935 {
1936 int padding = 4;
1937 ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once);
1938 ImGui::SetNextWindowSize(ImVec2(width + 2 * padding, height + 2 * padding), ImGuiCond_Once);
1939 ImGui::Begin("WndMain", NULL,
1940 ImGuiWindowFlags_NoTitleBar |
1941 ImGuiWindowFlags_NoResize |
1942 ImGuiWindowFlags_NoMove);
1943
1944 ImGui::InvisibleButton("", ImVec2(10, 80));
1945 ImGui::InvisibleButton("", ImVec2(285, 18));
1946 ImGui::SameLine();
1947 if (ImGui::Button("New Game")) {
1948 events.push(EVENT_GO_TO_GAME);
1949 }
1950
1951 ImGui::InvisibleButton("", ImVec2(10, 15));
1952 ImGui::InvisibleButton("", ImVec2(300, 18));
1953 ImGui::SameLine();
1954 if (ImGui::Button("Quit")) {
1955 events.push(EVENT_QUIT);
1956 }
1957
1958 ImGui::End();
1959 }
1960
1961 ImGui::Render();
1962 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
1963}
1964
1965void spawnAsteroid(vec3 pos, GLuint shader,
1966 map<GLuint, BufferInfo>& shaderBufferInfo,
1967 GLuint points_vbo,
1968 GLuint colors_vbo,
1969 GLuint selected_colors_vbo,
1970 GLuint texcoords_vbo,
1971 GLuint normals_vbo,
1972 GLuint ubo,
1973 GLuint model_mat_idx_vbo) {
1974 SceneObject obj = SceneObject();
1975 obj.type = TYPE_ASTEROID;
1976 obj.shader_program = shader;
1977
1978 obj.points = {
1979 // front
1980 1.0f, 1.0f, 1.0f,
1981 -1.0f, 1.0f, 1.0f,
1982 -1.0f, -1.0f, 1.0f,
1983 1.0f, 1.0f, 1.0f,
1984 -1.0f, -1.0f, 1.0f,
1985 1.0f, -1.0f, 1.0f,
1986
1987 // top
1988 1.0f, 1.0f, -1.0f,
1989 -1.0f, 1.0f, -1.0f,
1990 -1.0f, 1.0f, 1.0f,
1991 1.0f, 1.0f, -1.0f,
1992 -1.0f, 1.0f, 1.0f,
1993 1.0f, 1.0f, 1.0f,
1994
1995 // bottom
1996 1.0f, -1.0f, 1.0f,
1997 -1.0f, -1.0f, 1.0f,
1998 -1.0f, -1.0f, -1.0f,
1999 1.0f, -1.0f, 1.0f,
2000 -1.0f, -1.0f, -1.0f,
2001 1.0f, -1.0f, -1.0f,
2002
2003 // back
2004 1.0f, 1.0f, -1.0f,
2005 -1.0f, -1.0f, -1.0f,
2006 -1.0f, 1.0f, -1.0f,
2007 1.0f, 1.0f, -1.0f,
2008 1.0f, -1.0f, -1.0f,
2009 -1.0f, -1.0f, -1.0f,
2010
2011 // right
2012 1.0f, 1.0f, -1.0f,
2013 1.0f, 1.0f, 1.0f,
2014 1.0f, -1.0f, 1.0f,
2015 1.0f, 1.0f, -1.0f,
2016 1.0f, -1.0f, 1.0f,
2017 1.0f, -1.0f, -1.0f,
2018
2019 // left
2020 -1.0f, 1.0f, 1.0f,
2021 -1.0f, 1.0f, -1.0f,
2022 -1.0f, -1.0f, -1.0f,
2023 -1.0f, 1.0f, 1.0f,
2024 -1.0f, -1.0f, -1.0f,
2025 -1.0f, -1.0f, 1.0f,
2026 };
2027 obj.colors = {
2028 // front
2029 0.8f, 0.0f, 0.0f,
2030 0.8f, 0.0f, 0.0f,
2031 0.8f, 0.0f, 0.0f,
2032 0.8f, 0.0f, 0.0f,
2033 0.8f, 0.0f, 0.0f,
2034 0.8f, 0.0f, 0.0f,
2035
2036 // top
2037 0.8f, 0.0f, 0.0f,
2038 0.8f, 0.0f, 0.0f,
2039 0.8f, 0.0f, 0.0f,
2040 0.8f, 0.0f, 0.0f,
2041 0.8f, 0.0f, 0.0f,
2042 0.8f, 0.0f, 0.0f,
2043
2044 // bottom
2045 0.8f, 0.0f, 0.0f,
2046 0.8f, 0.0f, 0.0f,
2047 0.8f, 0.0f, 0.0f,
2048 0.8f, 0.0f, 0.0f,
2049 0.8f, 0.0f, 0.0f,
2050 0.8f, 0.0f, 0.0f,
2051
2052 // back
2053 0.8f, 0.0f, 0.0f,
2054 0.8f, 0.0f, 0.0f,
2055 0.8f, 0.0f, 0.0f,
2056 0.8f, 0.0f, 0.0f,
2057 0.8f, 0.0f, 0.0f,
2058 0.8f, 0.0f, 0.0f,
2059
2060 // right
2061 0.8f, 0.0f, 0.0f,
2062 0.8f, 0.0f, 0.0f,
2063 0.8f, 0.0f, 0.0f,
2064 0.8f, 0.0f, 0.0f,
2065 0.8f, 0.0f, 0.0f,
2066 0.8f, 0.0f, 0.0f,
2067
2068 // left
2069 0.8f, 0.0f, 0.0f,
2070 0.8f, 0.0f, 0.0f,
2071 0.8f, 0.0f, 0.0f,
2072 0.8f, 0.0f, 0.0f,
2073 0.8f, 0.0f, 0.0f,
2074 0.8f, 0.0f, 0.0f,
2075 };
2076 obj.texcoords = { 0.0f };
2077 obj.selected_colors = { 0.0f };
2078
2079 mat4 T = translate(mat4(1.0f), pos);
2080 mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));
2081 obj.model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
2082
2083 obj.translate_mat = T;
2084
2085 addObjectToScene(obj, shaderBufferInfo,
2086 points_vbo,
2087 colors_vbo,
2088 selected_colors_vbo,
2089 texcoords_vbo,
2090 normals_vbo,
2091 ubo,
2092 model_mat_idx_vbo);
2093}
2094
2095float getRandomNum(float low, float high) {
2096 return low + ((float)rand()/RAND_MAX) * (high-low);
2097}
Note: See TracBrowser for help on using the repository browser.