From 08215c4e987f900af51f0badfa496d3a4966791a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C5=A0toura=C4=8D?= <525032@mail.muni.cz>
Date: Thu, 19 Oct 2023 23:38:40 +0200
Subject: [PATCH] added cube side higlighting (partially works)

---
 src/algo/include/algo/raycast.hpp  |  5 ++-
 src/algo/src/raycast.cpp           | 50 ++++++++++++++++++++++++++++--
 src/common/include/common/aabb.hpp |  5 ++-
 src/common/src/aabb.cpp            | 19 ++++++++++--
 src/edit/include/edit/editor.hpp   |  4 +--
 src/edit/include/edit/scene.hpp    |  3 ++
 src/edit/src/editor.cpp            | 32 +++++++++----------
 src/edit/src/scene.cpp             | 45 +++++++++++++++++++++++++--
 src/studio/src/simulator.cpp       |  8 +++--
 9 files changed, 140 insertions(+), 31 deletions(-)

diff --git a/src/algo/include/algo/raycast.hpp b/src/algo/include/algo/raycast.hpp
index 1aaffe0..104647e 100644
--- a/src/algo/include/algo/raycast.hpp
+++ b/src/algo/include/algo/raycast.hpp
@@ -7,6 +7,7 @@
 #include <osi/window.hpp>
 #include <utils/math.hpp>
 
+#include <array>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -16,7 +17,9 @@ using scene_ptr = std::shared_ptr<Scene>;
 std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, float LH_first_a, float LH_second_a);
 std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_direction, std::pair<glm::vec3, glm::vec3> LH);
 // findIntersection uses functions 'intersect_axis' and 'intersect' and is NOT node tree compatible yet
-node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction);
+std::pair<glm::vec3, node_ptr> find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction);
+
+std::array<glm::vec3, 4> find_cube_side(node_ptr node, glm::vec3 hit_coords);
 
 std::pair<glm::vec3, glm::vec3> get_pick_ray(const scene_ptr &scene, const osi::Mouse &mouse, const osi::Window &window);
 
diff --git a/src/algo/src/raycast.cpp b/src/algo/src/raycast.cpp
index 82d3bec..69f5aff 100644
--- a/src/algo/src/raycast.cpp
+++ b/src/algo/src/raycast.cpp
@@ -1,9 +1,15 @@
 #include <algo/raycast.hpp>
+#include <edit/scene.hpp>
 #include <gfx/camera.hpp>
 #include <gfx/mesh.hpp>
 #include <gfx/render.hpp>
+#include <utils/math.hpp>
 
+#include <algorithm>
 #include <limits>
+#include <map>
+
+using scene_ptr = std::shared_ptr<Scene>;
 
 std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, 
                                                   float LH_first_a, float LH_second_a)
@@ -39,7 +45,7 @@ std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_directio
     return {t0, t1};
 }
 
-node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction)
+std::pair<glm::vec3, node_ptr> find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction)
 {
     node_ptr nearest_node = nullptr;
     float nearest_t = std::numeric_limits<float>::infinity();
@@ -69,7 +75,47 @@ node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_pos
         }
     }
 
-    return nearest_node;
+    return { ray_position + (nearest_t * ray_direction), nearest_node };
+}
+
+std::array<glm::vec3, 4> nearest_vertices(std::array<glm::vec3, 8> AABB_local, std::array<glm::vec3, 8> AABB_world, glm::vec3 hit_coords)
+{
+    std::map<float, std::vector<glm::vec3>> candidates;
+    for (int i = 0; i < 8; ++i)
+    {
+        candidates[glm::distance(AABB_world[i], hit_coords)].emplace_back(AABB_local[i]);
+    }
+
+    std::array<glm::vec3, 4> result;
+    int i = 0;
+    for (auto [dist, vertices] : candidates)
+    {
+        for (auto vertex : vertices)
+        {
+            if (i >= 4)
+                break;
+            result[i] = vertex;
+            ++i;
+        }
+    }
+    return result;
+}
+
+std::array<glm::vec3, 4> find_cube_side(node_ptr node, glm::vec3 hit_coords)
+{
+    std::array<glm::vec3, 4> side_vertices;
+    for (auto &object : node->getObjects())
+        {
+            auto obj = dynamic_pointer_cast<Mesh>(object);
+            if (!obj)
+                continue;
+
+            auto AABB_local = obj->getAABB().getFullAABB();
+            auto AABB_world = obj->getAABB().getAABBWorld(node);
+            side_vertices = nearest_vertices(AABB_local, AABB_world , hit_coords);
+            break; // possibly not needed - should receive selection_AABB node
+        }
+    return side_vertices;
 }
 
 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)
