source: opengl-game/new-game.cpp@ 5c403fe

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

Change the SceneObject definition to include a base model matrix and a transform model matrix, which are multiplied to create the final model matrix. Add a transformObject function that sets the transform matrix and updates the model ubo with the object's new model matrix

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