diff options
| -rw-r--r-- | Assets/Shaders/ComputeTextureQuad.glsl | 2 | ||||
| -rw-r--r-- | Assets/Shaders/Sphere.glsl | 17 | ||||
| -rw-r--r-- | premake5.lua | 2 | ||||
| -rw-r--r-- | src/Core/Camera.cpp | 4 | ||||
| -rw-r--r-- | src/Core/Camera.h | 7 | ||||
| -rw-r--r-- | src/Engine/Engine.h | 6 | ||||
| -rw-r--r-- | src/Engine/Object.h | 2 | ||||
| -rw-r--r-- | src/States/WorldBuilderState.cpp | 208 | ||||
| -rw-r--r-- | 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 <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> -#define _USE_MATH_DEFINES -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +#include <numbers> 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<float>(M_PI) / 2.0f; + float m_Elevation = static_cast<float>(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 <vector> +#include <numbers> #include <iostream> #include <fstream> #include <sstream> @@ -21,11 +22,6 @@ #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> -#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<float>(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 <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> +#include <numbers> #include <fstream> #include <sstream> #include <limits> -#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<float>(M_PI) / 3.0f); + m_Camera.SetElevation(static_cast<float>(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>(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<float>(M_PI) - 0.01f); + newElevation = glm::clamp(newElevation, 0.01f, static_cast<float>(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<float>(xpos)) / static_cast<float>(width) - 1.0f; + float ndcY = 1.0f - (2.0f * static_cast<float>(ypos)) / static_cast<float>(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<float>(M_PI) / 3.0f); + m_Camera.SetElevation(static_cast<float>(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<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::SetViewport(0, 0, width, height); - RenderCommand::EnableDepthTest(); + std::vector<float> vertices; + std::vector<uint32_t> indices; - static Ref<VertexArray> sphereVAO = nullptr; - static Ref<Shader> sphereShader = Ref<Shader>(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<float> vertices; - std::vector<uint32_t> indices; - - const int segments = 32; - const int rings = 16; + float phi = static_cast<float>(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<float>(M_PI) * ring / rings; - float sinPhi = sin(phi); - float cosPhi = cos(phi); + float theta = 2.0f * static_cast<float>(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<float>(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>(VertexBuffer::Create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); - VertexBufferLayout layout; - layout.Push<float>(3); - layout.Push<float>(3); - vertexBuffer->SetLayout(layout); - - auto indexBuffer = Ref<IndexBuffer>(IndexBuffer::Create(indices.data(), static_cast<uint32_t>(indices.size()))); - - sphereVAO = Ref<VertexArray>(VertexArray::Create()); - sphereVAO->AddVertexBuffer(vertexBuffer); - sphereVAO->SetIndexBuffer(indexBuffer); } + auto vertexBuffer = Ref<VertexBuffer>(VertexBuffer::Create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); + VertexBufferLayout layout; + layout.Push<float>(3); + layout.Push<float>(3); + vertexBuffer->SetLayout(layout); + + auto indexBuffer = Ref<IndexBuffer>(IndexBuffer::Create(indices.data(), static_cast<uint32_t>(indices.size()))); + + m_SphereVAO = Ref<VertexArray>(VertexArray::Create()); + m_SphereVAO->AddVertexBuffer(vertexBuffer); + m_SphereVAO->SetIndexBuffer(indexBuffer); + } + + void WorldBuilderState::RenderScene() + { + GLFWwindow* window = static_cast<GLFWwindow*>(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<int>(i)) + bool isSelected = (m_SelectedObjectIndex == static_cast<int>(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<Shader> m_SphereShader; + Ref<VertexArray> 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; }; }; |
