From d34925777dd4fac709096f1c18b7d886b43c15b2 Mon Sep 17 00:00:00 2001 From: hachem Date: Mon, 18 Aug 2025 05:02:13 +0200 Subject: [fix]: improvements, bump to c++20 and fix bugs --- Assets/Shaders/ComputeTextureQuad.glsl | 2 +- Assets/Shaders/Sphere.glsl | 17 ++- premake5.lua | 2 +- src/Core/Camera.cpp | 4 +- src/Core/Camera.h | 7 +- src/Engine/Engine.h | 6 +- src/Engine/Object.h | 2 +- src/States/WorldBuilderState.cpp | 208 ++++++++++++++++++--------------- src/States/WorldBuilderState.h | 8 ++ 9 files changed, 144 insertions(+), 112 deletions(-) diff --git a/Assets/Shaders/ComputeTextureQuad.glsl b/Assets/Shaders/ComputeTextureQuad.glsl index b7b76d0..95f433d 100644 --- a/Assets/Shaders/ComputeTextureQuad.glsl +++ b/Assets/Shaders/ComputeTextureQuad.glsl @@ -10,7 +10,7 @@ out vec2 v_TexCoord; void main() { gl_Position = vec4(a_Pos, 0.0, 1.0); - v_TexCoord = a_TexCoord; + v_TexCoord = a_TexCoord; } #type fragment diff --git a/Assets/Shaders/Sphere.glsl b/Assets/Shaders/Sphere.glsl index 37757b5..026f884 100644 --- a/Assets/Shaders/Sphere.glsl +++ b/Assets/Shaders/Sphere.glsl @@ -13,8 +13,8 @@ out vec3 v_WorldPos; void main() { - v_WorldPos = vec3(u_Transform * vec4(a_Position, 1.0)); - v_Normal = mat3(transpose(inverse(u_Transform))) * a_Normal; + v_WorldPos = vec3(u_Transform * vec4(a_Position, 1.0)); + v_Normal = mat3(transpose(inverse(u_Transform))) * a_Normal; gl_Position = u_ViewProjection * vec4(v_WorldPos, 1.0); } @@ -30,6 +30,9 @@ uniform float u_Specular; uniform float u_Emission; uniform vec3 u_LightPos; uniform vec3 u_CameraPos; +uniform int u_IsSelected; +uniform vec3 u_OutlineColor; +uniform float u_OutlineWidth; out vec4 o_FragColor; @@ -49,5 +52,15 @@ void main() vec3 emission = u_Color * u_Emission; vec3 result = ambient + diffuse + specular + emission; + + if (u_IsSelected > 0) + { + float ndotv = max(dot(normal, viewDir), 0.0); + float rim = 1.0 - ndotv; + float width = clamp(u_OutlineWidth, 0.0, 1.0); + float outlineMask = smoothstep(1.0 - width, 1.0, rim); + result = mix(result, u_OutlineColor, outlineMask); + } + o_FragColor = vec4(result, 1.0); } diff --git a/premake5.lua b/premake5.lua index adeb0c0..3c245a9 100644 --- a/premake5.lua +++ b/premake5.lua @@ -293,7 +293,7 @@ group "" project "Donut" kind "ConsoleApp" language "C++" - cppdialect "C++17" + cppdialect "C++20" staticruntime "on" targetdir ("bin/" .. outputdir) diff --git a/src/Core/Camera.cpp b/src/Core/Camera.cpp index eeb62a4..028924e 100644 --- a/src/Core/Camera.cpp +++ b/src/Core/Camera.cpp @@ -163,7 +163,7 @@ namespace Donut glm::vec3 Camera::GetOrbitalPosition() const { - float clampedElevation = glm::clamp(m_Elevation, 0.01f, float(M_PI) - 0.01f); + float clampedElevation = glm::clamp(m_Elevation, 0.01f, float(std::numbers::pi) - 0.01f); return glm::vec3 ( m_OrbitalRadius * sin(clampedElevation) * cos(m_Azimuth), @@ -191,7 +191,7 @@ namespace Donut m_Azimuth += dx * m_OrbitalSpeed; m_Elevation -= dy * m_OrbitalSpeed; - m_Elevation = glm::clamp(m_Elevation, 0.01f, float(M_PI) - 0.01f); + m_Elevation = glm::clamp(m_Elevation, 0.01f, float(std::numbers::pi) - 0.01f); } m_LastX_Orbital = x; diff --git a/src/Core/Camera.h b/src/Core/Camera.h index a049d06..a9aec2a 100644 --- a/src/Core/Camera.h +++ b/src/Core/Camera.h @@ -3,10 +3,7 @@ #include #include -#define _USE_MATH_DEFINES -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +#include namespace Donut { @@ -121,7 +118,7 @@ namespace Donut double m_OrbitalMinRadius = 1e10; double m_OrbitalMaxRadius = 1e12; float m_Azimuth = 0.0f; - float m_Elevation = static_cast(M_PI) / 2.0f; + float m_Elevation = static_cast(std::numbers::pi) / 2.0f; float m_OrbitalSpeed = 0.01f; double m_ZoomSpeed = 25e9f; bool m_Dragging = false; diff --git a/src/Engine/Engine.h b/src/Engine/Engine.h index e1b4ad8..7b4ced4 100644 --- a/src/Engine/Engine.h +++ b/src/Engine/Engine.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -21,11 +22,6 @@ #include #include -#define _USE_MATH_DEFINES -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - namespace Donut { const double c = 299792458.0; diff --git a/src/Engine/Object.h b/src/Engine/Object.h index ea672db..7e620c4 100644 --- a/src/Engine/Object.h +++ b/src/Engine/Object.h @@ -46,7 +46,7 @@ namespace Donut float a = glm::dot(ray.m_Direction, ray.m_Direction); float b = 2.0f * glm::dot(oc, ray.m_Direction); float c = glm::dot(oc, oc) - m_Radius * m_Radius; - double discriminant = b*b - 4*a*c; + float discriminant = static_cast(b*b - 4*a*c); if(discriminant < 0) return false; diff --git a/src/States/WorldBuilderState.cpp b/src/States/WorldBuilderState.cpp index 807038d..c5ed174 100644 --- a/src/States/WorldBuilderState.cpp +++ b/src/States/WorldBuilderState.cpp @@ -17,17 +17,11 @@ #include #include +#include #include #include #include -#define _USE_MATH_DEFINES -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -// TODO(Hachem): Remove constant shader and object creation in main loop -// TODO(Hachem): Change selection appearance // TODO(Hachem): JSON Scene saving and loading namespace Donut @@ -45,7 +39,7 @@ namespace Donut m_Camera.SetOrbitalSpeed(0.01f); m_Camera.SetZoomSpeed(2.0f); m_Camera.SetAzimuth(0.0f); - m_Camera.SetElevation(static_cast(M_PI) / 3.0f); + m_Camera.SetElevation(static_cast(std::numbers::pi) / 3.0f); m_Camera.UpdateOrbital(); Material defaultMaterial(glm::vec3(0.8f, 0.2f, 0.2f), 0.5f, 0.0f); @@ -60,6 +54,9 @@ namespace Donut Object sphere3(glm::vec3(0.0f, 2.0f, 0.0f), 0.8f, material3); m_Scene.objs.push_back(sphere3); + m_SphereShader = Ref(Shader::Create("Assets/Shaders/Sphere.glsl")); + InitializeSphereGeometry(); + m_Initialized = true; } @@ -87,7 +84,7 @@ namespace Donut float newAzimuth = m_Camera.GetAzimuth() + azimuthDelta; float newElevation = m_Camera.GetElevation() + elevationDelta; - newElevation = glm::clamp(newElevation, 0.01f, static_cast(M_PI) - 0.01f); + newElevation = glm::clamp(newElevation, 0.01f, static_cast(std::numbers::pi) - 0.01f); m_Camera.SetAzimuth(newAzimuth); m_Camera.SetElevation(newElevation); @@ -99,7 +96,7 @@ namespace Donut void WorldBuilderState::OnRender() { - RenderCommand::SetClearColor(glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)); + RenderCommand::SetClearColor(glm::vec4(0.05f, 0.05f, 0.05f, 1.0f)); RenderCommand::Clear(); RenderScene(); } @@ -123,8 +120,8 @@ namespace Donut int width, height; glfwGetFramebufferSize(window, &width, &height); - float ndcX = (2.0f * xpos) / width - 1.0f; - float ndcY = 1.0f - (2.0f * ypos) / height; + float ndcX = (2.0f * static_cast(xpos)) / static_cast(width) - 1.0f; + float ndcY = 1.0f - (2.0f * static_cast(ypos)) / static_cast(height); glm::vec4 rayStart_NDC(ndcX, ndcY, -1.0f, 1.0f); glm::vec4 rayEnd_NDC(ndcX, ndcY, 0.0f, 1.0f); @@ -178,8 +175,9 @@ namespace Donut } else { - m_CameraDragging = true; - m_LastMousePos = glm::vec2(xpos, ypos); + m_SelectedObjectIndex = -1; + m_CameraDragging = true; + m_LastMousePos = glm::vec2(xpos, ypos); } return true; @@ -292,7 +290,7 @@ namespace Donut { m_Camera.SetOrbitalRadius(15.0f); m_Camera.SetAzimuth(0.0f); - m_Camera.SetElevation(static_cast(M_PI) / 3.0f); + m_Camera.SetElevation(static_cast(std::numbers::pi) / 3.0f); m_Camera.SetOrbitalTarget(glm::vec3(0.0f, 0.0f, 0.0f)); m_Camera.UpdateOrbital(); } @@ -381,6 +379,8 @@ namespace Donut } } } + + ImGui::Spacing(); if (ImGui::CollapsingHeader("Gizmo Controls", &m_ShowGizmoControls)) { @@ -399,6 +399,22 @@ namespace Donut ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Hotkeys:"); ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "W = Translate, E = Rotate, R = Scale"); } + + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Selection Outline", &m_ShowOutlineControls)) + { + ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Outline Settings:"); + + ImGui::Text("Outline Color:"); + ImGui::ColorEdit3("##OutlineColor", &m_OutlineColor.x); + + ImGui::Text("Outline Width:"); + ImGui::SliderFloat("##OutlineWidth", &m_OutlineWidth, 0.01f, 0.9f, "%.2f"); + + ImGui::Spacing(); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "White rim around sphere silhouette"); + } ImGui::Spacing(); ImGui::Separator(); @@ -554,85 +570,82 @@ namespace Donut DONUT_ERROR("Failed to load scene"); } - void WorldBuilderState::RenderScene() + void WorldBuilderState::InitializeSphereGeometry() { - GLFWwindow* window = static_cast(Application::Get().GetWindow().GetNativeWindow()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::SetViewport(0, 0, width, height); - RenderCommand::EnableDepthTest(); + std::vector vertices; + std::vector indices; - static Ref sphereVAO = nullptr; - static Ref sphereShader = Ref(Shader::Create("Assets/Shaders/Sphere.glsl")); + const int segments = 32; + const int rings = 16; - if (!sphereVAO) + for (int ring = 0; ring <= rings; ++ring) { - std::vector vertices; - std::vector indices; - - const int segments = 32; - const int rings = 16; + float phi = static_cast(std::numbers::pi) * ring / rings; + float sinPhi = sin(phi); + float cosPhi = cos(phi); - for (int ring = 0; ring <= rings; ++ring) + for (int segment = 0; segment <= segments; ++segment) { - float phi = static_cast(M_PI) * ring / rings; - float sinPhi = sin(phi); - float cosPhi = cos(phi); + float theta = 2.0f * static_cast(std::numbers::pi) * segment / segments; + float sinTheta = sin(theta); + float cosTheta = cos(theta); - for (int segment = 0; segment <= segments; ++segment) - { - float theta = 2.0f * static_cast(M_PI) * segment / segments; - float sinTheta = sin(theta); - float cosTheta = cos(theta); - - float x = cosTheta * sinPhi; - float y = cosPhi; - float z = sinTheta * sinPhi; - - float nx = x; - float ny = y; - float nz = z; - - vertices.push_back(x); - vertices.push_back(y); - vertices.push_back(z); - vertices.push_back(nx); - vertices.push_back(ny); - vertices.push_back(nz); - } + float x = cosTheta * sinPhi; + float y = cosPhi; + float z = sinTheta * sinPhi; + + float nx = x; + float ny = y; + float nz = z; + + vertices.push_back(x); + vertices.push_back(y); + vertices.push_back(z); + vertices.push_back(nx); + vertices.push_back(ny); + vertices.push_back(nz); } - - for (int ring = 0; ring < rings; ++ring) + } + + for (int ring = 0; ring < rings; ++ring) + { + for (int segment = 0; segment < segments; ++segment) { - for (int segment = 0; segment < segments; ++segment) - { - uint32_t first = ring * (segments + 1) + segment; - uint32_t second = first + segments + 1; - - indices.push_back(first); - indices.push_back(second); - indices.push_back(first + 1); - - indices.push_back(second); - indices.push_back(second + 1); - indices.push_back(first + 1); - } + uint32_t first = ring * (segments + 1) + segment; + uint32_t second = first + segments + 1; + + indices.push_back(first); + indices.push_back(second); + indices.push_back(first + 1); + + indices.push_back(second); + indices.push_back(second + 1); + indices.push_back(first + 1); } - - auto vertexBuffer = Ref(VertexBuffer::Create(vertices.data(), static_cast(vertices.size() * sizeof(float)))); - VertexBufferLayout layout; - layout.Push(3); - layout.Push(3); - vertexBuffer->SetLayout(layout); - - auto indexBuffer = Ref(IndexBuffer::Create(indices.data(), static_cast(indices.size()))); - - sphereVAO = Ref(VertexArray::Create()); - sphereVAO->AddVertexBuffer(vertexBuffer); - sphereVAO->SetIndexBuffer(indexBuffer); } + auto vertexBuffer = Ref(VertexBuffer::Create(vertices.data(), static_cast(vertices.size() * sizeof(float)))); + VertexBufferLayout layout; + layout.Push(3); + layout.Push(3); + vertexBuffer->SetLayout(layout); + + auto indexBuffer = Ref(IndexBuffer::Create(indices.data(), static_cast(indices.size()))); + + m_SphereVAO = Ref(VertexArray::Create()); + m_SphereVAO->AddVertexBuffer(vertexBuffer); + m_SphereVAO->SetIndexBuffer(indexBuffer); + } + + void WorldBuilderState::RenderScene() + { + GLFWwindow* window = static_cast(Application::Get().GetWindow().GetNativeWindow()); + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + RenderCommand::SetViewport(0, 0, width, height); + RenderCommand::EnableDepthTest(); + glm::mat4 view = m_Camera.GetViewMatrix(); glm::mat4 projection = m_Camera.GetProjectionMatrix(); glm::mat4 viewProjection = projection * view; @@ -640,10 +653,13 @@ namespace Donut glm::vec3 lightPos = m_Scene.m_LightPos; glm::vec3 cameraPos = m_Camera.GetOrbitalPosition(); - sphereShader->Bind(); - sphereShader->SetMat4("u_ViewProjection", viewProjection); - sphereShader->SetFloat3("u_LightPos", lightPos); - sphereShader->SetFloat3("u_CameraPos", cameraPos); + m_SphereShader->Bind(); + m_SphereShader->SetMat4("u_ViewProjection", viewProjection); + m_SphereShader->SetFloat3("u_LightPos", lightPos); + m_SphereShader->SetFloat3("u_CameraPos", cameraPos); + + m_SphereShader->SetFloat3("u_OutlineColor", m_OutlineColor); + m_SphereShader->SetFloat("u_OutlineWidth", m_OutlineWidth); for (size_t i = 0; i < m_Scene.objs.size(); ++i) { @@ -652,25 +668,27 @@ namespace Donut glm::mat4 transform = glm::translate(glm::mat4(1.0f), obj.m_Centre); transform = glm::scale(transform, glm::vec3(obj.m_Radius)); - sphereShader->SetMat4("u_Transform", transform); + m_SphereShader->SetMat4("u_Transform", transform); - if (m_SelectedObjectIndex == static_cast(i)) + bool isSelected = (m_SelectedObjectIndex == static_cast(i)); + m_SphereShader->SetInt("u_IsSelected", isSelected ? 1 : 0); + if (isSelected) { glm::vec3 highlightColor = obj.m_Material.m_Color * 1.5f; highlightColor = glm::clamp(highlightColor, 0.0f, 1.0f); - sphereShader->SetFloat3("u_Color", highlightColor); - sphereShader->SetFloat("u_Emission", 0.2f); + m_SphereShader->SetFloat3("u_Color", highlightColor); + m_SphereShader->SetFloat("u_Emission", 0.2f); } else { - sphereShader->SetFloat3("u_Color", obj.m_Material.m_Color); - sphereShader->SetFloat("u_Emission", obj.m_Material.m_Emission); + m_SphereShader->SetFloat3("u_Color", obj.m_Material.m_Color); + m_SphereShader->SetFloat("u_Emission", obj.m_Material.m_Emission); } - sphereShader->SetFloat("u_Specular", obj.m_Material.m_Specular); + m_SphereShader->SetFloat("u_Specular", obj.m_Material.m_Specular); - sphereVAO->Bind(); - RenderCommand::DrawIndexed(sphereVAO); + m_SphereVAO->Bind(); + RenderCommand::DrawIndexed(m_SphereVAO); } RenderCommand::DisableDepthTest(); diff --git a/src/States/WorldBuilderState.h b/src/States/WorldBuilderState.h index c9b8d00..af7d918 100644 --- a/src/States/WorldBuilderState.h +++ b/src/States/WorldBuilderState.h @@ -39,11 +39,15 @@ namespace Donut void SaveScene(); void LoadScene(); void RenderScene(); + void InitializeSphereGeometry(); private: Scene m_Scene; Camera m_Camera; bool m_Initialized = false; + Ref m_SphereShader; + Ref m_SphereVAO; + glm::vec3 m_NewObjectPosition = glm::vec3(0.0f, 0.0f, 0.0f); float m_NewObjectRadius = 1.0f; glm::vec3 m_NewObjectColor = glm::vec3(1.0f, 1.0f, 1.0f); @@ -61,5 +65,9 @@ namespace Donut bool m_ShowObjectCreator = true; bool m_ShowSceneInfo = true; bool m_ShowGizmoControls = true; + bool m_ShowOutlineControls = true; + + glm::vec3 m_OutlineColor = glm::vec3(1.0f, 1.0f, 1.0f); + float m_OutlineWidth = 0.25f; }; }; -- cgit v1.3