diff --git a/src/common/include/common/aabb.hpp b/src/common/include/common/aabb.hpp
index 64fd9ae..63cf940 100644
--- a/src/common/include/common/aabb.hpp
+++ b/src/common/include/common/aabb.hpp
@@ -17,14 +17,17 @@ class AABB
     std::array<glm::vec3, 8> full_bbox;
 
     void findLH(std::vector<float> const &vertices);
-    void getFullAABB();
+    void createFullAABB();
 
 public:
     AABB(std::vector<float> const &vertices);
     std::pair<glm::vec3, glm::vec3> const &getLH() const { return LH; }
+    std::array<glm::vec3, 8> const &getFullAABB() const { return full_bbox; }
     std::vector<float> getVertices() const;
     std::vector<unsigned int> getIndices() const;
+
     std::pair<glm::vec3, glm::vec3> getLHWorld(node_ptr node) const;
+    std::array<glm::vec3, 8> getAABBWorld(node_ptr node) const;
 };
 
 #endif
\ No newline at end of file
diff --git a/src/common/src/aabb.cpp b/src/common/src/aabb.cpp
index c75a59f..a579ee1 100644
--- a/src/common/src/aabb.cpp
+++ b/src/common/src/aabb.cpp
@@ -3,7 +3,7 @@
 AABB::AABB(std::vector<float> const &vertices)
 {
     findLH(vertices);
-    getFullAABB();
+    createFullAABB();
 }
 
 void AABB::findLH(std::vector<float> const &vertices)
@@ -24,7 +24,7 @@ void AABB::findLH(std::vector<float> const &vertices)
     }
 }
 
-void AABB::getFullAABB()
+void AABB::createFullAABB()
 {
     full_bbox[0] = LH.first;
 
@@ -74,4 +74,19 @@ std::pair<glm::vec3, glm::vec3> AABB::getLHWorld(node_ptr node) const
     LH_world.second = node_trans * node_scale * glm::vec4(LH.second, 1);
 
     return LH_world;
+}
+std::array<glm::vec3, 8> AABB::getAABBWorld(node_ptr node) const
+{
+    std::array<glm::vec3, 8> AABB_world;
+
+    auto node_trans = node->getFrame()->getTranslationMat();
+    auto node_scale = node->getFrame()->getScaleMat();
+
+    for (int i = 0; i < 8; ++i)
+    {
+        AABB_world[i] = node_trans * node_scale * glm::vec4(full_bbox[i], 1);
+    }
+
+
+    return AABB_world;
 }
\ No newline at end of file
diff --git a/src/edit/include/edit/editor.hpp b/src/edit/include/edit/editor.hpp
index 0d82a41..1187378 100644
--- a/src/edit/include/edit/editor.hpp
+++ b/src/edit/include/edit/editor.hpp
@@ -81,11 +81,11 @@ public:
     void setPrevPlaneIntersect(glm::vec3 _prev_plane_intersect) { prev_plane_intersect = _prev_plane_intersect; }
 
     void doObjectAction(scene_ptr scene, ctrlhub_ptr controls);
-    void updateAxesCamera(scene_ptr scene, ctrlhub_ptr controls);
+    void changeOrthoCamAxes(scene_ptr scene, ctrlhub_ptr controls);
     void changeLevel(scene_ptr scene, ctrlhub_ptr controls);
 
     void adjustGridPosition(scene_ptr scene, ctrlhub_ptr controls, glm::vec3 position);
