From b01125ab08e55e1cee84af344ccf8922427719c9 Mon Sep 17 00:00:00 2001
From: Adam Wahab <adamfwahab@hotmail.com>
Date: Wed, 25 Sep 2024 11:56:09 +0200
Subject: [PATCH] fixed axis direction, need to add json input, hpmodel input

---
 opengl/CMakeLists.txt                         |   4 +-
 ...l_example.cpp => opengl_visualization.cpp} | 329 +++++++++---------
 2 files changed, 158 insertions(+), 175 deletions(-)
 rename opengl/{opengl_example.cpp => opengl_visualization.cpp} (78%)

diff --git a/opengl/CMakeLists.txt b/opengl/CMakeLists.txt
index dfa4947..8abfd1b 100644
--- a/opengl/CMakeLists.txt
+++ b/opengl/CMakeLists.txt
@@ -39,7 +39,7 @@ target_include_directories(imgui PUBLIC
 target_link_libraries(imgui PUBLIC glfw)
 
 # Add your OpenGL source files
-add_library(OpenGLStuff opengl_example.cpp)
+add_library(OpenGLStuff opengl_visualization.cpp)
 
 # Include directories for OpenGLStuff
 target_include_directories(OpenGLStuff PUBLIC
@@ -52,7 +52,7 @@ target_include_directories(OpenGLStuff PUBLIC
 target_link_libraries(OpenGLStuff PUBLIC OpenGL::GL glfw glad imgui)
 
 # Create an executable for the OpenGL example
-add_executable(opengl_example_run opengl_example.cpp)
+add_executable(opengl_example_run opengl_visualization.cpp)
 
 # Include directories for the executable
 target_include_directories(opengl_example_run PUBLIC
diff --git a/opengl/opengl_example.cpp b/opengl/opengl_visualization.cpp
similarity index 78%
rename from opengl/opengl_example.cpp
rename to opengl/opengl_visualization.cpp
index 002ebcd..a2e38cd 100644
--- a/opengl/opengl_example.cpp
+++ b/opengl/opengl_visualization.cpp
@@ -73,6 +73,9 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
 // Function to update window title based on mode
 void updateWindowTitle(GLFWwindow* window, bool showUI);
 
+// Helper function to convert world coordinates to screen coordinates
+bool WorldToScreen(const glm::vec3& worldPos, const glm::mat4& view, const glm::mat4& projection, ImVec2& screenPos);
+
 // Entry point
 int main()
 {
@@ -158,7 +161,7 @@ int main()
     std::vector<float> sphereVertices;
     std::vector<unsigned int> sphereIndices;
     float sphereRadius = 0.3f;
-    unsigned int sectorCount = 36; // Increased for smoother spheres
+    unsigned int sectorCount = 36;
     unsigned int stackCount = 18;
     generateSphere(sphereVertices, sphereIndices, sphereRadius, sectorCount, stackCount);
 
@@ -218,26 +221,21 @@ int main()
 
     // ------------------- Adding Axes and Grid Points ---------------------
 
-    // Define the extent of your axes
     const float AXIS_LENGTH = 10.0f;
 
-    // Axes vertices (position and color)
     std::vector<float> axesVertices = {
         // X-axis (Red)
-        -AXIS_LENGTH, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f, // Start point
-         AXIS_LENGTH, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f, // End point
+        -AXIS_LENGTH, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f,
+         AXIS_LENGTH, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f,
         // Y-axis (Green)
         0.0f, -AXIS_LENGTH, 0.0f,  0.0f, 1.0f, 0.0f,
         0.0f,  AXIS_LENGTH, 0.0f,  0.0f, 1.0f, 0.0f,
         // Z-axis (Blue)
+        0.0f, 0.0f, AXIS_LENGTH,   0.0f, 0.0f, 1.0f,
         0.0f, 0.0f, -AXIS_LENGTH,  0.0f, 0.0f, 1.0f,
-        0.0f, 0.0f,  AXIS_LENGTH,  0.0f, 0.0f, 1.0f,
     };
 
-    // Generate grid points
     std::vector<float> gridPoints;
-
-    // Generate grid points along each axis
     for (int i = -static_cast<int>(AXIS_LENGTH); i <= static_cast<int>(AXIS_LENGTH); ++i) {
         // X-axis points
         gridPoints.push_back(static_cast<float>(i)); gridPoints.push_back(0.0f); gridPoints.push_back(0.0f);
@@ -252,64 +250,46 @@ int main()
         gridPoints.push_back(1.0f); gridPoints.push_back(1.0f); gridPoints.push_back(1.0f);
     }
 
-    // Set up VAO and VBO for axes
     unsigned int axesVAO, axesVBO;
     glGenVertexArrays(1, &axesVAO);
     glGenBuffers(1, &axesVBO);
 
     glBindVertexArray(axesVAO);
-
     glBindBuffer(GL_ARRAY_BUFFER, axesVBO);
     glBufferData(GL_ARRAY_BUFFER, axesVertices.size() * sizeof(float), axesVertices.data(), GL_STATIC_DRAW);
-
-    // Position attribute
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
     glEnableVertexAttribArray(0);
-
-    // Color attribute
     glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
     glEnableVertexAttribArray(2);
-
     glBindVertexArray(0);
 
-    // Set up VAO and VBO for grid points
     unsigned int gridVAO, gridVBO;
     glGenVertexArrays(1, &gridVAO);
     glGenBuffers(1, &gridVBO);
 
     glBindVertexArray(gridVAO);
-
     glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
     glBufferData(GL_ARRAY_BUFFER, gridPoints.size() * sizeof(float), gridPoints.data(), GL_STATIC_DRAW);
-
-    // Position attribute
     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
     glEnableVertexAttribArray(0);
-
-    // Color attribute
     glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
     glEnableVertexAttribArray(2);
-
     glBindVertexArray(0);
 
     // ------------------- Initialize ImGui ---------------------
 
-    // Initialize ImGui
     IMGUI_CHECKVERSION();
     ImGui::CreateContext();
     ImGuiIO& io = ImGui::GetIO(); (void)io;
 
-    // Set ImGui style
     ImGui::StyleColorsLight();
     ImGuiStyle& style = ImGui::GetStyle();
     style.WindowRounding = 0.0f; // Remove window rounding
     style.Colors[ImGuiCol_WindowBg] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // White background
 
-    // Setup Platform/Renderer backends
     ImGui_ImplGlfw_InitForOpenGL(window, true);
     ImGui_ImplOpenGL3_Init("#version 330");
 
-    // Initially set cursor mode based on showUI
     if (showUI)
     {
         glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
@@ -319,135 +299,154 @@ int main()
         glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
     }
 
-    // Render loop
     while (!glfwWindowShouldClose(window))
     {
-        // Per-frame time logic
         float currentFrame = glfwGetTime();
         deltaTime = currentFrame - lastFrame;
         lastFrame = currentFrame;
 
-        // Start ImGui frame
         ImGui_ImplOpenGL3_NewFrame();
         ImGui_ImplGlfw_NewFrame();
         ImGui::NewFrame();
 
-        // Handle cursor visibility and input mode based on showUI
         if (showUI)
         {
-            // Ensure cursor is visible
             if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_NORMAL)
             {
                 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
-                firstMouse = true; // Reset mouse to prevent camera jumps when returning to camera mode
+                firstMouse = true;
             }
         }
         else
         {
-            // Ensure cursor is hidden and captured
             if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED)
             {
                 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
-                firstMouse = true; // Reset mouse to prevent sudden camera jumps
+                firstMouse = true;
             }
-            // Process camera movement input
             processInput(window);
         }
 
-        // ImGui window for adding spheres (fixed left sidebar)
         if (showUI)
         {
-            // Optionally, you can set the next window position and size
-            // to align with your design. Here, we use a sidebar approach.
-
             ImGui::SetNextWindowPos(ImVec2(0, 0));
             ImGui::SetNextWindowSize(ImVec2(static_cast<float>(SIDEBAR_WIDTH), static_cast<float>(SCR_HEIGHT)));
             ImGui::Begin("Control Panel", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
 
-            static float spherePos[3] = {0.0f, 0.0f, 0.0f};
-            ImGui::InputFloat3("Position", spherePos);
+            static int spherePos[3] = {0, 0, 0};
+            ImGui::InputInt("X Position", &spherePos[0]);
+            ImGui::InputInt("Y Position", &spherePos[1]);
+            ImGui::InputInt("Z Position", &spherePos[2]);
+
+            static bool highlight = false;
+            ImGui::Checkbox("h", &highlight);
 
             if (ImGui::Button("Add Sphere"))
             {
                 Sphere sphere;
-                sphere.position = glm::vec3(spherePos[0], spherePos[1], spherePos[2]);
-                sphere.color = glm::vec3(0.5f, 0.5f, 0.5f); // Default color
+                // For some reason the z orientation is not correct, so we have to add an "minus" to the z coordinate.
+                sphere.position = glm::vec3(spherePos[0], spherePos[1], -spherePos[2]);
 
-                spheres[std::make_tuple((int)spherePos[0], (int)spherePos[1], (int)spherePos[2])] = sphere;
+                if (highlight)
+                    sphere.color = glm::vec3(1.0f, 0.0f, 0.0f);
+                else
+                    sphere.color = glm::vec3(0.5f, 0.5f, 0.5f);
+
+                spheres[std::make_tuple(spherePos[0], spherePos[1], spherePos[2])] = sphere;
 
-                // Recalculate lines between spheres
                 updateLines(spheres, lineVertices, lineVBO);
             }
 
             ImGui::End();
         }
 
-        // Render
-        glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Dark gray background
+        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-        // Activate shader
         glUseProgram(shaderProgram);
 
-        // Create transformations
         glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
-        glm::mat4 projection = glm::perspective(glm::radians(fov),
-                                static_cast<float>(SCR_WIDTH) / static_cast<float>(SCR_HEIGHT), 0.1f, 100.0f);
+        glm::mat4 projection = glm::perspective(glm::radians(fov), static_cast<float>(SCR_WIDTH) / static_cast<float>(SCR_HEIGHT), 0.1f, 100.0f);
 
-        // Retrieve the matrix uniform locations
         unsigned int modelLoc = glGetUniformLocation(shaderProgram, "model");
         unsigned int viewLoc  = glGetUniformLocation(shaderProgram, "view");
         unsigned int projLoc  = glGetUniformLocation(shaderProgram, "projection");
 
-        // Pass the matrices to the shader
         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
 
-        // Render axes
+        // --- ADDED CODE START ---
+        // Render axis labels
+        ImDrawList* drawList = ImGui::GetBackgroundDrawList(); // Or ImGui::GetForegroundDrawList()
+
+        ImU32 textColor = IM_COL32(255, 255, 255, 255); // White color
+
+        ImVec2 screenPos;
+        if (WorldToScreen(glm::vec3(AXIS_LENGTH, 0.0f, 0.0f), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "X+");
+        }
+        if (WorldToScreen(glm::vec3(-AXIS_LENGTH, 0.0f, 0.0f), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "X-");
+        }
+        if (WorldToScreen(glm::vec3(0.0f, AXIS_LENGTH, 0.f), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "Y+");
+        }
+        if (WorldToScreen(glm::vec3(0.0f, -AXIS_LENGTH, 0.0f), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "Y-");
+        }
+        if (WorldToScreen(glm::vec3(0.0f, 0.0f, AXIS_LENGTH), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "Z-");
+        }
+        if (WorldToScreen(glm::vec3(0.0f, 0.0f, -AXIS_LENGTH), view, projection, screenPos))
+        {
+            drawList->AddText(screenPos, textColor, "Z+");
+        }
+
         glBindVertexArray(axesVAO);
-        glDrawArrays(GL_LINES, 0, 6); // 6 vertices for the axes
+        glDrawArrays(GL_LINES, 0, 6);
         glBindVertexArray(0);
 
-        // Render grid points
         glBindVertexArray(gridVAO);
-        glPointSize(5.0f); // Adjust point size as needed
-        glDrawArrays(GL_POINTS, 0, static_cast<unsigned int>(gridPoints.size() / 6)); // Each point has 6 floats (position + color)
+        glPointSize(5.0f);
+        glDrawArrays(GL_POINTS, 0, static_cast<unsigned int>(gridPoints.size() / 6));
         glBindVertexArray(0);
 
-        // Render spheres
         glBindVertexArray(sphereVAO);
         for (const auto& [key, sphere] : spheres)
         {
             glm::mat4 model = glm::mat4(1.0f);
             model = glm::translate(model, sphere.position);
 
-            // Pass model matrix
             glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
 
-            // Draw sphere
+            // Set sphere color
+            glVertexAttrib3f(2, sphere.color.r, sphere.color.g, sphere.color.b);
+
             glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(sphereIndices.size()), GL_UNSIGNED_INT, 0);
         }
         glBindVertexArray(0);
 
-        // Render lines
+        glLineWidth(3.0f);
         glBindVertexArray(lineVAO);
-        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); // Identity model matrix
+        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f)));
         glDrawArrays(GL_LINES, 0, static_cast<unsigned int>(lineVertices.size() / 6));
         glBindVertexArray(0);
