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

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

Pass a reference to faceClicked that will be set to the clicked point in world space, and fix the click detection algorithm to set the closest visible object to the camera as having been clicked.

  • Property mode set to 100644
File size: 25.6 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 object_id;
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, vec4& click_point);
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 vec4 click_point;
241 vec3 closest_point;
242 int closest_face_id = -1;
243
244 // Need to account for faces that are behind one another
245 // Using an iterator for the loop makes it difficult to get a reference to each face (for the faceClicked function)
246 for (int i = 0; i<faces.size(); i++) {
247 if (faceClicked(&faces[i], ray_world, cam_pos_temp, click_point)) {
248 click_point = view_mat * click_point;
249
250 // Check against clipping planes once I start applying the projection matrix
251 // if (NEAR_CLIP <= click_point.z && click_point.z < FAR_CLIP && ...) {
252 if (-1.0f <= click_point.z && click_point.z < 1.0f && click_point.z < closest_point.z) {
253 closest_point = click_point.xyz();
254 closest_face_id = i;
255 }
256 }
257 }
258
259 if (closest_face_id == -1) {
260 cout << "No object was clicked" << endl;
261 } else {
262 clickedObject = &objects[faces[closest_face_id].object_id];
263 cout << "Clicked object: " << faces[closest_face_id].object_id << endl;
264 printVector("Click point", closest_point);
265 }
266 }
267}
268
269int main(int argc, char* argv[]) {
270 cout << "New OpenGL Game" << endl;
271
272 if (!restart_gl_log()) {}
273 gl_log("starting GLFW\n%s\n", glfwGetVersionString());
274
275 glfwSetErrorCallback(glfw_error_callback);
276 if (!glfwInit()) {
277 fprintf(stderr, "ERROR: could not start GLFW3\n");
278 return 1;
279 }
280
281#ifdef __APPLE__
282 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
283 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
284 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
285 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
286#endif
287
288 glfwWindowHint(GLFW_SAMPLES, 4);
289
290 GLFWwindow* window = NULL;
291
292 if (FULLSCREEN) {
293 GLFWmonitor* mon = glfwGetPrimaryMonitor();
294 const GLFWvidmode* vmode = glfwGetVideoMode(mon);
295
296 cout << "Fullscreen resolution " << vmode->width << "x" << vmode->height << endl;
297 window = glfwCreateWindow(vmode->width, vmode->height, "Extended GL Init", mon, NULL);
298
299 width = vmode->width;
300 height = vmode->height;
301 } else {
302 window = glfwCreateWindow(width, height, "Hello Triangle", NULL, NULL);
303 }
304
305 if (!window) {
306 fprintf(stderr, "ERROR: could not open window with GLFW3\n");
307 glfwTerminate();
308 return 1;
309 }
310
311 bool squareSelected = false;
312
313 glfwSetMouseButtonCallback(window, mouse_button_callback_new);
314
315 glfwMakeContextCurrent(window);
316 glewExperimental = GL_TRUE;
317 glewInit();
318
319 // Check if we might ever need this. If not, remove it.
320 // glViewport(0, 0, width*2, height*2);
321
322 const GLubyte* renderer = glGetString(GL_RENDERER);
323 const GLubyte* version = glGetString(GL_VERSION);
324 printf("Renderer: %s\n", renderer);
325 printf("OpenGL version supported %s\n", version);
326
327 glEnable(GL_DEPTH_TEST);
328 glDepthFunc(GL_LESS);
329
330 glEnable(GL_CULL_FACE);
331 // glCullFace(GL_BACK);
332 // glFrontFace(GL_CW);
333
334 int x, y;
335 unsigned char* texImage = loadImage("test.png", &x, &y);
336 if (texImage) {
337 cout << "Yay, I loaded an image!" << endl;
338 cout << x << endl;
339 cout << y << endl;
340 printf ("first 4 bytes are: %i %i %i %i\n", texImage[0], texImage[1], texImage[2], texImage[3]);
341 }
342
343 GLuint tex = 0;
344 glGenTextures(1, &tex);
345 glActiveTexture(GL_TEXTURE0);
346 glBindTexture(GL_TEXTURE_2D, tex);
347 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);
348
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
351 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
352 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
353
354 GLfloat points[] = {
355 0.0f, 0.5f, 0.0f,
356 -0.5f, -0.5f, 0.0f,
357 0.5f, -0.5f, 0.0f,
358 0.5f, -0.5f, 0.0f,
359 -0.5f, -0.5f, 0.0f,
360 0.0f, 0.5f, 0.0f,
361 };
362
363 GLfloat colors[] = {
364 1.0, 0.0, 0.0,
365 0.0, 0.0, 1.0,
366 0.0, 1.0, 0.0,
367 0.0, 1.0, 0.0,
368 0.0, 0.0, 1.0,
369 1.0, 0.0, 0.0,
370 };
371
372 GLfloat colors_new[] = {
373 0.0, 1.0, 0.0,
374 0.0, 1.0, 0.0,
375 0.0, 1.0, 0.0,
376 0.0, 1.0, 0.0,
377 0.0, 1.0, 0.0,
378 0.0, 1.0, 0.0,
379 };
380
381 // Each point is made of 3 floats
382 int numPoints = (sizeof(points) / sizeof(float)) / 3;
383
384 GLfloat points2[] = {
385 0.5f, 0.5f, 0.0f,
386 -0.5f, 0.5f, 0.0f,
387 -0.5f, -0.5f, 0.0f,
388 0.5f, 0.5f, 0.0f,
389 -0.5f, -0.5f, 0.0f,
390 0.5f, -0.5f, 0.0f,
391 };
392
393 GLfloat colors2[] = {
394 0.0, 0.9, 0.9,
395 0.0, 0.9, 0.9,
396 0.0, 0.9, 0.9,
397 0.0, 0.9, 0.9,
398 0.0, 0.9, 0.9,
399 0.0, 0.9, 0.9,
400 };
401
402 GLfloat texcoords[] = {
403 1.0f, 1.0f,
404 0.0f, 1.0f,
405 0.0, 0.0,
406 1.0, 1.0,
407 0.0, 0.0,
408 1.0, 0.0
409 };
410
411 // Each point is made of 3 floats
412 int numPoints2 = (sizeof(points2) / sizeof(float)) / 3;
413
414 // initialize global variables for click intersection tests
415
416 mat4 T_model, R_model;
417
418 // triangle
419 objects.push_back(SceneObject());
420
421 /*
422 mat4 R_model = rotate(mat4(), 4.0f, vec3(0.0f, 1.0f, 0.0f));
423 */
424 T_model = translate(mat4(), vec3(0.0f, 0.0f, 0.0f));
425 R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
426 objects[0].model_mat = T_model*R_model;
427
428 faces.push_back(ObjectFace());
429 faces[0].object_id = 0;
430 faces[0].points = {
431 vec3(points[0], points[1], points[2]),
432 vec3(points[3], points[4], points[5]),
433 vec3(points[6], points[7], points[8]),
434 };
435
436 // square
437 objects.push_back(SceneObject());
438
439 // mat4 T_model2 = translate(mat4(), vec3(-1.0f, 0.0f, 0.0f));
440 T_model = translate(mat4(), vec3(-0.5f, 0.0f, 0.1f));
441 R_model = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
442 objects[1].model_mat = T_model*R_model;
443
444 faces.push_back(ObjectFace());
445 faces[1].object_id = 1;
446 faces[1].points = {
447 vec3(points2[0], points2[1], points2[2]),
448 vec3(points2[3], points2[4], points2[5]),
449 vec3(points2[6], points2[7], points2[8]),
450 };
451
452 faces.push_back(ObjectFace());
453 faces[2].object_id = 1;
454 faces[2].points = {
455 vec3(points2[9], points2[10], points2[11]),
456 vec3(points2[12], points2[13], points2[14]),
457 vec3(points2[15], points2[16], points2[17]),
458 };
459
460 GLuint points_vbo = 0;
461 glGenBuffers(1, &points_vbo);
462 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
463 glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
464
465 GLuint colors_vbo = 0;
466 glGenBuffers(1, &colors_vbo);
467 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
468 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
469
470 GLuint vao = 0;
471 glGenVertexArrays(1, &vao);
472 glBindVertexArray(vao);
473 glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
474 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
475 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
476 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
477
478 glEnableVertexAttribArray(0);
479 glEnableVertexAttribArray(1);
480
481 GLuint points2_vbo = 0;
482 glGenBuffers(1, &points2_vbo);
483 glBindBuffer(GL_ARRAY_BUFFER, points2_vbo);
484 glBufferData(GL_ARRAY_BUFFER, sizeof(points2), points2, GL_STATIC_DRAW);
485
486 GLuint colors2_vbo = 0;
487 glGenBuffers(1, &colors2_vbo);
488 glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
489 glBufferData(GL_ARRAY_BUFFER, sizeof(colors2), colors2, GL_STATIC_DRAW);
490
491 GLuint vt_vbo;
492 glGenBuffers(1, &vt_vbo);
493 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
494 glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
495
496 GLuint vao2 = 0;
497 glGenVertexArrays(1, &vao2);
498 glBindVertexArray(vao2);
499 glBindBuffer(GL_ARRAY_BUFFER, points2_vbo);
500 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
501 // glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
502 // glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
503 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
504 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
505
506 glEnableVertexAttribArray(0);
507 glEnableVertexAttribArray(1);
508
509 GLuint shader_program = loadShaderProgram("./color.vert", "./color.frag");
510 GLuint shader_program2 = loadShaderProgram("./texture.vert", "./texture.frag");
511
512 float speed = 1.0f;
513 float last_position = 0.0f;
514
515 float cam_speed = 1.0f;
516 float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
517
518 //cam_pos = vec3(0.0f, 0.0f, 2.0f);
519 cam_pos = vec3(0.0f, 0.0f, 0.3f);
520 float cam_yaw = 0.0f * 2.0f * 3.14159f / 360.0f;
521
522 mat4 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
523 mat4 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
524 /*
525 mat4 T = translate(mat4(), vec3(0.0f, 0.0f, 0.0f));
526 mat4 R = rotate(mat4(), 0.0f, vec3(0.0f, 1.0f, 0.0f));
527 */
528 view_mat = R*T;
529
530 float fov = 67.0f * ONE_DEG_IN_RAD;
531 float aspect = (float)width / (float)height;
532
533 float range = tan(fov * 0.5f) * NEAR_CLIP;
534 float Sx = NEAR_CLIP / (range * aspect);
535 float Sy = NEAR_CLIP / range;
536 float Sz = -(FAR_CLIP + NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
537 float Pz = -(2.0f * FAR_CLIP * NEAR_CLIP) / (FAR_CLIP - NEAR_CLIP);
538
539 /*
540 float proj_arr[] = {
541 Sx, 0.0f, 0.0f, 0.0f,
542 0.0f, Sy, 0.0f, 0.0f,
543 0.0f, 0.0f, Sz, -1.0f,
544 0.0f, 0.0f, Pz, 0.0f,
545 };
546 */
547 float proj_arr[] = {
548 1.0f, 0.0f, 0.0f, 0.0f,
549 0.0f, 1.0f, 0.0f, 0.0f,
550 0.0f, 0.0f, 1.0f, 0.0f,
551 0.0f, 0.0f, 0.0f, 1.0f,
552 };
553 proj_mat = make_mat4(proj_arr);
554
555 GLint model_test_loc = glGetUniformLocation(shader_program, "model");
556 GLint view_test_loc = glGetUniformLocation(shader_program, "view");
557 GLint proj_test_loc = glGetUniformLocation(shader_program, "proj");
558
559 GLint model_mat_loc = glGetUniformLocation(shader_program2, "model");
560 GLint view_mat_loc = glGetUniformLocation(shader_program2, "view");
561 GLint proj_mat_loc = glGetUniformLocation(shader_program2, "proj");
562
563 glUseProgram(shader_program);
564 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[0].model_mat));
565 glUniformMatrix4fv(view_test_loc, 1, GL_FALSE, value_ptr(view_mat));
566 glUniformMatrix4fv(proj_test_loc, 1, GL_FALSE, value_ptr(proj_mat));
567
568 glUseProgram(shader_program2);
569 glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, value_ptr(objects[1].model_mat));
570 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
571 glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, value_ptr(proj_mat));
572
573 bool cam_moved = false;
574
575 double previous_seconds = glfwGetTime();
576 while (!glfwWindowShouldClose(window)) {
577 double current_seconds = glfwGetTime();
578 double elapsed_seconds = current_seconds - previous_seconds;
579 previous_seconds = current_seconds;
580
581 if (fabs(last_position) > 1.0f) {
582 speed = -speed;
583 }
584
585 if (clickedObject == &objects[0]) {
586 selectedObject = &objects[0];
587 }
588
589 // At some point, I should change this to only rebind the buffer once per click, not once per frame
590 glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
591 if (selectedObject == &objects[0]) {
592 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors_new, GL_STATIC_DRAW);
593 }
594 else {
595 glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
596 }
597
598 /*
599 model[12] = last_position + speed*elapsed_seconds;
600 last_position = model[12];
601 */
602
603 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
604
605 glUseProgram(shader_program);
606
607 // this is temporary.
608 // It's needed to offset the code for the recoloring of the square working during click detection
609 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[0].model_mat));
610
611 glBindVertexArray(vao);
612
613 glDrawArrays(GL_TRIANGLES, 0, numPoints);
614
615 if (clickedObject == &objects[1]) {
616 squareSelected = !squareSelected;
617 selectedObject = &objects[1];
618 }
619
620 if (selectedObject == &objects[1]) {
621 glUseProgram(shader_program);
622
623 // this is temporary.
624 // It's needed to get the recoloring of the square working during click detection
625 glUniformMatrix4fv(model_test_loc, 1, GL_FALSE, value_ptr(objects[1].model_mat));
626
627 glBindVertexArray(vao2);
628
629 glBindBuffer(GL_ARRAY_BUFFER, colors2_vbo);
630 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
631 } else {
632 glUseProgram(shader_program2);
633
634 glBindVertexArray(vao2);
635
636 glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
637 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
638 }
639
640 glDrawArrays(GL_TRIANGLES, 0, numPoints2);
641
642 clickedObject = NULL;
643
644 glfwPollEvents();
645 glfwSwapBuffers(window);
646
647 if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
648 glfwSetWindowShouldClose(window, 1);
649 }
650
651 float dist = cam_speed * elapsed_seconds;
652 if (glfwGetKey(window, GLFW_KEY_A)) {
653 cam_pos.x -= cos(cam_yaw)*dist;
654 cam_pos.z += sin(cam_yaw)*dist;
655 cam_moved = true;
656 }
657 if (glfwGetKey(window, GLFW_KEY_D)) {
658 cam_pos.x += cos(cam_yaw)*dist;
659 cam_pos.z -= sin(cam_yaw)*dist;
660 cam_moved = true;
661 }
662 if (glfwGetKey(window, GLFW_KEY_W)) {
663 cam_pos.x -= sin(cam_yaw)*dist;
664 cam_pos.z -= cos(cam_yaw)*dist;
665 cam_moved = true;
666 }
667 if (glfwGetKey(window, GLFW_KEY_S)) {
668 cam_pos.x += sin(cam_yaw)*dist;
669 cam_pos.z += cos(cam_yaw)*dist;
670 cam_moved = true;
671 }
672 if (glfwGetKey(window, GLFW_KEY_LEFT)) {
673 cam_yaw += cam_yaw_speed * elapsed_seconds;
674 cam_moved = true;
675 }
676 if (glfwGetKey(window, GLFW_KEY_RIGHT)) {
677 cam_yaw -= cam_yaw_speed * elapsed_seconds;
678 cam_moved = true;
679 }
680 if (cam_moved) {
681 T = translate(mat4(), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
682 R = rotate(mat4(), -cam_yaw, vec3(0.0f, 1.0f, 0.0f));
683 // view_mat = R*T;
684
685 glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, value_ptr(view_mat));
686 cam_moved = false;
687 }
688 }
689
690 glfwTerminate();
691 return 0;
692}
693
694GLuint loadShader(GLenum type, string file) {
695 cout << "Loading shader from file " << file << endl;
696
697 ifstream shaderFile(file);
698 GLuint shaderId = 0;
699
700 if (shaderFile.is_open()) {
701 string line, shaderString;
702
703 while(getline(shaderFile, line)) {
704 shaderString += line + "\n";
705 }
706 shaderFile.close();
707 const char* shaderCString = shaderString.c_str();
708
709 shaderId = glCreateShader(type);
710 glShaderSource(shaderId, 1, &shaderCString, NULL);
711 glCompileShader(shaderId);
712
713 cout << "Loaded successfully" << endl;
714 } else {
715 cout << "Failed to loade the file" << endl;
716 }
717
718 return shaderId;
719}
720
721GLuint loadShaderProgram(string vertexShaderPath, string fragmentShaderPath) {
722 GLuint vs = loadShader(GL_VERTEX_SHADER, vertexShaderPath);
723 GLuint fs = loadShader(GL_FRAGMENT_SHADER, fragmentShaderPath);
724
725 GLuint shader_program = glCreateProgram();
726 glAttachShader(shader_program, vs);
727 glAttachShader(shader_program, fs);
728
729 glLinkProgram(shader_program);
730
731 return shader_program;
732}
733
734unsigned char* loadImage(string file_name, int* x, int* y) {
735 int n;
736 int force_channels = 4;
737 unsigned char* image_data = stbi_load(file_name.c_str(), x, y, &n, force_channels);
738 if (!image_data) {
739 fprintf(stderr, "ERROR: could not load %s\n", file_name.c_str());
740 }
741 return image_data;
742}
743
744bool faceClicked(ObjectFace* face, vec4 world_ray, vec4 cam, vec4& click_point) {
745 cout << "Points on the plane" << endl;
746 printVector("fp1", face->points[0]);
747 printVector("fp2", face->points[1]);
748 printVector("fp3", face->points[2]);
749
750 // LINE EQUATION: P = O + Dt
751 // O = cam_pos
752 // D = ray_world
753
754 // PLANE EQUATION: P dot n + d = 0 (n is the normal vector and d is the offset from the origin)
755
756 // Take the cross-product of two vectors on the plane to get the normal
757 vec3 v1 = face->points[1] - face->points[0];
758 vec3 v2 = face->points[2] - face->points[0];
759
760 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);
761 printVector("v1", v1);
762 printVector("v2", v2);
763 printVector("Cross", normal);
764
765 SceneObject* obj = &objects[face->object_id];
766 vec3 local_ray = (inverse(obj->model_mat) * world_ray).xyz();
767 vec3 local_cam = (inverse(obj->model_mat) * cam).xyz();
768 local_ray = local_ray - local_cam;
769
770 cout << "Test theory: " << glm::dot(local_cam, normal) << endl;
771 cout << "Test 2: " << glm::dot(local_ray, normal) << endl;
772
773 float d = -glm::dot(face->points[0], normal);
774 cout << "d: " << d << endl;
775
776 float t = -(glm::dot(local_cam, normal) + d) / glm::dot(local_ray, normal);
777 cout << "t: " << t << endl;
778
779 vec3 intersection = local_cam + t*local_ray;
780 printVector("Intersection", intersection);
781
782 if (insideTriangle(intersection, face->points)) {
783 click_point = obj->model_mat * vec4(intersection, 1.0f);
784 return true;
785 } else {
786 return false;
787 }
788}
789
790bool insideTriangle(vec3 p, array<vec3, 3> triangle_points) {
791 vec3 v21 = triangle_points[1]- triangle_points[0];
792 vec3 v31 = triangle_points[2]- triangle_points[0];
793 vec3 pv1 = p- triangle_points[0];
794
795 float y = (pv1.y*v21.x - pv1.x*v21.y) / (v31.y*v21.x - v31.x*v21.y);
796 float x = (pv1.x-y*v31.x) / v21.x;
797
798 cout << "(" << x << ", " << y << ")" << endl;
799
800 return x > 0.0f && y > 0.0f && x+y < 1.0f;
801}
802
803void printVector(string label, vec3 v) {
804 cout << label << " -> (" << v.x << "," << v.y << "," << v.z << ")" << endl;
805}
Note: See TracBrowser for help on using the repository browser.