diff options
| -rw-r--r-- | assets/shaders/compute_texture_quad.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/world_builder_state.cpp | 206 | ||||
| -rw-r--r-- | src/states/world_builder_state.h | 8 |
9 files changed, 144 insertions, 110 deletions
diff --git a/assets/shaders/compute_texture_quad.glsl b/assets/shaders/compute_texture_quad.glsl index b7b76d0..95f433d 100644 --- a/assets/shaders/compute_texture_quad.glsl +++ b/assets/shaders/compute_texture_quad.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 7e22bc9..57f577d 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 bba6ee2..9c2b061 100644 --- a/src/core/camera.cpp +++ b/src/core/camera.cpp @@ -163,7 +163,7 @@ namespace Donut glm::vec3 Camera::get_orbital_position() const { - float clamped_elevation = glm::clamp(m_elevation, 0.01f, float(M_PI) - 0.01f); + float clamped_elevation = glm::clamp(m_elevation, 0.01f, float(std::numbers::pi) - 0.01f); return glm::vec3 ( m_orbital_radius * sin(clamped_elevation) * cos(m_azimuth), @@ -191,7 +191,7 @@ namespace Donut m_azimuth += dx * m_orbital_speed; m_elevation -= dy * m_orbital_speed; - 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_last_x_orbital = x; diff --git a/src/core/camera.h b/src/core/camera.h index 809be48..677cb71 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_orbital_min_radius = 1e10; double m_orbital_max_radius = 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_orbital_speed = 0.01f; double m_zoom_speed = 25e9f; bool m_dragging = false; diff --git a/src/engine/engine.h b/src/engine/engine.h index 0d0fb1b..124fa39 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 c45815b..19938d8 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/world_builder_state.cpp b/src/states/world_builder_state.cpp index 16b7866..ad0e57b 100644 --- a/src/states/world_builder_state.cpp +++ b/src/states/world_builder_state.cpp @@ -17,15 +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 - namespace Donut { void WorldBuilderState::on_enter() @@ -41,7 +37,7 @@ namespace Donut m_camera.set_orbital_speed(0.01f); m_camera.set_zoom_speed(2.0f); m_camera.set_azimuth(0.0f); - m_camera.set_elevation(static_cast<float>(M_PI) / 3.0f); + m_camera.set_elevation(static_cast<float>(std::numbers::pi) / 3.0f); m_camera.update_orbital(); Material default_material(glm::vec3(0.8f, 0.2f, 0.2f), 0.5f, 0.0f); @@ -56,6 +52,9 @@ namespace Donut Object sphere3(glm::vec3(0.0f, 2.0f, 0.0f), 0.8f, material3); m_scene.objs.push_back(sphere3); + m_sphere_shader = Ref<Shader>(Shader::create("assets/shaders/sphere.glsl")); + initialize_sphere_geometry(); + m_initialized = true; } @@ -83,7 +82,7 @@ namespace Donut float new_azimuth = m_camera.get_azimuth() + azimuth_delta; float new_elevation = m_camera.get_elevation() + elevation_delta; - new_elevation = glm::clamp(new_elevation, 0.01f, static_cast<float>(M_PI) - 0.01f); + new_elevation = glm::clamp(new_elevation, 0.01f, static_cast<float>(std::numbers::pi) - 0.01f); m_camera.set_azimuth(new_azimuth); m_camera.set_elevation(new_elevation); @@ -95,7 +94,7 @@ namespace Donut void WorldBuilderState::on_render() { - RenderCommand::set_clear_color(glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)); + RenderCommand::set_clear_color(glm::vec4(0.05f, 0.05f, 0.05f, 1.0f)); RenderCommand::clear(); render_scene(); } @@ -119,8 +118,8 @@ namespace Donut int width, height; glfwGetFramebufferSize(window, &width, &height); - float ndc_x = (2.0f * xpos) / width - 1.0f; - float ndc_y = 1.0f - (2.0f * ypos) / height; + float ndc_x = (2.0f * static_cast<float>(xpos)) / static_cast<float>(width) - 1.0f; + float ndc_y = 1.0f - (2.0f * static_cast<float>(ypos)) / static_cast<float>(height); glm::vec4 ray_start_ndc(ndc_x, ndc_y, -1.0f, 1.0f); glm::vec4 ray_end_ndc(ndc_x, ndc_y, 0.0f, 1.0f); @@ -174,8 +173,9 @@ namespace Donut } else { - m_camera_dragging = true; - m_last_mouse_pos = glm::vec2(xpos, ypos); + m_selected_object_index = -1; + m_camera_dragging = true; + m_last_mouse_pos = glm::vec2(xpos, ypos); } return true; @@ -288,7 +288,7 @@ namespace Donut { m_camera.set_orbital_radius(15.0f); m_camera.set_azimuth(0.0f); - m_camera.set_elevation(static_cast<float>(M_PI) / 3.0f); + m_camera.set_elevation(static_cast<float>(std::numbers::pi) / 3.0f); m_camera.set_orbital_target(glm::vec3(0.0f, 0.0f, 0.0f)); m_camera.update_orbital(); } @@ -377,6 +377,8 @@ namespace Donut } } } + + ImGui::Spacing(); if (ImGui::CollapsingHeader("Gizmo Controls", &m_show_gizmo_controls)) { @@ -395,6 +397,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_show_outline_controls)) + { + ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Outline Settings:"); + + ImGui::Text("Outline Color:"); + ImGui::ColorEdit3("##OutlineColor", &m_outline_color.x); + + ImGui::Text("Outline Width:"); + ImGui::SliderFloat("##OutlineWidth", &m_outline_width, 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(); @@ -550,85 +568,82 @@ namespace Donut DONUT_ERROR("Failed to load scene"); } - void WorldBuilderState::render_scene() + void WorldBuilderState::initialize_sphere_geometry() { - GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); - int width, height; - glfwGetFramebufferSize(window, &width, &height); - - RenderCommand::set_viewport(0, 0, width, height); - RenderCommand::enable_depth_test(); + std::vector<float> vertices; + std::vector<uint32_t> indices; - static Ref<VertexArray> sphere_vao = nullptr; - static Ref<Shader> sphere_shader = Ref<Shader>(Shader::create("assets/shaders/sphere.glsl")); + const int segments = 32; + const int rings = 16; - if (!sphere_vao) + 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 sin_phi = sin(phi); + float cos_phi = 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 sin_phi = sin(phi); - float cos_phi = cos(phi); + float theta = 2.0f * static_cast<float>(std::numbers::pi) * segment / segments; + float sin_theta = sin(theta); + float cos_theta = cos(theta); - for (int segment = 0; segment <= segments; ++segment) - { - float theta = 2.0f * static_cast<float>(M_PI) * segment / segments; - float sin_theta = sin(theta); - float cos_theta = cos(theta); - - float x = cos_theta * sin_phi; - float y = cos_phi; - float z = sin_theta * sin_phi; - - 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 = cos_theta * sin_phi; + float y = cos_phi; + float z = sin_theta * sin_phi; + + 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 vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); - VertexBufferLayout layout; - layout.push<float>(3); - layout.push<float>(3); - vertex_buffer->set_layout(layout); - - auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); - - sphere_vao = Ref<VertexArray>(VertexArray::create()); - sphere_vao->add_vertex_buffer(vertex_buffer); - sphere_vao->set_index_buffer(index_buffer); } + auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); + VertexBufferLayout layout; + layout.push<float>(3); + layout.push<float>(3); + vertex_buffer->set_layout(layout); + + auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); + + m_sphere_vao = Ref<VertexArray>(VertexArray::create()); + m_sphere_vao->add_vertex_buffer(vertex_buffer); + m_sphere_vao->set_index_buffer(index_buffer); + } + + void WorldBuilderState::render_scene() + { + GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + RenderCommand::set_viewport(0, 0, width, height); + RenderCommand::enable_depth_test(); + glm::mat4 view = m_camera.get_view_matrix(); glm::mat4 projection = m_camera.get_projection_matrix(); glm::mat4 view_projection = projection * view; @@ -636,10 +651,13 @@ namespace Donut glm::vec3 light_pos = m_scene.m_light_pos; glm::vec3 camera_pos = m_camera.get_orbital_position(); - sphere_shader->bind(); - sphere_shader->set_mat4("u_ViewProjection", view_projection); - sphere_shader->set_float3("u_LightPos", light_pos); - sphere_shader->set_float3("u_CameraPos", camera_pos); + m_sphere_shader->bind(); + m_sphere_shader->set_mat4("u_ViewProjection", view_projection); + m_sphere_shader->set_float3("u_LightPos", light_pos); + m_sphere_shader->set_float3("u_CameraPos", camera_pos); + + m_sphere_shader->set_float3("u_OutlineColor", m_outline_color); + m_sphere_shader->set_float("u_OutlineWidth", m_outline_width); for (size_t i = 0; i < m_scene.objs.size(); ++i) { @@ -648,25 +666,27 @@ namespace Donut glm::mat4 transform = glm::translate(glm::mat4(1.0f), obj.m_centre); transform = glm::scale(transform, glm::vec3(obj.m_radius)); - sphere_shader->set_mat4("u_Transform", transform); + m_sphere_shader->set_mat4("u_Transform", transform); - if (m_selected_object_index == static_cast<int>(i)) + bool is_selected = (m_selected_object_index == static_cast<int>(i)); + m_sphere_shader->set_int("u_IsSelected", is_selected ? 1 : 0); + if (is_selected) { glm::vec3 highlight_color = obj.m_material.m_color * 1.5f; highlight_color = glm::clamp(highlight_color, 0.0f, 1.0f); - sphere_shader->set_float3("u_Color", highlight_color); - sphere_shader->set_float("u_Emission", 0.2f); + m_sphere_shader->set_float3("u_Color", highlight_color); + m_sphere_shader->set_float("u_Emission", 0.2f); } else { - sphere_shader->set_float3("u_Color", obj.m_material.m_color); - sphere_shader->set_float("u_Emission", obj.m_material.m_emission); + m_sphere_shader->set_float3("u_Color", obj.m_material.m_color); + m_sphere_shader->set_float("u_Emission", obj.m_material.m_emission); } - sphere_shader->set_float("u_Specular", obj.m_material.m_specular); + m_sphere_shader->set_float("u_Specular", obj.m_material.m_specular); - sphere_vao->bind(); - RenderCommand::draw_indexed(sphere_vao); + m_sphere_vao->bind(); + RenderCommand::draw_indexed(m_sphere_vao); } RenderCommand::disable_depth_test(); diff --git a/src/states/world_builder_state.h b/src/states/world_builder_state.h index c587fbe..4cbe987 100644 --- a/src/states/world_builder_state.h +++ b/src/states/world_builder_state.h @@ -39,11 +39,15 @@ namespace Donut void save_scene(); void load_scene(); void render_scene(); + void initialize_sphere_geometry(); private: Scene m_scene; Camera m_camera; bool m_initialized = false; + Ref<Shader> m_sphere_shader; + Ref<VertexArray> m_sphere_vao; + glm::vec3 m_new_object_position = glm::vec3(0.0f, 0.0f, 0.0f); float m_new_object_radius = 1.0f; glm::vec3 m_new_object_color = glm::vec3(1.0f, 1.0f, 1.0f); @@ -61,5 +65,9 @@ namespace Donut bool m_show_object_creator = true; bool m_show_scene_info = true; bool m_show_gizmo_controls = true; + bool m_show_outline_controls = true; + + glm::vec3 m_outline_color = glm::vec3(1.0f, 1.0f, 1.0f); + float m_outline_width = 0.25f; }; }; |