-    void adjustGridRotation(scene_ptr scene, ctrlhub_ptr controls, glm::vec3 rotation);
+    void adjustGridRotation(scene_ptr scene, ctrlhub_ptr controls, glm::quat rotation);
 
     void selectObject(scene_ptr scene, ctrlhub_ptr controls);
     void rotateObject(scene_ptr scene, ctrlhub_ptr controls);
diff --git a/src/edit/include/edit/scene.hpp b/src/edit/include/edit/scene.hpp
index c303384..f88ed68 100644
--- a/src/edit/include/edit/scene.hpp
+++ b/src/edit/include/edit/scene.hpp
@@ -23,6 +23,7 @@ private:
     std::vector<node_ptr> scene;
     node_ptr selection;
     node_ptr selection_AABB;
+    node_ptr side_higlight;
     node_ptr pre_add_AABB;
 
     node_ptr grid;
@@ -90,12 +91,14 @@ public:
     void addRay(glm::vec3 ray_position, glm::vec3 ray_direction);
     void addSelectionAABB(node_ptr node);
     void addPreAddAABB(node_ptr node, Frame position);
+    void addSideHighlight(node_ptr node, std::array<glm::vec3, 4> &side_vertices);
 
     void findLights(const std::vector<node_ptr> &nodes);
     void findCameras(const std::vector<node_ptr> &nodes);
 
     void changeDrawMode(node_ptr node, unsigned int mode);
     void manageSelection(node_ptr nearest_node); // Not node tree compatible
+    void manageHighlight(glm::vec3 hit_coord, node_ptr nearest_node);
 };
 
 #endif
\ No newline at end of file
diff --git a/src/edit/src/editor.cpp b/src/edit/src/editor.cpp
index 60cb236..7de8aa3 100644
--- a/src/edit/src/editor.cpp
+++ b/src/edit/src/editor.cpp
@@ -24,7 +24,7 @@ void Editor::doObjectAction(scene_ptr scene, ctrlhub_ptr controls)
     }
 }
 
-void Editor::updateAxesCamera(scene_ptr scene, ctrlhub_ptr controls)
+void Editor::changeOrthoCamAxes(scene_ptr scene, ctrlhub_ptr controls)
 {
     if (!keyboard.just_pressed().contains("I") 
         && !keyboard.just_pressed().contains("K") 
@@ -32,13 +32,13 @@ void Editor::updateAxesCamera(scene_ptr scene, ctrlhub_ptr controls)
         return;
 
     glm::vec3 cam_levels = build_level.getAll();
-    std::array<glm::vec3, 3> rotations = { glm::vec3(0.0f, -90.0f, 0.0f), // L(x-depth)
-                                           glm::vec3(-90.0f, 0.0f, 0.0f), // I (y-depth) // FIX - breaks things
-                                           glm::vec3(0.0f, 180.0f, 0.0f)  }; // K (z-depth)
+    std::array<glm::quat, 3> rotations = { glm::angleAxis(glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), // L(x-depth)
+                                           glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), // I (y-depth) // FIX - breaks things
+                                           glm::angleAxis(glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f))  }; // K (z-depth)
 
-    std::array<glm::vec3, 3> grid_rotations = { glm::vec3(-90.0f, -90.0f, 0.0f), // L(x-depth)
-                                                glm::vec3(0.0f, 0.0f, 0.0f), // I (y-depth)
-                                                glm::vec3(-90.0f, 0.0f, 0.0f)  }; // K (z-depth)
+    std::array<glm::quat, 3> grid_rotations = {glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), // L(x-depth)
+                                                glm::quat(), // I (y-depth)
+                                                glm::angleAxis(glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f))  }; // K (z-depth)
     std::uint8_t new_active = 0;
 
     if (keyboard.just_pressed().contains("I"))
@@ -51,16 +51,14 @@ void Editor::updateAxesCamera(scene_ptr scene, ctrlhub_ptr controls)
         new_active = 0;
 
     cam_levels[new_active] += new_active == 1 ? 5.0f : -5.0f; // +5 for up-down, else -5 
