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

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

Created a faceClicked method to encapsulate checking for the intersection of the world ray with a given face, and check all the faces in the scene when trying to determine which object was clicked.

  • Property mode set to 100644
File size: 24.8 KB
Line 
1#include "logger.h"
2
3#include "stb_image.h"
4
5#define _USE_MATH_DEFINES
6#define GLM_SWIZZLE
7
8// This is to fix a non-alignment issue when passing vec4 params.
9// Check if it got fixed in a later version of GLM
10#define GLM_FORCE_PURE
11
12#include <glm/mat4x4.hpp>
13#include <glm/gtc/matrix_transform.hpp>
14#include <glm/gtc/type_ptr.hpp>
15
16#include <GL/glew.h>
17#include <GLFW/glfw3.h>
18
19#include <cstdio>
20#include <iostream>
21#include <fstream>
22#include <cmath>
23#include <string>
24#include <array>
25#include <vector>
26
27using namespace std;
28using namespace glm;
29
30#define ONE_DEG_IN_RAD (2.0 * M_PI) / 360.0 // 0.017444444
31
32struct SceneObject {
33 mat4 model_mat;
34};
35
36struct ObjectFace {
37 unsigned int objectId;
38 array<vec3, 3> points;
39};
40
41const bool FULLSCREEN = false;
42int width = 640;
43int height = 480;
44
45vec3 cam_pos;
46
47mat4 view_mat;
48mat4 proj_mat;
49
50vector<SceneObject> objects;
51vector<ObjectFace> faces;
52
53SceneObject* clickedObject = NULL;
54SceneObject* selectedObject = NULL;
55
56bool faceClicked(ObjectFace* face, vec4 world_ray, vec4 cam);
57bool insideTriangle(vec3 p, array<vec3, 3> triangle_points);
58
59GLuint loadShader(GLenum type, string file);
60GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath);
61unsigned char* loadImage(string file_name, int* x, int* y);
62
63void printVector(string label, vec3 v);
64
65float NEAR_CLIP = 0.1f;
66float FAR_CLIP = 100.0f;
67
68void glfw_error_callback(int error, const char* description) {
69 gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
70}
71
72void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
73 /*
74 double mouse_x, mouse_y;
75 glfwGetCursorPos(window, &mouse_x, &mouse_y);
76
77 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
78 cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
79
80 float x = (2.0f*mouse_x) / width - 1.0f;
81 float y = 1.0f - (2.0f*mouse_y) / height;
82 cout << "x: " << x << ", y: " << y << endl;
83
84 // Since the projection matrix gets applied before the view matrix,
85 // treat the initial camera position (aka origin of the ray) as (0, 0, 0)
86
87 // When getting the ray direction, you can use near and fov to get the
88 // coordinates
89
90 vec4 ray_clip = vec4(x, y, -1.0f, 1.0f); // this should have a z equal to the near clipping plane
91 vec4 ray_eye = inverse(proj_mat) * ray_clip;
92 ray_eye = vec4(ray_eye.xy(), -1.0f, 0.0f);
93 vec3 ray_world = normalize((inverse(view_mat) * ray_eye).xyz());
94
95 / * LATEST NOTES:
96 *
97 * Normalizing the world ray caused issues, although it should make sense with the projection
98 * matrix, since the z coordinate has meaning there.
99 *
100 * Now, I need to figure out the correct intersection test in 2D space
101 * Also, need to check that the global triangle points are correct
102 * /
103
104 // since ray_world is the end result we want anyway, we probably don't need to add cam_pos to
105 // it, only to subtract it later
106
107 vec3 click_point = cam_pos + ray_world;
108
109 / * Now, we need to generate the constants for the equations describing
110 * a 3D line:
111 * (x - x0) / a = (y - y0) / b = (z - z0) / c
112 *
113 * The line goes through the camera position, so
114 * cam_pos = <x0, y0, z0>
115 * /
116
117 // upper right corner is 1, 1 in opengl
118
119 cout << "Converted -> (" << ray_world.x << "," << ray_world.y << "," << ray_world.z << ")" << endl << endl;;
120 cout << "Camera -> (" << cam_pos.x << "," << cam_pos.y << "," << cam_pos.z << ")" << endl;
121 cout << "Click point -> (" << click_point.x << "," << click_point.y << "," << click_point.z << ")" << endl;
122
123 float a = 1.0f;
124 float b = a * (click_point.y - cam_pos.y) / (click_point.x - cam_pos.x);
125 float c = a * (click_point.z - cam_pos.z) / (click_point.x - cam_pos.x);
126
127 cout << "(x - " << cam_pos.x << ") / " << a << " = ";
128 cout << "(y - " << cam_pos.y << ") / " << b << " = ";
129 cout << "(z - " << cam_pos.z << ") / " << c << endl;;
130
131 / * Now, we need to generate the constants for the equations describing
132 * a 3D plane:
133 * dx + ey +fz +g = 0
134 * /
135
136 vec3 fp1 = triangle_face[0];
137 vec3 fp2 = triangle_face[1];
138 vec3 fp3 = triangle_face[2];
139
140 cout << "Points on the plane" << endl;
141 cout << "(" << fp1.x << ", " << fp1.y << ", " << fp1.z << ")" << endl;
142 cout << "(" << fp2.x << ", " << fp2.y << ", " << fp2.z << ")" << endl;
143 cout << "(" << fp3.x << ", " << fp3.y << ", " << fp3.z << ")" << endl;
144
145 float pa = (fp2.y-fp1.y)*(fp3.z-fp1.z) - (fp3.y-fp1.y)*(fp2.z-fp1.z);
146 float pb = (fp2.z-fp1.z)*(fp3.x-fp1.x) - (fp3.z-fp1.z)*(fp2.x-fp1.x);
147 float pc = (fp2.x-fp1.x)*(fp3.y-fp1.y) - (fp3.x-fp1.x)*(fp2.y-fp1.y);
148 float pd = -(pa*fp1.x+pb*fp1.y+pc*fp1.z);
149
150 cout << pa << "x+" << pb << "y+" << pc << "z+" << pd << "=0" << endl;
151
152 // get intersection
153
154 // the intersection this computes is incorrect
155 // it doesn't match the equation of the plane
156 vec3 i;
157 i.z = -cam_pos.z - pc*pd/(pa*a+pb*b);
158 i.x = cam_pos.x + a * (i.z-cam_pos.z) / c;
159 i.y = cam_pos.y + b * (i.z-cam_pos.z) / c;
160
161 cout << "The holy grail?" << endl;
162 cout << "(" << i.x << "," << i.y << "," << i.z << ")" << endl;
163
164 clicked = insideTriangle(i, triangle_face);
165 cout << (clicked ? "true" : "false") << endl;
166 }
167 */
168}
169
170/* REFACTORING PLAN:
171 *
172 * Have an array of object structs
173 * Each object struct has:
174 * -a model matrix
175 * -a selected boolean
176 * Eventually, maybe also want to store a reference to the correct shader
177 * or whatever other info I need to properly render it
178 *
179 * Have an array of face structs
180 * Each face struct has
181 * -an object index indicating which object it is a part of
182 * -an array of three points
183 *
184 * The mouse button callback will:
185 * -iterate through the faces array
186 * -For each face, it will call faceClicked() with the following params:
187 * -Probably a world ray created from the mouse click coordinates
188 * -An array of 3 points representing the face
189 * -The object struct represnting the object the face is a part of
190 *
191 * -Really, all I need to pass in are the world ray and an ObjectFace reference
192 * -The world ray will first need to be multiplied by the view and projection matrices before being passed in
193 */
194
195void mouse_button_callback_new(GLFWwindow* window, int button, int action, int mods) {
196 double mouse_x, mouse_y;
197 glfwGetCursorPos(window, &mouse_x, &mouse_y);
198
199 if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
200 cout << "Mouse clicked (" << mouse_x << "," << mouse_y << ")" << endl;
201 selectedObject = NULL;
202
203 float x = (2.0f*mouse_x) / width - 1.0f;
204 float y = 1.0f - (2.0f*mouse_y) / height;
205
206 cout << "x: " << x << ", y: " << y << endl;
207
208 // Since the projection matrix gets applied before the view matrix,
209 // treat the initial camera position (aka origin of the ray) as (0, 0, 0)
210
211 // When getting the ray direction, you can use near and fov to get the
212 // coordinates
213
214 // vec4 ray_clip = vec4(x, y, -1.0f, 1.0f); // this should have a z equal to the near clipping plane
215 // vec4 ray_eye = inverse(proj_mat) * ray_clip;
216 // ray_eye = vec4(ray_eye.xy(), -1.0f, 0.0f);
217 // vec3 ray_world = normalize((inverse(view_mat) * ray_eye).xyz());
218
219 vec4 ray_clip = vec4(x, y, NEAR_CLIP, 1.0f); // this should have a z equal to the near clipping plane
220 vec4 ray_eye = ray_clip; // Need to apply the projection matrix here
221 vec4 ray_world = inverse(view_mat) * ray_eye;
222
223 /* LATEST NOTES:
224 *
225 * Normalizing the world ray caused issues, although it should make sense with the projection
226 * matrix, since the z coordinate has meaning there.
227 * Plus, we really want to normalize it only once we recompute it below as the difference of two points,
228 * although doing so shouldn't effect the results. Check the book to see if there is a good reason for doing so.
229 */
230
231 printVector("Initial world ray:", ray_world.xyz());
232
233 vec4 cam_pos_origin = vec4(x, y, 0.0f, 1.0f);
234 vec4 cam_pos_temp = inverse(view_mat) * cam_pos_origin;
235
236 cout << "Ray clip -> (" << ray_clip.x << "," << ray_clip.y << "," << ray_clip.z << ")" << endl << endl;;
237 cout << "Ray world -> (" << ray_world.x << "," << ray_world.y << "," << ray_world.z << ")" << endl << endl;;
238 cout << "Camera -> (" << cam_pos_temp.x << "," << cam_pos_temp.y << "," << cam_pos_temp.z << ")" << endl;
239
240 // Need to account for faces that are behind one another
241 // Using an iterator for the loop makes it difficult to get a reference to each face (for the faceClicked function)
242 for (int i = 0; i<faces.size(); i++) {
243 if (faceClicked(&faces[i], ray_world, cam_pos_temp)) {
244 clickedObject = &objects[faces[i].objectId];
245 cout << "Clicked object: " << faces[i].objectId << endl;
246 break;
247 }
248 }
249
250 if (clickedObject == NULL) {
251 cout << "No object was clicked" << endl;
252 }
253 }
254}
255
256int main(int argc, char* argv[]) {
257 cout << "New OpenGL Game" << endl;
258
259 if (!restart_gl_log()) {}
260 gl_log("starting GLFW\n%s\n", glfwGetVersionString());
261
262 glfwSetErrorCallback(glfw_error_callback);
263 if (!glfwInit()) {
264 fprintf(stderr, "ERROR: could not start GLFW3\n");
265 return 1;
266 }
267
268#ifdef __APPLE__
269 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
270 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
271 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
272 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
273#endif
274
275 glfwWindowHint(GLFW_SAMPLES, 4);
276
277 GLFWwindow* window = NULL;
278
279 if (FULLSCREEN) {
280 GLFWmonitor* mon = glfwGetPrimaryMonitor();
281 const GLFWvidmode* vmode = glfwGetVideoMode(mon);
282
283 cout << "Fullscreen resolution " << vmode->width << "x" << vmode->height << endl;
284 window = glfwCreateWindow(vmode->width, vmode->height, "Extended GL Init", mon, NULL);
285
286 width = vmode->width;
287 height = vmode->height;
288 } else {
289 window = glfwCreateWindow(width, height, "Hello Triangle", NULL, NULL);
290 }
291
292 if (!window) {
293 fprintf(stderr, "ERROR: could not open window with GLFW3\n");
294 glfwTerminate();
295 return 1;
296 }
297
298 bool squareSelected = false;
299
300 glfwSetMouseButtonCallback(window, mouse_button_callback_new);
301
302 glfwMakeContextCurrent(window);
303 glewExperimental = GL_TRUE;
304 glewInit();
305
306 // Check if we might ever need this. If not, remove it.
307 // glViewport(0, 0, width*2, height*2);
308
309 const GLubyte* renderer = glGetString(GL_RENDERER);
310 const GLubyte* version = glGetString(GL_VERSION);
311 printf("Renderer: %s\n", renderer);
312 printf("OpenGL version supported %s\n", version);
313
314 glEnable(GL_DEPTH_TEST);
315 glDepthFunc(GL_LESS);
316
317 glEnable(GL_CULL_FACE);
318 // glCullFace(GL_BACK);
319 // glFrontFace(GL_CW);
320
321 int x, y;
322 unsigned char* texImage = loadImage("test.png", &x, &y);
323 if (texImage) {
324 cout << "Yay, I loaded an image!" << endl;
325 cout << x << endl;
326 cout << y << endl;
327 printf ("first 4 bytes are: %i %i %i %i\n", texImage[0], texImage[1], texImage[2], texImage[3]);
328 }
329
330 GLuint tex = 0;
331 glGenTextures(1, &tex);
332 glActiveTexture(GL_TEXTURE0);
333 glBindTexture(GL_TEXTURE_2D, tex);
334 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);
335
336 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
337 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
338 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
339 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
340
341 GLfloat points[] = {
342 0.0f, 0.5f, 0.0f,
343 -0.5f, -0.5f, 0.0f,
344 0.5f, -0.5f, 0.0f,
345 0.5f, -0.5f, 0.0f,
346 -0.5f, -0.5f, 0.0f,
347 0.0f, 0.5f, 0.0f,
348 };
349
350 GLfloat colors[] = {
351 1.0, 0.0, 0.0,
352 0.0, 0.0, 1.0,
353 0.0, 1.0, 0.0,
354 0.0, 1.0, 0.0,
355 0.0, 0.0, 1.0,
356 1.0, 0.0, 0.0,
357 };
358
359 GLfloat colors_new[] = {
360 0.0, 1.0, 0.0,
361 0.0, 1.0, 0.0,
362 0.0, 1.0, 0.0,
363 0.0, 1.0, 0.0,
364 0.0, 1.0, 0.0,
365 0.0, 1.0, 0.0,
366 };
367
368 // Each point is made of 3 floats
369 int numPoints = (sizeof(points) / sizeof(float)) / 3;
370
371 GLfloat points2[] = {
372 0.5f, 0.5f, 0.0f,
373 -0.5f, 0.5f, 0.0f,
374 -0.5f, -0.5f, 0.0f,
375 0.5f, 0.5f, 0.0f,
376 -0.5f, -0.5f, 0.0f,
377 0.5f, -0.5f, 0.0f,
378 };
379
380 GLfloat colors2[] = {
381 0.0, 0.9, 0.9,
382 0.0, 0.9, 0.9,
383 0.0, 0.9, 0.9,
384 0.0, 0.9, 0.9,
385 0.0, 0.9, 0.9,
386 0.0, 0.9, 0.9,
387 };
388
389 GLfloat texcoords[] = {
390 1.0f, 1.0f,
391 0.0f, 1.0f,
392 0.0, 0.0,
393 1.0, 1.0,
394 0.0, 0.0,
395 1.0, 0.0
396 };
397
398 // Each point is made of 3 floats
399 int numPoints2 = (sizeof(points2) / sizeof(float)) / 3;
400
401 // initialize global variables for click intersection tests
402
403 mat4 T_model, R_model;
404
405 // triangle
406 objects.push_back(SceneObject());
407
408 /*
409 mat4 R_model = rotate(mat4(), 4.0f, vec3(0.0f, 1.0f, 0.0f));
410 */
411 T_model = translate(mat4(), vec3(0.5f, 0.0f, 0.0f));
412 R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
413 objects[0].model_mat = T_model*R_model;
414
415 faces.push_back(ObjectFace());
416 faces[0].objectId = 0;
417 faces[0].points = {
418 vec3(points[0], points[1], points[2]),
419 vec3(points[3], points[4], points[5]),
420 vec3(points[6], points[7], points[8]),
421 };
422
423 // square
424 objects.push_back(SceneObject());
425
426 // mat4 T_model2 = translate(mat4(), vec3(-1.0f, 0.0f, 0.0f));
427 T_model = translate(mat4(), vec3(-0.5f, 0.0f, 0.0f));
428 R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
429 objects[1].model_mat = T_model*R_model;
430
431 faces.push_back(ObjectFace());
432 faces[1].objectId = 1;
433 faces[1].points = {
434 vec3(points2[0], points2[1], points2[2]),
435 vec3(points2[3], points2[4], points2[5]),
436 vec3(points2[6], points2[7], points2[8]),
437 };
438
439 faces.push_back(ObjectFace());
440 faces[2].objectId = 1;
441 faces[2].points = {
442 vec3(points2[9], points2[10], points2[11]),
443 vec3(points2[12], points2[13], points2[14]),
444 vec3(points2[15], points2[16], points2[17]),
445 };
446
447 GLuint points_vbo = 0;
448 glGenBuffers(1, &points_vbo);
449 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
450 glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
451
452 GLuint colors_vbo = 0;
453 glGenBuffers(1, &colors_vbo);
454 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
455 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
456
457 GLuint vao = 0;
458 glGenVertexArrays(1, &vao);
459 glBindVertexArray(vao);
460 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
461 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
462 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
463 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
464
465 glEnableVertexAttribArray(0);
466 glEnableVertexAttribArray(1);
467
468 GLuint points2_vbo = 0;
469 glGenBuffers(1, &points2_vbo);
470 glBindBuffer(GL_ARRAY_BUFFER, points2_vbo);
471 glBufferData(GL_ARRAY_BUFFER, sizeof(points2), points2, GL_STATIC_DRAW);
472
473 GLuint colors2_vbo = 0;
474 glGenBuffers(1, &colors2_vbo);
475 glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
476 glBufferData(GL_ARRAY_BUFFER, sizeof(colors2), colors2, GL_STATIC_DRAW);
477
478 GLuint vt_vbo;
479 glGenBuffers(1, &vt_vbo);
480 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
481 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
482
483 GLuint vao2 = 0;
484 glGenVertexArrays(1, &vao2);
485 glBindVertexArray(vao2);
486 glBindBuffer(GL_ARRAY_BUFFER, points2_vbo);
487 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
488 // glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
489 // glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
490 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
491 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
492
493 glEnableVertexAttribArray(0);
494 glEnableVertexAttribArray(1);
495
496 GLuint shader_program = loadShaderProgram("./color.vert", "./color.frag");
497 GLuint shader_program2 = loadShaderProgram("./texture.vert", "./texture.frag");
498
499 float speed = 1.0f;
500 float last_position = 0.0f;
501
502 float cam_speed = 1.0f;
503 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
504
505 //cam_pos = vec3(0.0f, 0.0f, 2.0f);
506 cam_pos = vec3(0.0f, 0.0f, 0.3f);
507 float cam_yaw = 0.0f * 2.0f * 3.14159f / 360.0f;
508
509 mat4 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
510 mat4 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
511 /*
512 mat4 T = translate(mat4(), vec3(0.0f, 0.0f, 0.0f));
513 mat4 R = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
514 */
515 view_mat = R*T;
516
517 float fov = 67.0f * ONE_DEG_IN_RAD;
518 float aspect = (float)width / (float)height;
519
520 float range = tan(fov * 0.5f) * NEAR_CLIP;
521 float Sx = NEAR_CLIP / (range * aspect);
522 float Sy = NEAR_CLIP / range;
523 float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
524 float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
525
526 /*
527 float proj_arr[] = {
528 Sx, 0.0f, 0.0f, 0.0f,
529 0.0f, Sy, 0.0f, 0.0f,
530 0.0f, 0.0f, Sz, -1.0f,
531 0.0f, 0.0f, Pz, 0.0f,
532 };
533 */
534 float proj_arr[] = {
535 1.0f, 0.0f, 0.0f, 0.0f,
536 0.0f, 1.0f, 0.0f, 0.0f,
537 0.0f, 0.0f, 1.0f, 0.0f,
538 0.0f, 0.0f, 0.0f, 1.0f,
539 };
540 proj_mat = make_mat4(proj_arr);
541
542 GLint model_test_loc = glGetUniformLocation(shader_program, "model");
543 GLint view_test_loc = glGetUniformLocation(shader_program, "view");
544 GLint proj_test_loc = glGetUniformLocation(shader_program, "proj");
545
546 GLint model_mat_loc = glGetUniformLocation(shader_program2, "model");
547 GLint view_mat_loc = glGetUniformLocation(shader_program2, "view");
548 GLint proj_mat_loc = glGetUniformLocation(shader_program2, "proj");
549
550 glUseProgram(shader_program);
551 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[0].model_mat));
552 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
553 glUniformMatrix4fv(proj_test_loc, 1, GL_FALSE, value_ptr(proj_mat));
554
555 glUseProgram(shader_program2);
556 glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, value_ptr(objects[1].model_mat));
557 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
558 glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
559
560 bool cam_moved = false;
561
562 double previous_seconds = glfwGetTime();
563 while (!glfwWindowShouldClose(window)) {
564 double current_seconds = glfwGetTime();
565 double elapsed_seconds = current_seconds - previous_seconds;
566 previous_seconds = current_seconds;
567
568 if (fabs(last_position) > 1.0f) {
569 speed = -speed;
570 }
571
572 if (clickedObject == &objects[0]) {
573 selectedObject = &objects[0];
574 }
575
576 // At some point, I should change this to only rebind the buffer once per click, not once per frame
577 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
578 if (selectedObject == &objects[0]) {
579 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors_new, GL_STATIC_DRAW);
580 }
581 else {
582 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
583 }
584
585 /*
586 model[12] = last_position + speed*elapsed_seconds;
587 last_position = model[12];
588 */
589
590 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
591
592 glUseProgram(shader_program);
593
594 // this is temporary.
595 // It's needed to offset the code for the recoloring of the square working during click detection
596 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[0].model_mat));
597
598 glBindVertexArray(vao);
599
600 glDrawArrays(GL_TRIANGLES, 0, numPoints);
601
602 if (clickedObject == &objects[1]) {
603 squareSelected = !squareSelected;
604 selectedObject = &objects[1];
605 }
606
607 if (selectedObject == &objects[1]) {
608 glUseProgram(shader_program);
609
610 // this is temporary.
611 // It's needed to get the recoloring of the square working during click detection
612 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[1].model_mat));
613
614 glBindVertexArray(vao2);
615
616 glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
617 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
618 } else {
619 glUseProgram(shader_program2);
620
621 glBindVertexArray(vao2);
622
623 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
624 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
625 }
626
627 glDrawArrays(GL_TRIANGLES, 0, numPoints2);
628
629 clickedObject = NULL;
630
631 glfwPollEvents();
632 glfwSwapBuffers(window);
633
634 if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
635 glfwSetWindowShouldClose(window, 1);
636 }
637
638 float dist = cam_speed * elapsed_seconds;
639 if (glfwGetKey(window, GLFW_KEY_A)) {
640 cam_pos.x -= cos(cam_yaw)*dist;
641 cam_pos.z += sin(cam_yaw)*dist;
642 cam_moved = true;
643 }
644 if (glfwGetKey(window, GLFW_KEY_D)) {
645 cam_pos.x += cos(cam_yaw)*dist;
646 cam_pos.z -= sin(cam_yaw)*dist;
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 cam_moved = true;
653 }
654 if (glfwGetKey(window, GLFW_KEY_S)) {
655 cam_pos.x += sin(cam_yaw)*dist;
656 cam_pos.z += cos(cam_yaw)*dist;
657 cam_moved = true;
658 }
659 if (glfwGetKey(window, GLFW_KEY_LEFT)) {
660 cam_yaw += cam_yaw_speed * elapsed_seconds;
661 cam_moved = true;
662 }
663 if (glfwGetKey(window, GLFW_KEY_RIGHT)) {
664 cam_yaw -= cam_yaw_speed * elapsed_seconds;
665 cam_moved = true;
666 }
667 if (cam_moved) {
668 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
669 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
670 // view_mat = R*T;
671
672 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
673 cam_moved = false;
674 }
675 }
676
677 glfwTerminate();
678 return 0;
679}
680
681GLuint loadShader(GLenum type, string file) {
682 cout << "Loading shader from file " << file << endl;
683
684 ifstream shaderFile(file);
685 GLuint shaderId = 0;
686
687 if (shaderFile.is_open()) {
688 string line, shaderString;
689
690 while(getline(shaderFile, line)) {
691 shaderString += line + "\n";
692 }
693 shaderFile.close();
694 const char* shaderCString = shaderString.c_str();
695
696 shaderId = glCreateShader(type);
697 glShaderSource(shaderId, 1, &shaderCString, NULL);
698 glCompileShader(shaderId);
699
700 cout << "Loaded successfully" << endl;
701 } else {
702 cout << "Failed to loade the file" << endl;
703 }
704
705 return shaderId;
706}
707
708GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
709 GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
710 GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
711
712 GLuint shader_program = glCreateProgram();
713 glAttachShader(shader_program, vs);
714 glAttachShader(shader_program, fs);
715
716 glLinkProgram(shader_program);
717
718 return shader_program;
719}
720
721unsigned char* loadImage(string file_name, int* x, int* y) {
722 int n;
723 int force_channels = 4;
724 unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
725 if (!image_data) {
726 fprintf(stderr, "ERROR: could not load %s\n", file_name.c_str());
727 }
728 return image_data;
729}
730
731bool faceClicked(ObjectFace* face, vec4 world_ray, vec4 cam) {
732 cout << "Points on the plane" << endl;
733 printVector("fp1", face->points[0]);
734 printVector("fp2", face->points[1]);
735 printVector("fp3", face->points[2]);
736
737 // LINE EQUATION: P = O + Dt
738 // O = cam_pos
739 // D = ray_world
740
741 // PLANE EQUATION: P dot n + d = 0 (n is the normal vector and d is the offset from the origin)
742
743 // Take the cross-product of two vectors on the plane to get the normal
744 vec3 v1 = face->points[1] - face->points[0];
745 vec3 v2 = face->points[2] - face->points[0];
746
747 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);
748 printVector("v1", v1);
749 printVector("v2", v2);
750 printVector("Cross", normal);
751
752 SceneObject* obj = &objects[face->objectId];
753 vec3 local_ray = (inverse(obj->model_mat) * world_ray).xyz();
754 vec3 local_cam = (inverse(obj->model_mat) * cam).xyz();
755 local_ray = local_ray - local_cam;
756
757 cout << "Test theory: " << glm::dot(local_cam, normal) << endl;
758 cout << "Test 2: " << glm::dot(local_ray, normal) << endl;
759
760 float d = -glm::dot(face->points[0], normal);
761 cout << "d: " << d << endl;
762
763 float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
764 cout << "t: " << t << endl;
765
766 vec3 intersection = local_cam + t*local_ray;
767 printVector("Intersection", intersection);
768
769 return insideTriangle(intersection, face->points);
770}
771
772bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
773 vec3 v21 = triangle_points[1]- triangle_points[0];
774 vec3 v31 = triangle_points[2]- triangle_points[0];
775 vec3 pv1 = p- triangle_points[0];
776
777 float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
778 float x = (pv1.x-y*v31.x) / v21.x;
779
780 cout << "(" << x << ", " << y << ")" << endl;
781
782 return x > 0.0f && y > 0.0f && x+y < 1.0f;
783}
784
785void printVector(string label, vec3 v) {
786 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
787}
Note: See TracBrowser for help on using the repository browser.