aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-18 05:02:13 +0200
committerhachem <im@hachem.wtf>2025-08-18 05:02:13 +0200
commitd34925777dd4fac709096f1c18b7d886b43c15b2 (patch)
treefac4c30a28784672c701898ff7612dbdfe530d49
parent1ecaea469e86ef3f5d18122c8b2cc187286e27f7 (diff)
[fix]: improvements, bump to c++20 and fix bugs
-rw-r--r--Assets/Shaders/ComputeTextureQuad.glsl2
-rw-r--r--Assets/Shaders/Sphere.glsl17
-rw-r--r--premake5.lua2
-rw-r--r--src/Core/Camera.cpp4
-rw-r--r--src/Core/Camera.h7
-rw-r--r--src/Engine/Engine.h6
-rw-r--r--src/Engine/Object.h2
-rw-r--r--src/States/WorldBuilderState.cpp208
-rw-r--r--src/States/WorldBuilderState.h8
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;
};
};