From ce608edde518d78b32112f7c1af40261c59cdf48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C5=A0toura=C4=8D?= <525032@mail.muni.cz>
Date: Fri, 13 Oct 2023 21:08:07 +0200
Subject: [PATCH] added ortho/persp switch and raycast for ortho

---
 src/algo/src/raycast.cpp                      | 49 ++++++++++++++++---
 src/controls/include/controls/control_hub.hpp |  2 +-
 src/controls/src/control_hub.cpp              |  3 ++
 src/gfx/include/gfx/camera.hpp                |  4 ++
 src/gfx/src/render.cpp                        | 14 ++++--
 5 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/src/algo/src/raycast.cpp b/src/algo/src/raycast.cpp
index 078c515..82d3bec 100644
--- a/src/algo/src/raycast.cpp
+++ b/src/algo/src/raycast.cpp
@@ -72,12 +72,8 @@ node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_pos
     return nearest_node;
 }
 
-std::pair<glm::vec3, glm::vec3> get_pick_ray(const scene_ptr &scene, const osi::Mouse &mouse, const osi::Window &window)
+std::pair<glm::vec3, glm::vec3> get_pick_ray_perspective(const camera_ptr &camera, const glm::mat4 view, const osi::Mouse &mouse, const osi::Window &window)
 {
-    camera_ptr camera = scene->getActiveCameras()[0].lock(); // Should be changed to which viewport is in focus
-    glm::mat4 view = get_view_matrix(camera);
-    glm::mat4 projection = get_projection_matrix(camera);
-    
     // https://gamedev.stackexchange.com/questions/12360/how-do-you-determine-which-object-surface-the-users-pointing-at-with-lwjgl/12370#12370
     //get the mouse position in screenSpace coords
     float aspect_ratio = camera->getWindowSize().x / camera->getWindowSize().y;
@@ -110,9 +106,48 @@ std::pair<glm::vec3, glm::vec3> get_pick_ray(const scene_ptr &scene, const osi::
 
     ray_direction = camera->getFrame()->getRotation() * ray_direction;
 
-    /* VISUAL REPRESENTATION OF RAY */
+     /* VISUAL REPRESENTATION OF RAY */
     // addRay(ray_position, ray_direction);
 
     ray_direction = glm::normalize(ray_direction);
 
-    return {ray_position, ray_direction};}
\ No newline at end of file
+    return {ray_position, ray_direction};
+}
+
+std::pair<glm::vec3, glm::vec3> get_pick_ray_ortho(const camera_ptr &camera, const glm::mat4 view, const osi::Mouse &mouse, const osi::Window &window)
+{
+    // https://stackoverflow.com/a/66813405
+
+    // get x and y coordinates relative to frustum width and height.
+    // glOrthoWidth and glOrthoHeight are the sizeX and sizeY values 
+    // you created your projection matrix with. If your frustum has a width of 100, 
+    // x would become -50 when the mouse is left and +50 when the mouse is right.
+
+    // NOTE: the / 2.0f / 128.0f corresponds to dividing numbers in render.cpp (get_projection_matrix)
+    float x = +(2.0f * (float) mouse.pos().x / window.size().x  - 1) * (window.size().x / 2.0f / 128.0f);
+    float y = -(2.0f * (float) mouse.pos().y / window.size().y - 1) * (window.size().y / 2.0f / 128.0f);
+
+    // Now, you want to calculate the camera's local right and up vectors 
+    // (depending on the camera's current view direction):
+    glm::vec3 cameraRight = camera->getFrame()->getRotationAxisX();
+    glm::vec3 cameraUp = camera->getFrame()->getRotationAxisY();
+
+    // Finally, calculate the ray origin:
+    glm::vec3 ray_position = camera->getFrame()->getPosition() + cameraRight * x + cameraUp * y;
+    glm::vec3 ray_direction = -camera->getFrame()->getRotationAxisZ();;
+
+    ray_direction = glm::normalize(ray_direction);
+
+    return {ray_position, ray_direction};
+}
+
+std::pair<glm::vec3, glm::vec3> get_pick_ray(const scene_ptr &scene, const osi::Mouse &mouse, const osi::Window &window)
+{
+    camera_ptr camera = scene->getActiveCameras()[0].lock(); // Should be changed to which viewport is in focus
+    glm::mat4 view = get_view_matrix(camera);
+    glm::mat4 projection = get_projection_matrix(camera);
+
+    
+    return camera->isPerspective() ? get_pick_ray_perspective(camera, view, mouse, window) 
+                                   : get_pick_ray_ortho(camera, view, mouse, window);
+}
\ No newline at end of file
diff --git a/src/controls/include/controls/control_hub.hpp b/src/controls/include/controls/control_hub.hpp
index f516589..f7b8b86 100644
--- a/src/controls/include/controls/control_hub.hpp
+++ b/src/controls/include/controls/control_hub.hpp
@@ -45,7 +45,7 @@ public:
                       const osi::Window &window, 
                       bool &editor_running);
 