-    build_level.setActiveIndex(new_active);
+    // build_level.setActiveIndex(new_active);
     controls->getActiveCamCtrl()->setRotation(rotations[new_active]);
     controls->getActiveCamCtrl()->setPos(cam_levels[0], cam_levels[1], cam_levels[2]);
 
-    // NOTE: grid could have its own controller ?
-    // scene->getGrid()->getFrame()->setRotationQuat(grid_rotations[new_active]);
-    adjustGridRotation(scene, controls, grid_rotations[new_active]);
+    // adjustGridRotation(scene, controls, grid_rotations[new_active]);
 
 }
-void Editor::changeLevel(scene_ptr scene, ctrlhub_ptr controls)
+void Editor::changeLevel(scene_ptr scene, ctrlhub_ptr controls) // Unused & incorrect
 {
     auto prev_build_level = build_level;
     if (keyboard.just_pressed().contains("P"))
@@ -69,7 +67,7 @@ void Editor::changeLevel(scene_ptr scene, ctrlhub_ptr controls)
     if (keyboard.just_pressed().contains("O"))
         --build_level;
 
-    adjustGridPosition(scene, controls, build_level - prev_build_level);
+    // adjustGridPosition(scene, controls, build_level - prev_build_level);
 }
 
 void Editor::adjustGridPosition(scene_ptr scene, ctrlhub_ptr controls, glm::vec3 position)
@@ -80,13 +78,12 @@ void Editor::adjustGridPosition(scene_ptr scene, ctrlhub_ptr controls, glm::vec3
     controls->bindObject(prev_active_object);
 }
 
-void Editor::adjustGridRotation(scene_ptr scene, ctrlhub_ptr controls, glm::vec3 rotation)
+void Editor::adjustGridRotation(scene_ptr scene, ctrlhub_ptr controls, glm::quat rotation)
 {
     auto prev_active_object = controls->getActiveObjCtrl()->getFrame();
     controls->bindObject(scene->getGrid()->getFrame());
     controls->getActiveObjCtrl()->setRotation(rotation);
     controls->bindObject(prev_active_object);
-
 }
 
 void Editor::selectObject(scene_ptr scene, ctrlhub_ptr controls)
@@ -96,9 +93,10 @@ void Editor::selectObject(scene_ptr scene, ctrlhub_ptr controls)
 
     auto [ ray_position, ray_direction ] = get_pick_ray(scene, mouse, window);
 
-    auto nearest_node = find_intersection(scene->getScene(), ray_position, ray_direction);
+    auto [ hit_coord, nearest_node ] = find_intersection(scene->getScene(), ray_position, ray_direction);
 
     scene->manageSelection(nearest_node);
+    scene->manageHighlight(hit_coord, nearest_node); 
 }
 
 void Editor::rotateObject(scene_ptr scene, ctrlhub_ptr controls)
@@ -129,7 +127,7 @@ void Editor::moveObject(scene_ptr scene, ctrlhub_ptr controls)
     auto [ ray_position, ray_direction ] = get_pick_ray(scene, mouse, window);
 
     // Initial click not onto the selected object
-    if (!object_moving && find_intersection(scene->getScene(), ray_position, ray_direction) != scene->getSelection()) 
+    if (!object_moving && find_intersection(scene->getScene(), ray_position, ray_direction).second != scene->getSelection()) 
         return;
 
     /* Controller setup */
diff --git a/src/edit/src/scene.cpp b/src/edit/src/scene.cpp
index 08da752..7207f4f 100644
--- a/src/edit/src/scene.cpp
+++ b/src/edit/src/scene.cpp
@@ -1,4 +1,5 @@
 #include <edit/scene.hpp>
+#include <algo/raycast.hpp>
 #include <gfx/shapes.hpp>
 #include <gfx/render.hpp> // for grid vertices
 #include <filein/obj_loader.hpp>
@@ -21,16 +22,20 @@ void Scene::createScene()
 
     addNode(Frame{});
     addMesh(scene.back(), cube);
+    scene.back()->getFrame()->setScale(glm::vec3(0.5f, 0.5f, 0.5f));
 
     addNode(glm::vec3(5, 1, -4));
     addMesh(scene.back(), cube);
 
