source: opengl-game/new-game.cpp@ 0d5c100

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

Create a populateBuffers() function to encapsulate populating all the OpenGL data buffers using for rendering objects in the scene given a list of those objects.

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