-    /* Methods for manul in-code control */
+    /* Methods for manual in-code control */
     void rotate_cam(glm::vec3 rotation);
     void rotate_obj(glm::vec3 rotation);
 
diff --git a/src/controls/src/control_hub.cpp b/src/controls/src/control_hub.cpp
index 40f0a11..3b240db 100644
--- a/src/controls/src/control_hub.cpp
+++ b/src/controls/src/control_hub.cpp
@@ -45,6 +45,9 @@ void ControlHub::processInput(const scene_ptr &scene, const osi::Keyboard &keybo
         active_camera_type->keyboardMove(keyboard.down());
     }
 
+    if (keyboard.just_pressed().contains("C"))
+        scene->getActiveCameras()[0].lock()->setPerspective(!scene->getActiveCameras()[0].lock()->isPerspective());
+
     // int fill_mode = keyboard.down().contains("X") ? GL_LINE : GL_FILL; // TO DO: put elsewhere
     // glPolygonMode(GL_FRONT_AND_BACK, fill_mode);
     // ASSUMPTION(glGetError() == GL_NO_ERROR);
diff --git a/src/gfx/include/gfx/camera.hpp b/src/gfx/include/gfx/camera.hpp
index c3727e8..d8930c6 100644
--- a/src/gfx/include/gfx/camera.hpp
+++ b/src/gfx/include/gfx/camera.hpp
@@ -14,6 +14,7 @@ class Camera : public ObjectBase
 {
     float FOV = 45.0f;
     glm::u32vec2 window_size = glm::u32vec2{0, 0};
+    bool is_perspective = true;
 
     frame_weak_ptr frame;
 
@@ -26,6 +27,9 @@ public:
     glm::vec2 getWindowSize() const;
     void setWindowSize(glm::u32vec2 _window_size);
 
+    bool isPerspective() const { return is_perspective; }
+    void setPerspective(bool _is_perspective) { is_perspective = _is_perspective; }
+
     frame_ptr getFrame() const
     {
         frame_ptr f = frame.lock();
diff --git a/src/gfx/src/render.cpp b/src/gfx/src/render.cpp
index 78d7101..4d808eb 100644
--- a/src/gfx/src/render.cpp
+++ b/src/gfx/src/render.cpp
@@ -69,10 +69,16 @@ glm::mat4 get_view_matrix(camera_ptr camera)
 
 glm::mat4 get_projection_matrix(camera_ptr camera)
 {
-    return glm::perspective(glm::radians(camera->getFOV()), 
-                            camera->getWindowSize().x / camera->getWindowSize().y, 
-                            0.1f, 
-                            100.0f);
+    return camera->isPerspective() ? 
+            glm::perspective(glm::radians(camera->getFOV()), 
+                             camera->getWindowSize().x / camera->getWindowSize().y, 
+                             0.1f, 
+                             100.0f) 
+            : 
+            glm::ortho(-camera->getWindowSize().x / 2.0f / 128.0f, camera->getWindowSize().x / 2.0f / 128.0f, 
+                       -camera->getWindowSize().y / 2.0f / 128.0f, camera->getWindowSize().y / 2.0f / 128.0f,
+                       0.1f,
+                       100.0f);
 }
 
 void draw_objects(std::map<std::string, shader_ptr> &my_shaders, std::vector<light_ptr> lights,
-- 
GitLab