+        glLineWidth(1.0f);
 
-        // Update window title based on mode
         updateWindowTitle(window, showUI);
 
-        // Render ImGui
         ImGui::Render();
         ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
 
-        // Swap buffers and poll IO events
         glfwSwapBuffers(window);
         glfwPollEvents();
     }
 
-    // De-allocate resources
     glDeleteVertexArrays(1, &sphereVAO);
     glDeleteBuffers(1, &sphereVBO);
     glDeleteBuffers(1, &sphereEBO);
@@ -463,22 +462,19 @@ int main()
 
     glDeleteProgram(shaderProgram);
 
-    // Cleanup ImGui
     ImGui_ImplOpenGL3_Shutdown();
     ImGui_ImplGlfw_Shutdown();
     ImGui::DestroyContext();
 
-    // Terminate GLFW
     glfwTerminate();
 
     return 0;
 }
 
-// Sphere generation function
 void generateSphere(std::vector<float>& vertices, std::vector<unsigned int>& indices, float radius, unsigned int sectorCount, unsigned int stackCount)
 {
-    float x, y, z, xy;                              // vertex position
-    float nx, ny, nz, lengthInv = 1.0f / radius;    // normal
+    float x, y, z, xy;
+    float nx, ny, nz, lengthInv = 1.0f / radius;
 
     float sectorStep = 2 * glm::pi<float>() / sectorCount;
     float stackStep = glm::pi<float>() / stackCount;
@@ -486,28 +482,23 @@ void generateSphere(std::vector<float>& vertices, std::vector<unsigned int>& ind
 
     for(unsigned int i = 0; i <= stackCount; ++i)
     {
-        stackAngle = glm::pi<float>() / 2 - i * stackStep;        // from pi/2 to -pi/2
-        xy = radius * cosf(stackAngle);             // r * cos(u)
-        z = radius * sinf(stackAngle);              // r * sin(u)
+        stackAngle = glm::pi<float>() / 2 - i * stackStep;
+        xy = radius * cosf(stackAngle);
+        z = radius * sinf(stackAngle);
 
-        // add (sectorCount+1) vertices per stack
         for(unsigned int j = 0; j <= sectorCount; ++j)
         {
-            sectorAngle = j * sectorStep;           // from 0 to 2pi
+            sectorAngle = j * sectorStep;
 
-            // vertex position (x, y, z)
-            x = xy * cosf(sectorAngle);             // r * cos(u) * cos(v)
-            y = xy * sinf(sectorAngle);             // r * cos(u) * sin(v)
+            x = xy * cosf(sectorAngle);
+            y = xy * sinf(sectorAngle);
 
-            // normalized vertex normal (nx, ny, nz)
             nx = x * lengthInv;
             ny = y * lengthInv;
             nz = z * lengthInv;
 
-            // vertex color (default white)
             float r = 1.0f, g = 1.0f, b = 1.0f;
 
-            // Add to vertices
             vertices.push_back(x);
             vertices.push_back(y);
             vertices.push_back(z);
@@ -522,16 +513,14 @@ void generateSphere(std::vector<float>& vertices, std::vector<unsigned int>& ind
         }
     }
 
-    // indices
     unsigned int k1, k2;
     for(unsigned int i = 0; i < stackCount; ++i)
     {
-        k1 = i * (sectorCount + 1);     // beginning of current stack
-        k2 = k1 + sectorCount + 1;      // beginning of next stack
+        k1 = i * (sectorCount + 1);
+        k2 = k1 + sectorCount + 1;
 
         for(unsigned int j = 0; j < sectorCount; ++j, ++k1, ++k2)
         {
-            // 2 triangles per sector except for first and last stacks
             if(i != 0)
             {
                 indices.push_back(k1);
@@ -549,39 +538,81 @@ void generateSphere(std::vector<float>& vertices, std::vector<unsigned int>& ind
     }
 }
 
-// Process all input
+void updateLines(const std::map<std::tuple<int, int, int>, Sphere>& spheres,
+                std::vector<float>& lineVertices, unsigned int lineVBO)
+{
+    lineVertices.clear();
+
+    for (const auto& [key, sphere] : spheres)
+    {
+        int x = std::get<0>(key);
+        int y = std::get<1>(key);
+        int z = std::get<2>(key);
+
+        for (int dx = -1; dx <= 1; ++dx)
+        {
+            for (int dy = -1; dy <= 1; ++dy)
+            {
+                for (int dz = -1; dz <= 1; ++dz)
+                {
+                    if ((abs(dx) + abs(dy) + abs(dz)) != 1)
+                        continue;
+
+                    int nx = x + dx;
+                    int ny = y + dy;
+                    int nz = z + dz;
+
+                    auto neighborKey = std::make_tuple(nx, ny, nz);
+                    if (spheres.find(neighborKey) != spheres.end())
+                    {
+                        if (key < neighborKey)
+                        {
+                            glm::vec3 neighborPos = spheres.at(neighborKey).position;
+
+                            lineVertices.insert(lineVertices.end(), {
+                                sphere.position.x, sphere.position.y, sphere.position.z, 0.5f, 0.5f, 0.5f,
+                                neighborPos.x, neighborPos.y, neighborPos.z, 0.5f, 0.5f, 0.5f
+                            });
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
+    glBufferData(GL_ARRAY_BUFFER, lineVertices.size() * sizeof(float), &lineVertices[0], GL_DYNAMIC_DRAW);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
 void processInput(GLFWwindow *window)
 {
-    float cameraSpeed = 10.0f * deltaTime; // Adjusted camera speed
+    float cameraSpeed = 10.0f * deltaTime;
 
     if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
-        cameraPos += cameraSpeed * cameraFront; // Move forward
+        cameraPos += cameraSpeed * cameraFront;
     if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
-        cameraPos -= cameraSpeed * cameraFront; // Move backward
+        cameraPos -= cameraSpeed * cameraFront;
     if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
-        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; // Move left
+        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
     if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
-        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; // Move right
+        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
     if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
-        cameraPos += cameraSpeed * cameraUp; // Move up
+        cameraPos += cameraSpeed * cameraUp;
     if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
-        cameraPos -= cameraSpeed * cameraUp; // Move down
+        cameraPos -= cameraSpeed * cameraUp;
 
-    // Exit application
     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
         glfwSetWindowShouldClose(window, true);
 }
 
-// Update framebuffer_size_callback
 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
 {
     SCR_WIDTH = width;
     SCR_HEIGHT = height;
-    // Adjust the viewport to cover the entire window
     glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
 }
 
-// GLFW: whenever the mouse moves, this callback is called
 void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
 {
     if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED)
@@ -598,7 +629,7 @@ void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
     }
 
     float xoffset = xpos - lastX;
-    float yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to top
+    float yoffset = lastY - ypos;
 
     lastX = xpos;
     lastY = ypos;
@@ -610,13 +641,11 @@ void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
     yaw   += xoffset;
     pitch += yoffset;
 
-    // Constrain the pitch to avoid screen flipping
     if(pitch > 89.0f)
         pitch = 89.0f;
     if(pitch < -89.0f)
         pitch = -89.0f;
 
-    // Update camera front vector
     glm::vec3 front;
     front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
     front.y = sin(glm::radians(pitch));
@@ -625,27 +654,23 @@ void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
     cameraFront = glm::normalize(front);
 }
 
-// GLFW: whenever the mouse scroll wheel scrolls, this callback is called
 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
 {
-    fov -= static_cast<float>(yoffset); // yoffset is positive or negative depending on scroll direction
+    fov -= static_cast<float>(yoffset);
     if(fov < 1.0f)
         fov = 1.0f;
     if(fov > 90.0f)
         fov = 90.0f;
 }
 
-// Shader compilation and linking
 unsigned int createShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
 {
-    // Vertex Shader
     unsigned int vertexShader;
     vertexShader = glCreateShader(GL_VERTEX_SHADER);
 
     glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
     glCompileShader(vertexShader);
 
-    // Check for compile-time errors
     int success;
     char infoLog[512];
 
@@ -658,14 +683,12 @@ unsigned int createShaderProgram(const char* vertexShaderSource, const char* fra
         return 0;
     }
 
-    // Fragment Shader
     unsigned int fragmentShader;
     fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
     glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
     glCompileShader(fragmentShader);
 
-    // Check for compile-time errors
     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
     if(!success)
     {
@@ -675,7 +698,6 @@ unsigned int createShaderProgram(const char* vertexShaderSource, const char* fra
         return 0;
     }
 
-    // Link shaders
     unsigned int shaderProgram;
     shaderProgram = glCreateProgram();
 
@@ -683,7 +705,6 @@ unsigned int createShaderProgram(const char* vertexShaderSource, const char* fra
     glAttachShader(shaderProgram, fragmentShader);
     glLinkProgram(shaderProgram);
 
-    // Check for linking errors
     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
     if(!success)
     {
@@ -693,91 +714,53 @@ unsigned int createShaderProgram(const char* vertexShaderSource, const char* fra
         return 0;
     }
 
-    // Delete shaders as they're linked into our program now and no longer necessary
     glDeleteShader(vertexShader);
     glDeleteShader(fragmentShader);
 
     return shaderProgram;
 }
 
-// Function to update lines between spheres
-void updateLines(const std::map<std::tuple<int, int, int>, Sphere>& spheres,
-                std::vector<float>& lineVertices, unsigned int lineVBO)
-{
-    lineVertices.clear();
-
-    for (const auto& [key, sphere] : spheres)
-    {
-        int x = std::get<0>(key);
-        int y = std::get<1>(key);
-        int z = std::get<2>(key);
-
-        // Check adjacent positions
-        for (int dx = -1; dx <= 1; ++dx)
-        {
-            for (int dy = -1; dy <= 1; ++dy)
-            {
-                for (int dz = -1; dz <= 1; ++dz)
-                {
-                    // Skip the same sphere or diagonals (non-axis-aligned neighbors)
-                    if (abs(dx) + abs(dy) + abs(dz) != 1)
-                        continue;
-
-                    int nx = x + dx;
-                    int ny = y + dy;
-                    int nz = z + dz;
-
-                    auto neighborKey = std::make_tuple(nx, ny, nz);
-                    if (spheres.find(neighborKey) != spheres.end())
-                    {
-                        // Ensure each line is added only once
-                        if (key < neighborKey)
-                        {
-                            glm::vec3 neighborPos = spheres.at(neighborKey).position;
-
-                            // Line from sphere to neighbor
-                            lineVertices.insert(lineVertices.end(), {
-                                sphere.position.x, sphere.position.y, sphere.position.z, 0.5f, 0.5f, 0.5f,
-                                neighborPos.x, neighborPos.y, neighborPos.z, 0.5f, 0.5f, 0.5f
-                            });
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // Update the line VBO
-    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
-    glBufferData(GL_ARRAY_BUFFER, lineVertices.size() * sizeof(float), &lineVertices[0], GL_DYNAMIC_DRAW);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
-
-// Key callback for toggling UI
 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
 {
-    // Toggle UI visibility with TAB key
     if (key == GLFW_KEY_TAB && action == GLFW_PRESS)
     {
         showUI = !showUI;
         if (showUI)
         {
-            // Show cursor for UI interaction
             glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
         }
         else
         {
-            // Hide and capture cursor for camera control
             glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
-            firstMouse = true; // Reset mouse to prevent sudden camera jumps
+            firstMouse = true;
         }
     }
 }
 
-// Function to update window title based on mode
 void updateWindowTitle(GLFWwindow* window, bool showUI)
 {
     std::string title = "3D Spheres with Connections - ";
     title += showUI ? "UI Interaction Mode" : "Camera Control Mode";
     glfwSetWindowTitle(window, title.c_str());
-}
\ No newline at end of file
+}
+
+bool WorldToScreen(const glm::vec3& worldPos, const glm::mat4& view, const glm::mat4& projection, ImVec2& screenPos)
+{
+    glm::vec4 clipSpacePos = projection * view * glm::vec4(worldPos, 1.0f);
+
+    if (clipSpacePos.w <= 0.0f)
+        return false; // Behind the camera
+
+    glm::vec3 ndc = glm::vec3(clipSpacePos) / clipSpacePos.w;
+
+    if (ndc.x < -1.0f || ndc.x > 1.0f || ndc.y < -1.0f || ndc.y > 1.0f)
+        return false; // Outside of screen
+
+    // Map to window coordinates
+    float windowX = (ndc.x + 1.0f) * SCR_WIDTH / 2.0f;
+    float windowY = (1.0f - ndc.y) * SCR_HEIGHT / 2.0f; // Invert Y for window coordinates
+
+    screenPos = ImVec2(windowX, windowY);
+
+    return true;
+}
-- 
GitLab