diff options
Diffstat (limited to 'src/ui/ui_layer.cpp')
| -rw-r--r-- | src/ui/ui_layer.cpp | 104 |
1 files changed, 99 insertions, 5 deletions
diff --git a/src/ui/ui_layer.cpp b/src/ui/ui_layer.cpp index 6748be2..4aa470b 100644 --- a/src/ui/ui_layer.cpp +++ b/src/ui/ui_layer.cpp @@ -6,7 +6,12 @@ #include "rendering/render_api.h" #include <imgui.h> +#include <ImGuizmo.h> #include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> +#include <algorithm> +#include <cstdlib> +#include <cstdio> #include <string> namespace Donut @@ -52,7 +57,7 @@ namespace Donut namespace { - // Setup: renderer backend + environment + // Setup: display / renderer / overlay / environment settings class SetupWorkspace : public Workspace { public: @@ -60,9 +65,52 @@ namespace Donut auto view() const -> View override { return View::None; } auto on_ui(const UIContext& ctx) -> void override { + auto& s = SettingsManager::get_settings(); + + if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) + { + const bool fs = ctx.actions.is_fullscreen(); + int cw = 0, ch = 0; ctx.actions.get_window_size(cw, ch); + + // Resolution presets (windowed only). + struct Res { const char* label; int w, h; }; + static const Res kRes[] = { + { "1280 x 720", 1280, 720 }, { "1600 x 900", 1600, 900 }, + { "1920 x 1080", 1920, 1080 }, { "2560 x 1440", 2560, 1440 }, + }; + char cur_label[32]; std::snprintf(cur_label, sizeof(cur_label), "%d x %d", cw, ch); + ImGui::BeginDisabled(fs); + if (ImGui::BeginCombo("Resolution", cur_label)) + { + for (const auto& r : kRes) + if (ImGui::Selectable(r.label, cw == r.w && ch == r.h)) + ctx.actions.set_resolution(r.w, r.h); + ImGui::EndCombo(); + } + ImGui::EndDisabled(); + + bool fs_v = fs; + if (ImGui::Checkbox("Fullscreen", &fs_v)) ctx.actions.set_fullscreen(fs_v); + + if (ImGui::Checkbox("V-Sync", &s.graphics.v_sync_enabled)) + { + ctx.actions.set_vsync(s.graphics.v_sync_enabled); + SettingsManager::save_settings(); + } + + ImGui::BeginDisabled(s.graphics.v_sync_enabled); + if (ImGui::SliderInt("Frame cap", &s.simulation.target_fps, 30, 240, "%d FPS")) + SettingsManager::save_settings(); + ImGui::EndDisabled(); + if (s.graphics.v_sync_enabled) + ImGui::TextDisabled("Frame cap applies only with V-Sync off."); + + if (ImGui::SliderFloat("UI scale", &m_ui_scale, 0.8f, 1.6f, "%.2fx")) + ctx.actions.set_ui_scale(m_ui_scale); + } + if (ImGui::CollapsingHeader("Renderer", ImGuiTreeNodeFlags_DefaultOpen)) { - auto& s = SettingsManager::get_settings(); const char* apis[] = { "OpenGL", "Vulkan" }; int cur = (s.graphics.render_api == "Vulkan") ? 1 : 0; if (ImGui::Combo("Graphics API", &cur, apis, 2)) @@ -74,7 +122,15 @@ namespace Donut if (s.graphics.render_api != running) ImGui::TextColored(ImVec4(0.98f, 0.62f, 0.20f, 1.0f), "Restart to apply (%s running)", running); else - ImGui::TextDisabled("Active backend: %s", running); + ImGui::TextDisabled("Active backend: %s (%s)", running, ctx.device_name.c_str()); + } + + if (ImGui::CollapsingHeader("Overlay", ImGuiTreeNodeFlags_DefaultOpen)) + { + bool dirty = false; + dirty |= ImGui::Checkbox("Show FPS", &s.graphics.show_fps); + dirty |= ImGui::Checkbox("Show frame time", &s.graphics.show_performance_metrics); + if (dirty) SettingsManager::save_settings(); } if (ImGui::CollapsingHeader("Environment", ImGuiTreeNodeFlags_DefaultOpen)) @@ -95,6 +151,8 @@ namespace Donut ImGui::TextDisabled("Switching rebuilds the cubemap (brief pause)."); } } + private: + float m_ui_scale = 1.0f; }; // Scene: place and edit objects @@ -141,8 +199,36 @@ namespace Donut ImGui::DragFloat3("Position", &o.position.x, 0.1f); ImGui::DragFloat("Radius", &o.radius, 0.05f, 0.1f, 20.0f); ImGui::ColorEdit3("Color", &o.color.x); + + ImGui::Spacing(); + if (ImGui::RadioButton("Move", m_op == ImGuizmo::TRANSLATE)) m_op = ImGuizmo::TRANSLATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Scale", m_op == ImGuizmo::SCALE)) m_op = ImGuizmo::SCALE; + ImGui::SameLine(); ImGui::TextDisabled("(drag the handles in the viewport)"); + + // Viewport gizmo for the selected sphere. Uses the scene camera + // (its projection was set for this frame by the Application) and + // draws into the background draw list so it sits over the render + // but under the panels. + ImGuizmo::SetOrthographic(false); + ImGuizmo::SetDrawlist(ImGui::GetBackgroundDrawList()); + ImGuiIO& io = ImGui::GetIO(); + ImGuizmo::SetRect(0.0f, 0.0f, io.DisplaySize.x, io.DisplaySize.y); + glm::mat4 view = sc.scene_camera.get_view_matrix(); + glm::mat4 proj = sc.scene_camera.get_projection_matrix(); + glm::mat4 xform = glm::translate(glm::mat4(1.0f), o.position) + * glm::scale(glm::mat4(1.0f), glm::vec3(o.radius)); + if (ImGuizmo::Manipulate(&view[0][0], &proj[0][0], m_op, ImGuizmo::WORLD, &xform[0][0])) + { + float t[3], r[3], s[3]; + ImGuizmo::DecomposeMatrixToComponents(&xform[0][0], t, r, s); + o.position = glm::vec3(t[0], t[1], t[2]); + o.radius = std::max(0.05f, (s[0] + s[1] + s[2]) / 3.0f); + } } } + private: + ImGuizmo::OPERATION m_op = ImGuizmo::TRANSLATE; }; // Simulation: camera + accretion disk + quality @@ -239,6 +325,8 @@ namespace Donut static bool styled = false; if (!styled) { apply_donut_style(); styled = true; } + ImGuizmo::BeginFrame(); // gizmos are drawn by the Scene workspace + // Full-viewport dock space with a pass-through centre, so the panel docks to // any edge while the render shows through the middle. ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); @@ -248,8 +336,14 @@ namespace Donut ImGuiIO& io = ImGui::GetIO(); ImGui::TextDisabled("%s", ctx.device_name.empty() ? "GPU" : ctx.device_name.c_str()); - ImGui::Text("%.0f FPS", io.Framerate); - ImGui::SameLine(); ImGui::TextDisabled("%.1f ms/frame", io.Framerate > 0 ? 1000.0f / io.Framerate : 0.0f); + const bool show_fps = SettingsManager::get_show_fps(); + const bool show_ms = SettingsManager::get_show_performance_metrics(); + if (show_fps) ImGui::Text("%.0f FPS", io.Framerate); + if (show_ms) + { + if (show_fps) ImGui::SameLine(); + ImGui::TextDisabled("%.1f ms/frame", io.Framerate > 0 ? 1000.0f / io.Framerate : 0.0f); + } ImGui::Spacing(); if (ImGui::BeginTabBar("workspaces")) |