-    addNode(glm::vec3(2, 0, 1));
+    addNode(glm::vec3(1, 0, 1));
     addMesh(scene.back(), cube);
-    addNode(glm::vec3(2, 2, 1));
+    scene.back()->getFrame()->setScale(glm::vec3(0.5f, 0.5f, 0.5f));
+    addNode(glm::vec3(1, 1, 1));
     addMesh(scene.back(), cube);
-    addNode(glm::vec3(2, 2, 2));
+    scene.back()->getFrame()->setScale(glm::vec3(0.5f, 0.5f, 0.5f));
+    addNode(glm::vec3(1, 1, 2));
     addMesh(scene.back(), cube);
+    scene.back()->getFrame()->setScale(glm::vec3(0.5f, 0.5f, 0.5f));
 
     /* ADD AXIS OBJECT */
     // Mesh axis(axis_obj_vertices, axis_obj_indices, axis_obj_normals);
@@ -278,6 +283,27 @@ void Scene::addPreAddAABB(node_ptr node, Frame position)
         addMesh(scene.back(), std::move(obj_bbox));
     }
 }
+void Scene::addSideHighlight(node_ptr node, std::array<glm::vec3, 4> &side_vertices)
+{
+    addNode(node->getFrame());
+    side_higlight = scene.back();
+    std::vector<float> vertices;
+    for (auto v : side_vertices)
+    {
+        vertices.emplace_back(v.x);
+        vertices.emplace_back(v.y);
+        vertices.emplace_back(v.z - 0.05f); // TO DO: determine which side and offset higlight in front
+    }
+
+    std::vector<float> normals;
+    std::vector<unsigned int> indices = { 0, 1, 2, 1, 2, 3 };
+
+    Mesh m(vertices, indices, std::vector<float>{}, glm::vec3(0.0f, 1.0f, 0.0f), "basic");
+    m.setSelectability(false);
+
+    addMesh(side_higlight, std::move(m));
+}
+
 void Scene::findLights(const std::vector<node_ptr> &nodes)
 {
     for (auto &node : nodes)
@@ -328,3 +354,16 @@ void Scene::manageSelection(node_ptr nearest_node)
     selection = nearest_node;
     addSelectionAABB(nearest_node);
 }
+
+void Scene::manageHighlight(glm::vec3 hit_coord, node_ptr selection_AABB)
+{
+    removeNode(side_higlight);
+    if (!selection_AABB)
+    {
+        side_higlight = nullptr;
+        return;
+    }
+
+    auto side_vertices = find_cube_side(selection_AABB, hit_coord);
+    addSideHighlight(selection_AABB, side_vertices);
+}
diff --git a/src/studio/src/simulator.cpp b/src/studio/src/simulator.cpp
index 32f1989..36abbe3 100644
--- a/src/studio/src/simulator.cpp
+++ b/src/studio/src/simulator.cpp
@@ -37,12 +37,14 @@ void Simulator::update()
     controls->processInput(scene, keyboard(), timer(), window());
     controls->processMouse(mouse(), window(), editor->getEditorRunning()); 
 
-    editor->updateAxesCamera(scene, controls);
     editor->doObjectAction(scene, controls);
-    editor->changeLevel(scene, controls);
+    editor->changeOrthoCamAxes(scene, controls);
+    // editor->changeLevel(scene, controls);
 
     auto cam_frame = scene->getActiveCameras()[0].lock()->getFrame()->getPosition();
-    std::cout << "Camera coords: X " << cam_frame.x << " | Y " << cam_frame.y << " | Z " << cam_frame.z << std::endl;
+    auto cam_front_vec = controls->getActiveCamCtrl()->getFrontVec();
+    // std::cout << "Camera coords: X " << cam_frame.x << " | Y " << cam_frame.y << " | Z " << cam_frame.z << std::endl;
+    // std::cout << "Camera frontVec: X " << cam_front_vec.x << " | Y " << cam_front_vec.y << " | Z " << cam_front_vec.z << std::endl;
 
     /* Rotation around x-axis demo */
     // controls->rotate_obj(glm::vec3(1.0f, 0.0f, 0.0f));
-- 
GitLab