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

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

Add a system to keep track of which keys are pressed or held down and add another light source to help illuminate the scene from different directions.

  • Property mode set to 100644
File size: 37.0 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#define GLM_SWIZZLE
11
12// This is to fix a non-alignment issue when passing vec4 params.
13// Check if it got fixed in a later version of GLM
14#define GLM_FORCE_PURE
15
16#include <glm/mat4x4.hpp>
17#include <glm/gtc/matrix_transform.hpp>
18#include <glm/gtc/type_ptr.hpp>
19
20#include "IMGUI/imgui.h"
21#include "imgui_impl_glfw_gl3.h"
22
23#include <GL/glew.h>
24#include <GLFW/glfw3.h>
25
26#include <cstdio>
27#include <iostream>
28#include <fstream>
29#include <cmath>
30#include <string>
31#include <array>
32#include <vector>
33#include <queue>
34#include <map>
35
36using namespace std;
37using namespace glm;
38
39struct SceneObject {
40 unsigned int id;
41 mat4 model_mat;
42 GLuint shader_program;
43 unsigned int num_points;
44 GLint vertex_vbo_offset;
45 vector<GLfloat> points;
46 vector<GLfloat> colors;
47 vector<GLfloat> texcoords;
48 vector<GLfloat> normals;
49 vector<GLfloat> selected_colors;
50};
51
52enum State {
53 STATE_MAIN_MENU,
54 STATE_GAME,
55};
56
57enum Event {
58 EVENT_GO_TO_MAIN_MENU,
59 EVENT_GO_TO_GAME,
60 EVENT_QUIT,
61};
62
63#define NUM_KEYS (512)
64#define ONE_DEG_IN_RAD (2.0 * M_PI) / 360.0 // 0.017444444 (maybe make this a const instead)
65
66const int KEY_STATE_UNCHANGED = -1;
67const bool FULLSCREEN = false;
68const bool SHOW_FPS = false;
69const bool DISABLE_VSYNC = false; // disable vsync to see real framerate
70unsigned int MAX_UNIFORMS = 0; // Requires OpenGL constants only available at runtime, so it can't be const
71
72int key_state[NUM_KEYS];
73bool key_pressed[NUM_KEYS];
74
75int width = 640;
76int height = 480;
77
78double fps;
79
80vec3 cam_pos;
81
82mat4 view_mat;
83mat4 proj_mat;
84
85vector<SceneObject> objects;
86queue<Event> events;
87
88SceneObject* clickedObject = NULL;
89SceneObject* selectedObject = NULL;
90
91float NEAR_CLIP = 0.1f;
92float FAR_CLIP = 100.0f;
93
94// Should really have some array or struct of UI-related variables
95bool isRunning = true;
96
97ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
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 addObjectToScene(SceneObject& obj);
115void populateBuffers(vector<SceneObject>& objects,
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,
123 map<GLuint, unsigned int>& shaderCounts,
124 map<GLuint, unsigned int>& curShaderBase);
125
126void renderMainMenu();
127void renderMainMenuGui();
128
129void renderScene(vector<SceneObject>& objects,
130 GLuint color_sp, GLuint texture_sp,
131 GLuint vao1, GLuint vao2,
132 GLuint points_vbo, GLuint normals_vbo,
133 GLuint colors_vbo, GLuint texcoords_vbo, GLuint selected_colors_vbo,
134 SceneObject* selectedObject,
135 map<GLuint, unsigned int>& shaderCounts,
136 map<GLuint, unsigned int>& curShaderBase);
137void renderSceneGui();
138
139int main(int argc, char* argv[]) {
140 cout << "New OpenGL Game" << endl;
141
142 if (!restart_gl_log()) {}
143 gl_log("starting GLFW\n%s\n", glfwGetVersionString());
144
145 glfwSetErrorCallback(glfw_error_callback);
146 if (!glfwInit()) {
147 fprintf(stderr, "ERROR: could not start GLFW3\n");
148 return 1;
149 }
150
151#ifdef __APPLE__
152 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
153 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
154 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
155 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
156#endif
157
158 glfwWindowHint(GLFW_SAMPLES, 4);
159
160 GLFWwindow* window = NULL;
161 GLFWmonitor* mon = NULL;
162
163 if (FULLSCREEN) {
164 mon = glfwGetPrimaryMonitor();
165 const GLFWvidmode* vmode = glfwGetVideoMode(mon);
166
167 width = vmode->width;
168 height = vmode->height;
169 cout << "Fullscreen resolution " << vmode->width << "x" << vmode->height << endl;
170 }
171 window = glfwCreateWindow(width, height, "New OpenGL Game", mon, NULL);
172
173 if (!window) {
174 fprintf(stderr, "ERROR: could not open window with GLFW3\n");
175 glfwTerminate();
176 return 1;
177 }
178
179 glfwMakeContextCurrent(window);
180 glewExperimental = GL_TRUE;
181 glewInit();
182
183 /*
184 * RENDERING ALGORITHM NOTES:
185 *
186 * Basically, I need to split my objects into groups, so that each group fits into
187 * GL_MAX_UNIFORM_BLOCK_SIZE. I need to have an offset and a size for each group.
188 * Getting the offset is straitforward. The size may as well be GL_MAX_UNIFORM_BLOCK_SIZE
189 * for each group, since it seems that smaller sizes just round up to the nearest GL_MAX_UNIFORM_BLOCK_SIZE
190 *
191 * I'll need to have a loop inside my render loop that calls glBindBufferRange(GL_UNIFORM_BUFFER, ...
192 * for every 1024 objects and then draws all those objects with one glDraw call.
193 *
194 * Since I currently have very few objects, I'll wait to implement this until I have
195 * a reasonable number of objects always using the same shader.
196 */
197
198 GLint UNIFORM_BUFFER_OFFSET_ALIGNMENT, MAX_UNIFORM_BLOCK_SIZE;
199 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &UNIFORM_BUFFER_OFFSET_ALIGNMENT);
200 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &MAX_UNIFORM_BLOCK_SIZE);
201
202 MAX_UNIFORMS = MAX_UNIFORM_BLOCK_SIZE / sizeof(mat4);
203
204 cout << "UNIFORM_BUFFER_OFFSET_ALIGNMENT: " << UNIFORM_BUFFER_OFFSET_ALIGNMENT << endl;
205 cout << "MAX_UNIFORMS: " << MAX_UNIFORMS << endl;
206
207 // Setup Dear ImGui binding
208 IMGUI_CHECKVERSION();
209 ImGui::CreateContext();
210 ImGuiIO& io = ImGui::GetIO(); (void)io;
211 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
212 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
213 ImGui_ImplGlfwGL3_Init(window, true);
214
215 // Setup style
216 ImGui::StyleColorsDark();
217 //ImGui::StyleColorsClassic();
218
219 glfwSetMouseButtonCallback(window, mouse_button_callback);
220 glfwSetKeyCallback(window, key_callback);
221
222 const GLubyte* renderer = glGetString(GL_RENDERER);
223 const GLubyte* version = glGetString(GL_VERSION);
224 printf("Renderer: %s\n", renderer);
225 printf("OpenGL version supported %s\n", version);
226
227 glEnable(GL_DEPTH_TEST);
228 glDepthFunc(GL_LESS);
229
230 glEnable(GL_CULL_FACE);
231 // glCullFace(GL_BACK);
232 // glFrontFace(GL_CW);
233
234 int x, y;
235 unsigned char* texImage = loadImage("test.png", &x, &y);
236 if (texImage) {
237 cout << "Yay, I loaded an image!" << endl;
238 cout << x << endl;
239 cout << y << endl;
240 printf("first 4 bytes are: %i %i %i %i\n", texImage[0], texImage[1], texImage[2], texImage[3]);
241 }
242
243 GLuint tex = 0;
244 glGenTextures(1, &tex);
245 glActiveTexture(GL_TEXTURE0);
246 glBindTexture(GL_TEXTURE_2D, tex);
247 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);
248
249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
251 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
252 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
253
254 /* RENDERING ALGORITHM
255 *
256 * Create a separate vbo for each of the following things:
257 * - points
258 * - colors
259 * - texture coordinates
260 * - selected colors
261 * - normals
262 * - indices into a ubo that stores a model matrix for each object
263 *
264 * Also, make a model matrix ubo, the entirety of which will be passed to the vertex shader.
265 * The vbo containing the correct index into the ubo (mentioned above) will be used to select
266 * the right model matrix for each point. The index in the vbo will be the saem for all points
267 * of any given object.
268 *
269 * There will be two shader programs for now, one for draing colored objects, and another for
270 * drawing textured ones. The points, normals, and model mat ubo indices will be passed to both
271 * shaders, while the colors vbo will only be passed to the colors shader, and the texcoords vbo
272 * only to the texture shader.
273 *
274 * Right now, the currently selected object is drawn using one color (specified in the selected
275 * colors vbo) regardless of whether it is normally rendering using colors or a texture. The selected
276 * object is rendering by binding the selected colors vbo in place of the colors vbo and using the colors
277 * shader. Then, the selected object is redrawn along with all other objects, but the depth buffer test
278 * prevents the unselected version of the object from appearing on the screen. This lets me render all the
279 * objects that use a particular shader using one glDrawArrays() call.
280 */
281
282 GLuint color_sp = loadShaderProgram("./color.vert", "./color.frag");
283 GLuint texture_sp = loadShaderProgram("./texture.vert", "./texture.frag");
284
285 SceneObject obj;
286 mat4 T_model, R_model;
287
288 // triangle
289 obj = SceneObject();
290 obj.shader_program = color_sp;
291 obj.points = {
292 0.0f, 0.5f, 0.0f,
293 -0.5f, -0.5f, 0.0f,
294 0.5f, -0.5f, 0.0f,
295 0.5f, -0.5f, 0.0f,
296 -0.5f, -0.5f, 0.0f,
297 0.0f, 0.5f, 0.0f,
298 };
299 obj.colors = {
300 1.0f, 0.0f, 0.0f,
301 0.0f, 0.0f, 1.0f,
302 0.0f, 1.0f, 0.0f,
303 0.0f, 1.0f, 0.0f,
304 0.0f, 0.0f, 1.0f,
305 1.0f, 0.0f, 0.0f,
306 };
307 obj.texcoords = {
308 1.0f, 1.0f,
309 0.0f, 1.0f,
310 0.0f, 0.0f,
311 1.0f, 1.0f,
312 0.0f, 0.0f,
313 1.0f, 0.0f
314 };
315 obj.selected_colors = {
316 0.0f, 1.0f, 0.0f,
317 0.0f, 1.0f, 0.0f,
318 0.0f, 1.0f, 0.0f,
319 0.0f, 1.0f, 0.0f,
320 0.0f, 1.0f, 0.0f,
321 0.0f, 1.0f, 0.0f,
322 };
323
324 T_model = translate(mat4(), vec3(0.45f, 0.0f, 0.0f));
325 R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
326 obj.model_mat = T_model*R_model;
327
328 addObjectToScene(obj);
329
330 // square
331 obj = SceneObject();
332 obj.shader_program = texture_sp;
333 obj.points = {
334 0.5f, 0.5f, 0.0f,
335 -0.5f, 0.5f, 0.0f,
336 -0.5f, -0.5f, 0.0f,
337 0.5f, 0.5f, 0.0f,
338 -0.5f, -0.5f, 0.0f,
339 0.5f, -0.5f, 0.0f,
340 };
341 obj.colors = {
342 1.0f, 0.0f, 0.0f,
343 0.0f, 0.0f, 1.0f,
344 0.0f, 1.0f, 0.0f,
345 0.0f, 1.0f, 0.0f,
346 0.0f, 0.0f, 1.0f,
347 1.0f, 0.0f, 0.0f,
348 };
349 obj.texcoords = {
350 1.0f, 1.0f,
351 0.0f, 1.0f,
352 0.0f, 0.0f,
353 1.0f, 1.0f,
354 0.0f, 0.0f,
355 1.0f, 0.0f
356 };
357 obj.selected_colors = {
358 0.0f, 0.6f, 0.9f,
359 0.0f, 0.6f, 0.9f,
360 0.0f, 0.6f, 0.9f,
361 0.0f, 0.6f, 0.9f,
362 0.0f, 0.6f, 0.9f,
363 0.0f, 0.6f, 0.9f,
364 };
365
366 T_model = translate(mat4(), vec3(-0.5f, 0.0f, -1.00f));
367 R_model = rotate(mat4(), 0.5f, vec3(0.0f, 1.0f, 0.0f));
368 obj.model_mat = T_model*R_model;
369
370 addObjectToScene(obj);
371
372 // player ship
373 obj = SceneObject();
374 obj.shader_program = color_sp;
375 obj.points = {
376 0.0f, 0.5f, 0.0f,
377 -0.5f, -0.5f, 0.0f,
378 0.5f, -0.5f, 0.0f,
379 0.5f, -0.5f, 0.0f,
380 -0.5f, -0.5f, 0.0f,
381 0.0f, 0.5f, 0.0f,
382 };
383 obj.colors = {
384 0.0f, 0.0f, 0.3f,
385 0.0f, 0.0f, 0.3f,
386 0.0f, 0.0f, 0.3f,
387 0.0f, 0.0f, 0.3f,
388 0.0f, 0.0f, 0.3f,
389 0.0f, 0.0f, 0.3f,
390 };
391 obj.texcoords = {
392 1.0f, 1.0f,
393 0.0f, 1.0f,
394 0.0f, 0.0f,
395 1.0f, 1.0f,
396 0.0f, 0.0f,
397 1.0f, 0.0f,
398 };
399 obj.selected_colors = {
400 0.0f, 1.0f, 0.0f,
401 0.0f, 1.0f, 0.0f,
402 0.0f, 1.0f, 0.0f,
403 0.0f, 1.0f, 0.0f,
404 0.0f, 1.0f, 0.0f,
405 0.0f, 1.0f, 0.0f,
406 };
407
408 T_model = translate(mat4(), vec3(0.0f, -0.9f, 0.0f));
409 R_model = rotate(mat4(), -1.0f, vec3(1.0f, 0.0f, 0.0f));
410 obj.model_mat = T_model; //T_model * R_model;
411
412 addObjectToScene(obj);
413
414 vector<SceneObject>::iterator obj_it;
415 GLsizeiptr offset;
416
417 GLuint points_vbo, colors_vbo, selected_colors_vbo, texcoords_vbo,
418 normals_vbo, ubo, model_mat_idx_vbo;
419
420 map<GLuint, unsigned int> shaderCounts, curShaderBase;
421
422 populateBuffers(objects,
423 &points_vbo,
424 &colors_vbo,
425 &selected_colors_vbo,
426 &texcoords_vbo,
427 &normals_vbo,
428 &ubo,
429 &model_mat_idx_vbo,
430 shaderCounts,
431 curShaderBase);
432
433 GLuint vao = 0;
434 glGenVertexArrays(1, &vao);
435 glBindVertexArray(vao);
436
437 glEnableVertexAttribArray(0);
438 glEnableVertexAttribArray(1);
439 glEnableVertexAttribArray(2);
440 glEnableVertexAttribArray(3);
441
442 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
443 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
444
445 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
446 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
447
448 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
449 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
450
451 GLuint vao2 = 0;
452 glGenVertexArrays(1, &vao2);
453 glBindVertexArray(vao2);
454
455 glEnableVertexAttribArray(0);
456 glEnableVertexAttribArray(1);
457 glEnableVertexAttribArray(2);
458 glEnableVertexAttribArray(3);
459
460 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
461 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
462
463 glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
464 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
465
466 glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
467 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
468
469 glBindBuffer(GL_ARRAY_BUFFER, model_mat_idx_vbo);
470 glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, 0, 0);
471
472 float cam_speed = 1.0f;
473 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
474
475 // glm::lookAt can create the view matrix
476 // glm::perspective can create the projection matrix
477
478 cam_pos = vec3(0.0f, 0.0f, 2.0f);
479 float cam_yaw = 0.0f * 2.0f * 3.14159f / 360.0f;
480
481 mat4 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
482 mat4 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
483 view_mat = R*T;
484
485 float fov = 67.0f * ONE_DEG_IN_RAD;
486 float aspect = (float)width / (float)height;
487
488 float range = tan(fov * 0.5f) * NEAR_CLIP;
489 float Sx = NEAR_CLIP / (range * aspect);
490 float Sy = NEAR_CLIP / range;
491 float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
492 float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
493
494 float proj_arr[] = {
495 Sx, 0.0f, 0.0f, 0.0f,
496 0.0f, Sy, 0.0f, 0.0f,
497 0.0f, 0.0f, Sz, -1.0f,
498 0.0f, 0.0f, Pz, 0.0f,
499 };
500 proj_mat = make_mat4(proj_arr);
501
502 GLuint ub_binding_point = 0;
503
504 GLuint view_test_loc = glGetUniformLocation(color_sp, "view");
505 GLuint proj_test_loc = glGetUniformLocation(color_sp, "proj");
506 GLuint color_sp_ub_index = glGetUniformBlockIndex(color_sp, "models");
507
508 GLuint view_mat_loc = glGetUniformLocation(texture_sp, "view");
509 GLuint proj_mat_loc = glGetUniformLocation(texture_sp, "proj");
510 GLuint texture_sp_ub_index = glGetUniformBlockIndex(texture_sp, "models");
511
512 glUseProgram(color_sp);
513 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
514 glUniformMatrix4fv(proj_test_loc, 1, GL_FALSE, value_ptr(proj_mat));
515
516 glUniformBlockBinding(color_sp, color_sp_ub_index, ub_binding_point);
517 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
518
519 glUseProgram(texture_sp);
520 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
521 glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
522
523 glUniformBlockBinding(texture_sp, texture_sp_ub_index, ub_binding_point);
524 glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
525
526 bool cam_moved = false;
527
528 int frame_count = 0;
529 double elapsed_seconds_fps = 0.0f;
530 double previous_seconds = glfwGetTime();
531
532 // This draws wireframes. Useful for seeing separate faces and occluded objects.
533 //glPolygonMode(GL_FRONT, GL_LINE);
534
535 if (DISABLE_VSYNC && SHOW_FPS) {
536 glfwSwapInterval(0);
537 }
538
539 State curState = STATE_MAIN_MENU;
540
541 while (!glfwWindowShouldClose(window) && isRunning) {
542 double current_seconds = glfwGetTime();
543 double elapsed_seconds = current_seconds - previous_seconds;
544 previous_seconds = current_seconds;
545
546 if (SHOW_FPS) {
547 elapsed_seconds_fps += elapsed_seconds;
548 if (elapsed_seconds_fps > 0.25f) {
549 fps = (double)frame_count / elapsed_seconds_fps;
550 cout << "FPS: " << fps << endl;
551
552 frame_count = 0;
553 elapsed_seconds_fps = 0.0f;
554 }
555
556 frame_count++;
557 }
558
559 // Handle events
560
561 clickedObject = NULL;
562
563 // reset the all key states to KEY_STATE_UNCHANGED (something the GLFW key callback can never return)
564 // so that GLFW_PRESS and GLFW_RELEASE are only detected once
565 // TODO: Change this if we ever need to act on GLFW_REPEAT (which is when a key is held down continuously)
566 fill(key_state, key_state + NUM_KEYS, KEY_STATE_UNCHANGED);
567
568 glfwPollEvents();
569
570 while (!events.empty()) {
571 switch (events.front()) {
572 case EVENT_GO_TO_MAIN_MENU:
573 curState = STATE_MAIN_MENU;
574 break;
575 case EVENT_GO_TO_GAME:
576 curState = STATE_GAME;
577 break;
578 case EVENT_QUIT:
579 isRunning = false;
580 break;
581 }
582 events.pop();
583 }
584
585 if (curState == STATE_GAME) {
586 if (clickedObject == &objects[0]) {
587 selectedObject = &objects[0];
588 }
589 if (clickedObject == &objects[1]) {
590 selectedObject = &objects[1];
591 }
592
593 /*
594 if (key_state[GLFW_KEY_SPACE] == GLFW_PRESS) {
595 //transformObject(objects[1], translate(mat4(), vec3(0.3f, 0.0f, 0.0f)), ubo);
596 }
597 if (key_pressed[GLFW_KEY_RIGHT]) {
598 transformObject(objects[2], translate(mat4(), vec3(0.01f, 0.0f, 0.0f)), ubo);
599 }
600 if (key_pressed[GLFW_KEY_LEFT]) {
601 transformObject(objects[2], translate(mat4(), vec3(-0.01f, 0.0f, 0.0f)), ubo);
602 }
603 */
604 }
605
606 // Render scene
607
608 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
609
610 switch (curState) {
611 case STATE_MAIN_MENU:
612 renderMainMenu();
613 renderMainMenuGui();
614 break;
615 case STATE_GAME:
616 renderScene(objects,
617 color_sp, texture_sp,
618 vao, vao2,
619 points_vbo, normals_vbo,
620 colors_vbo, texcoords_vbo, selected_colors_vbo,
621 selectedObject,
622 shaderCounts, curShaderBase);
623 renderSceneGui();
624 break;
625 }
626
627 glfwSwapBuffers(window);
628
629 if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
630 glfwSetWindowShouldClose(window, 1);
631 }
632
633 float dist = cam_speed * elapsed_seconds;
634 if (glfwGetKey(window, GLFW_KEY_A)) {
635 cam_pos.x -= cos(cam_yaw)*dist;
636 cam_pos.z += sin(cam_yaw)*dist;
637
638 cam_moved = true;
639 }
640 if (glfwGetKey(window, GLFW_KEY_D)) {
641 cam_pos.x += cos(cam_yaw)*dist;
642 cam_pos.z -= sin(cam_yaw)*dist;
643
644 cam_moved = true;
645 }
646 if (glfwGetKey(window, GLFW_KEY_W)) {
647 cam_pos.x -= sin(cam_yaw)*dist;
648 cam_pos.z -= cos(cam_yaw)*dist;
649
650 cam_moved = true;
651 }
652 if (glfwGetKey(window, GLFW_KEY_S)) {
653 cam_pos.x += sin(cam_yaw)*dist;
654 cam_pos.z += cos(cam_yaw)*dist;
655
656 cam_moved = true;
657 }
658 if (glfwGetKey(window, GLFW_KEY_LEFT)) {
659 cam_yaw += cam_yaw_speed * elapsed_seconds;
660 cam_moved = true;
661 }
662 if (glfwGetKey(window, GLFW_KEY_RIGHT)) {
663 cam_yaw -= cam_yaw_speed * elapsed_seconds;
664 cam_moved = true;
665 }
666 if (cam_moved) {
667 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
668 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
669
670 view_mat = R*T;
671
672 glUseProgram(color_sp);
673 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
674
675 glUseProgram(texture_sp);
676 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
677
678 cam_moved = false;
679 }
680 }
681
682 ImGui_ImplGlfwGL3_Shutdown();
683 ImGui::DestroyContext();
684
685 glfwDestroyWindow(window);
686 glfwTerminate();
687
688 return 0;
689}
690
691void glfw_error_callback(int error, const char* description) {
692 gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
693}
694
695void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
696 double mouse_x, mouse_y;
697 glfwGetCursorPos(window, &mouse_x, &mouse_y);
698
699 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
700 cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
701 selectedObject = NULL;
702
703 float x = (2.0f*mouse_x) / width - 1.0f;
704 float y = 1.0f - (2.0f*mouse_y) / height;
705
706 cout << "x: " << x << ", y: " << y << endl;
707
708 vec4 ray_clip = vec4(x, y, -1.0f, 1.0f);
709 vec4 ray_eye = inverse(proj_mat) * ray_clip;
710 ray_eye = vec4(ray_eye.xy(), -1.0f, 1.0f);
711 vec4 ray_world = inverse(view_mat) * ray_eye;
712
713 vec4 cam_pos_temp = vec4(cam_pos, 1.0f);
714
715 vec4 click_point;
716 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
717 SceneObject* closest_object = NULL;
718
719 for (vector<SceneObject>::iterator it = objects.begin(); it != objects.end(); it++) {
720 for (unsigned int p_idx = 0; p_idx < it->points.size(); p_idx += 9) {
721 if (faceClicked(
722 {
723 vec3(it->points[p_idx], it->points[p_idx + 1], it->points[p_idx + 2]),
724 vec3(it->points[p_idx + 3], it->points[p_idx + 4], it->points[p_idx + 5]),
725 vec3(it->points[p_idx + 6], it->points[p_idx + 7], it->points[p_idx + 8]),
726 },
727 &*it, ray_world, cam_pos_temp, click_point
728 )) {
729 click_point = view_mat * click_point;
730
731 if (-NEAR_CLIP >= click_point.z && click_point.z > -FAR_CLIP && click_point.z > closest_point.z) {
732 closest_point = click_point.xyz();
733 closest_object = &*it;
734 }
735 }
736 }
737 }
738
739 if (closest_object == NULL) {
740 cout << "No object was clicked" << endl;
741 } else {
742 clickedObject = closest_object;
743 cout << "Clicked object: " << clickedObject->id << endl;
744 }
745 }
746}
747
748void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
749 key_state[key] = action;
750
751 // should be true for GLFW_PRESS and GLFW_REPEAT
752 key_pressed[key] = (action != GLFW_RELEASE);
753}
754
755
756GLuint loadShader(GLenum type, string file) {
757 cout << "Loading shader from file " << file << endl;
758
759 ifstream shaderFile(file);
760 GLuint shaderId = 0;
761
762 if (shaderFile.is_open()) {
763 string line, shaderString;
764
765 while(getline(shaderFile, line)) {
766 shaderString += line + "\n";
767 }
768 shaderFile.close();
769 const char* shaderCString = shaderString.c_str();
770
771 shaderId = glCreateShader(type);
772 glShaderSource(shaderId, 1, &shaderCString, NULL);
773 glCompileShader(shaderId);
774
775 cout << "Loaded successfully" << endl;
776 } else {
777 cout << "Failed to load the file" << endl;
778 }
779
780 return shaderId;
781}
782
783GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
784 GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
785 GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
786
787 GLuint shader_program = glCreateProgram();
788 glAttachShader(shader_program, vs);
789 glAttachShader(shader_program, fs);
790
791 glLinkProgram(shader_program);
792
793 return shader_program;
794}
795
796unsigned char* loadImage(string file_name, int* x, int* y) {
797 int n;
798 int force_channels = 4; // This forces RGBA (4 bytes per pixel)
799 unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
800
801 int width_in_bytes = *x * 4;
802 unsigned char *top = NULL;
803 unsigned char *bottom = NULL;
804 unsigned char temp = 0;
805 int half_height = *y / 2;
806
807 // flip image upside-down to account for OpenGL treating lower-left as (0, 0)
808 for (int row = 0; row < half_height; row++) {
809 top = image_data + row * width_in_bytes;
810 bottom = image_data + (*y - row - 1) * width_in_bytes;
811 for (int col = 0; col < width_in_bytes; col++) {
812 temp = *top;
813 *top = *bottom;
814 *bottom = temp;
815 top++;
816 bottom++;
817 }
818 }
819
820 if (!image_data) {
821 fprintf(stderr, "ERROR: could not load %s\n", file_name.c_str());
822 }
823
824 // Not Power-of-2 check
825 if ((*x & (*x - 1)) != 0 || (*y & (*y - 1)) != 0) {
826 fprintf(stderr, "WARNING: texture %s is not power-of-2 dimensions\n", file_name.c_str());
827 }
828
829 return image_data;
830}
831
832bool faceClicked(array<vec3, 3> points, SceneObject* obj, vec4 world_ray, vec4 cam, vec4& click_point) {
833 // LINE EQUATION: P = O + Dt
834 // O = cam
835 // D = ray_world
836
837 // PLANE EQUATION: P dot n + d = 0
838 // n is the normal vector
839 // d is the offset from the origin
840
841 // Take the cross-product of two vectors on the plane to get the normal
842 vec3 v1 = points[1] - points[0];
843 vec3 v2 = points[2] - points[0];
844
845 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);
846
847 vec3 local_ray = (inverse(obj->model_mat) * world_ray).xyz();
848 vec3 local_cam = (inverse(obj->model_mat) * cam).xyz();
849
850 local_ray = local_ray - local_cam;
851
852 float d = -glm::dot(points[0], normal);
853 float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
854
855 vec3 intersection = local_cam + t*local_ray;
856
857 if (insideTriangle(intersection, points)) {
858 click_point = obj->model_mat * vec4(intersection, 1.0f);
859 return true;
860 } else {
861 return false;
862 }
863}
864
865bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
866 vec3 v21 = triangle_points[1] - triangle_points[0];
867 vec3 v31 = triangle_points[2] - triangle_points[0];
868 vec3 pv1 = p - triangle_points[0];
869
870 float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
871 float x = (pv1.x-y*v31.x) / v21.x;
872
873 return x > 0.0f && y > 0.0f && x+y < 1.0f;
874}
875
876void printVector(string label, vec3 v) {
877 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
878}
879
880void print4DVector(string label, vec4 v) {
881 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << "," << v.w << ")" << endl;
882}
883
884void addObjectToScene(SceneObject& obj) {
885 obj.id = objects.size(); // currently unused
886 obj.num_points = obj.points.size() / 3;
887
888 obj.normals.reserve(obj.points.size());
889 for (int i = 0; i < obj.points.size(); i += 9) {
890 vec3 point1 = vec3(obj.points[i], obj.points[i + 1], obj.points[i + 2]);
891 vec3 point2 = vec3(obj.points[i + 3], obj.points[i + 4], obj.points[i + 5]);
892 vec3 point3 = vec3(obj.points[i + 6], obj.points[i + 7], obj.points[i + 8]);
893
894 vec3 normal = normalize(cross(point2 - point1, point3 - point1));
895
896 // Add the same normal for all 3 points
897 for (int j = 0; j < 3; j++) {
898 obj.normals.push_back(normal.x);
899 obj.normals.push_back(normal.y);
900 obj.normals.push_back(normal.z);
901 }
902 }
903
904 objects.push_back(obj);
905}
906
907void populateBuffers(vector<SceneObject>& objects,
908 GLuint* points_vbo,
909 GLuint* colors_vbo,
910 GLuint* selected_colors_vbo,
911 GLuint* texcoords_vbo,
912 GLuint* normals_vbo,
913 GLuint* ubo,
914 GLuint* model_mat_idx_vbo,
915 map<GLuint, unsigned int>& shaderCounts,
916 map<GLuint, unsigned int>& curShaderBase) {
917 GLsizeiptr points_buffer_size = 0;
918 GLsizeiptr textures_buffer_size = 0;
919 GLsizeiptr ubo_buffer_size = 0;
920 GLsizeiptr model_mat_idx_buffer_size = 0;
921
922 map<GLuint, unsigned int> curShaderOffset;
923
924 map<GLuint, unsigned int> shaderUboCounts;
925 map<GLuint, unsigned int> curShaderUboBase;
926 map<GLuint, unsigned int> curShaderUboOffset;
927
928 vector<SceneObject>::iterator it;
929
930 /* Find all shaders that need to be used and the number of objects and
931 * number of points for each shader. Construct a map from shader id to count
932 * of points being drawn using that shader (for thw model matrix ubo, we
933 * need object counts instead). These will be used to get offsets into the
934 * vertex buffer for each shader.
935 */
936 for (it = objects.begin(); it != objects.end(); it++) {
937 points_buffer_size += it->points.size() * sizeof(GLfloat);
938 textures_buffer_size += it->texcoords.size() * sizeof(GLfloat);
939 ubo_buffer_size += 16 * sizeof(GLfloat);
940 model_mat_idx_buffer_size += it->num_points * sizeof(GLuint);
941
942 if (shaderCounts.count(it->shader_program) == 0) {
943 shaderCounts[it->shader_program] = it->num_points;
944 shaderUboCounts[it->shader_program] = 1;
945 } else {
946 shaderCounts[it->shader_program] += it->num_points;
947 shaderUboCounts[it->shader_program]++;
948 }
949 }
950
951 map<GLuint, unsigned int>::iterator shaderIt;
952 unsigned int lastShaderCount = 0;
953 unsigned int lastShaderUboCount = 0;
954
955 /*
956 * The counts calculated above can be used to get the starting offset of
957 * each shader in the vertex buffer. Create a map of base offsets to mark
958 * where the data for the first object using a given shader begins. Also,
959 * create a map of current offsets to mark where to copy data for the next
960 * object being added.
961 */
962 cout << "Shader counts:" << endl;
963 for (shaderIt = shaderCounts.begin(); shaderIt != shaderCounts.end(); shaderIt++) {
964 curShaderOffset[shaderIt->first] = 0;
965 curShaderUboOffset[shaderIt->first] = 0;
966
967 curShaderBase[shaderIt->first] = lastShaderCount;
968 lastShaderCount += shaderCounts[shaderIt->first];
969
970 curShaderUboBase[shaderIt->first] = lastShaderUboCount;
971 lastShaderUboCount += shaderUboCounts[shaderIt->first];
972 }
973
974 // Initialize all the buffers using the counts calculated above
975
976 *points_vbo = 0;
977 glGenBuffers(1, points_vbo);
978 glBindBuffer(GL_ARRAY_BUFFER, *points_vbo);
979 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
980
981 *colors_vbo = 0;
982 glGenBuffers(1, colors_vbo);
983 glBindBuffer(GL_ARRAY_BUFFER, *colors_vbo);
984 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
985
986 *selected_colors_vbo = 0;
987 glGenBuffers(1, selected_colors_vbo);
988 glBindBuffer(GL_ARRAY_BUFFER, *selected_colors_vbo);
989 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
990
991 *texcoords_vbo = 0;
992 glGenBuffers(1, texcoords_vbo);
993 glBindBuffer(GL_ARRAY_BUFFER, *texcoords_vbo);
994 glBufferData(GL_ARRAY_BUFFER, textures_buffer_size, NULL, GL_DYNAMIC_DRAW);
995
996 *normals_vbo = 0;
997 glGenBuffers(1, normals_vbo);
998 glBindBuffer(GL_ARRAY_BUFFER, *normals_vbo);
999 glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
1000
1001 *ubo = 0;
1002 glGenBuffers(1, ubo);
1003 glBindBuffer(GL_UNIFORM_BUFFER, *ubo);
1004 glBufferData(GL_UNIFORM_BUFFER, ubo_buffer_size, NULL, GL_DYNAMIC_DRAW);
1005
1006 *model_mat_idx_vbo = 0;
1007 glGenBuffers(1, model_mat_idx_vbo);
1008 glBindBuffer(GL_ARRAY_BUFFER, *model_mat_idx_vbo);
1009 glBufferData(GL_ARRAY_BUFFER, model_mat_idx_buffer_size, NULL, GL_DYNAMIC_DRAW);
1010
1011 GLint vertex_ubo_offset;
1012 for (it = objects.begin(); it != objects.end(); it++) {
1013 it->vertex_vbo_offset = curShaderBase[it->shader_program] + curShaderOffset[it->shader_program];
1014 vertex_ubo_offset = curShaderUboBase[it->shader_program] + curShaderUboOffset[it->shader_program];
1015
1016 glBindBuffer(GL_ARRAY_BUFFER, *points_vbo);
1017 glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->points.size() * sizeof(GLfloat), &it->points[0]);
1018
1019 glBindBuffer(GL_ARRAY_BUFFER, *colors_vbo);
1020 glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->colors.size() * sizeof(GLfloat), &it->colors[0]);
1021
1022 glBindBuffer(GL_ARRAY_BUFFER, *selected_colors_vbo);
1023 glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->selected_colors.size() * sizeof(GLfloat), &it->selected_colors[0]);
1024
1025 glBindBuffer(GL_ARRAY_BUFFER, *texcoords_vbo);
1026 glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 2, it->texcoords.size() * sizeof(GLfloat), &it->texcoords[0]);
1027
1028 glBindBuffer(GL_ARRAY_BUFFER, *normals_vbo);
1029 glBufferSubData(GL_ARRAY_BUFFER, it->vertex_vbo_offset * sizeof(GLfloat) * 3, it->normals.size() * sizeof(GLfloat), &it->normals[0]);
1030
1031 glBindBuffer(GL_ARRAY_BUFFER, *model_mat_idx_vbo);
1032 for (int i = 0; i < it->num_points; i++) {
1033 glBufferSubData(GL_ARRAY_BUFFER, (it->vertex_vbo_offset + i) * sizeof(GLuint), sizeof(GLuint), &vertex_ubo_offset);
1034 }
1035
1036 curShaderOffset[it->shader_program] += it->num_points;
1037
1038 glBindBuffer(GL_UNIFORM_BUFFER, *ubo);
1039 glBufferSubData(GL_UNIFORM_BUFFER, vertex_ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(it->model_mat));
1040
1041 curShaderUboOffset[it->shader_program]++;
1042 }
1043}
1044
1045void renderScene(vector<SceneObject>& objects,
1046 GLuint color_sp, GLuint texture_sp,
1047 GLuint vao1, GLuint vao2,
1048 GLuint points_vbo, GLuint normals_vbo,
1049 GLuint colors_vbo, GLuint texcoords_vbo, GLuint selected_colors_vbo,
1050 SceneObject* selectedObject,
1051 map<GLuint, unsigned int>& shaderCounts,
1052 map<GLuint, unsigned int>& curShaderBase) {
1053
1054 glUseProgram(color_sp);
1055 glBindVertexArray(vao1);
1056
1057 if (selectedObject != NULL) {
1058 glBindBuffer(GL_ARRAY_BUFFER, selected_colors_vbo);
1059 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
1060
1061 glDrawArrays(GL_TRIANGLES, selectedObject->vertex_vbo_offset, selectedObject->num_points);
1062 }
1063
1064 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
1065 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
1066
1067 glDrawArrays(GL_TRIANGLES, curShaderBase[color_sp], shaderCounts[color_sp]);
1068
1069 glUseProgram(texture_sp);
1070 glBindVertexArray(vao2);
1071
1072 glDrawArrays(GL_TRIANGLES, curShaderBase[texture_sp], shaderCounts[texture_sp]);
1073}
1074
1075void renderSceneGui() {
1076 ImGui_ImplGlfwGL3_NewFrame();
1077
1078 // 1. Show a simple window.
1079 // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets automatically appears in a window called "Debug".
1080 /*
1081 {
1082 static float f = 0.0f;
1083 static int counter = 0;
1084 ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
1085 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
1086 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
1087
1088 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our windows open/close state
1089 ImGui::Checkbox("Another Window", &show_another_window);
1090
1091 if (ImGui::Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated)
1092 counter++;
1093 ImGui::SameLine();
1094 ImGui::Text("counter = %d", counter);
1095
1096 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
1097 }
1098 */
1099
1100 {
1101 ImGui::SetNextWindowSize(ImVec2(85, 22), ImGuiCond_Once);
1102 ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once);
1103 ImGui::Begin("WndStats", NULL,
1104 ImGuiWindowFlags_NoTitleBar |
1105 ImGuiWindowFlags_NoResize |
1106 ImGuiWindowFlags_NoMove);
1107 ImGui::Text("Score: ???");
1108 ImGui::End();
1109 }
1110
1111 {
1112 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once);
1113 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once);
1114 ImGui::Begin("WndMenubar", NULL,
1115 ImGuiWindowFlags_NoTitleBar |
1116 ImGuiWindowFlags_NoResize |
1117 ImGuiWindowFlags_NoMove);
1118 ImGui::InvisibleButton("", ImVec2(155, 18));
1119 ImGui::SameLine();
1120 if (ImGui::Button("Main Menu")) {
1121 events.push(EVENT_GO_TO_MAIN_MENU);
1122 }
1123 ImGui::End();
1124 }
1125
1126 ImGui::Render();
1127 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
1128}
1129
1130void renderMainMenu() {
1131}
1132
1133void renderMainMenuGui() {
1134 ImGui_ImplGlfwGL3_NewFrame();
1135
1136 {
1137 int padding = 4;
1138 ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once);
1139 ImGui::SetNextWindowSize(ImVec2(width + 2 * padding, height + 2 * padding), ImGuiCond_Once);
1140 ImGui::Begin("WndMain", NULL,
1141 ImGuiWindowFlags_NoTitleBar |
1142 ImGuiWindowFlags_NoResize |
1143 ImGuiWindowFlags_NoMove);
1144
1145 ImGui::InvisibleButton("", ImVec2(10, 80));
1146 ImGui::InvisibleButton("", ImVec2(285, 18));
1147 ImGui::SameLine();
1148 if (ImGui::Button("New Game")) {
1149 events.push(EVENT_GO_TO_GAME);
1150 }
1151
1152 ImGui::InvisibleButton("", ImVec2(10, 15));
1153 ImGui::InvisibleButton("", ImVec2(300, 18));
1154 ImGui::SameLine();
1155 if (ImGui::Button("Quit")) {
1156 events.push(EVENT_QUIT);
1157 }
1158
1159 ImGui::End();
1160 }
1161
1162 ImGui::Render();
1163 ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
1164}
Note: See TracBrowser for help on using the repository browser.