diff options
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | config/settings.toml | 17 | ||||
| m--------- | ext/toml11 | 0 | ||||
| -rw-r--r-- | premake5.lua | 2 | ||||
| -rw-r--r-- | src/core/application.cpp | 9 | ||||
| -rw-r--r-- | src/core/settings_manager.cpp | 178 | ||||
| -rw-r--r-- | src/core/settings_manager.h | 70 | ||||
| -rw-r--r-- | src/states/config_state.cpp | 54 | ||||
| -rw-r--r-- | src/states/simulation_state.cpp | 56 |
9 files changed, 382 insertions, 7 deletions
diff --git a/.gitmodules b/.gitmodules index bd955cb..27a424d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ path = ext/imgui url = https://github.com/ocornut/imgui.git branch = docking +[submodule "ext/toml11"] + path = ext/toml11 + url = https://github.com/ToruNiina/toml11 diff --git a/config/settings.toml b/config/settings.toml new file mode 100644 index 0000000..088d789 --- /dev/null +++ b/config/settings.toml @@ -0,0 +1,17 @@ +[simulation] +max_steps_static = 15000 +max_steps_moving = 30000 +compute_height = 256 +target_fps = 60 +early_exit_distance = 5e+12 +gravity_enabled = true + +[graphics] +render_api = "OpenGL" +vsync_enabled = true +enable_anti_aliasing = true +show_fps = true +show_performance_metrics = true +show_debug_info = false +selected_theme = "Dark" + diff --git a/ext/toml11 b/ext/toml11 new file mode 160000 +Subproject 2a18a89008d3daac6d8f9db03ddd582173032c7 diff --git a/premake5.lua b/premake5.lua index 389bdb5..25db23d 100644 --- a/premake5.lua +++ b/premake5.lua @@ -29,6 +29,7 @@ IncludeDir["glfw"] = "ext/glfw/include" IncludeDir["glad"] = "ext/glad/include" IncludeDir["imgui"] = "ext/imgui" IncludeDir["imgui_backends"] = "ext/imgui/backends" +IncludeDir["toml11"] = "ext/toml11/include" group "Dependencies" @@ -284,6 +285,7 @@ project "Donut" "%{IncludeDir.glad}", "%{IncludeDir.imgui}", "%{IncludeDir.imgui_backends}", + "%{IncludeDir.toml11}", } links diff --git a/src/core/application.cpp b/src/core/application.cpp index 30194de..9d2278e 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1,6 +1,7 @@ #include "application.h" #include "rendering/renderer.h" +#include "settings_manager.h" #include "states/simulation_state.h" #include "states/config_state.h" @@ -98,7 +99,12 @@ namespace Donut { Logger::init(); - RendererAPI::set_api(RendererAPI::API::OpenGL); + SettingsManager::initialize(); + + const auto& settings = SettingsManager::get_settings_const(); + RendererAPI::API api = (settings.graphics.render_api == "Vulkan") ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL; + RendererAPI::set_api(api); + Renderer::init(); m_window->init_im_gui(); @@ -117,6 +123,7 @@ namespace Donut m_state_manager->shutdown(); Renderer::shutdown(); + SettingsManager::shutdown(); Logger::shutdown(); } diff --git a/src/core/settings_manager.cpp b/src/core/settings_manager.cpp new file mode 100644 index 0000000..eb68794 --- /dev/null +++ b/src/core/settings_manager.cpp @@ -0,0 +1,178 @@ +#include "settings_manager.h" +#include "log.h" +#include "theme_manager.h" +#include "rendering/renderer.h" + +#include <fstream> +#include <filesystem> +#include <algorithm> + +namespace Donut +{ + Settings SettingsManager::s_settings; + bool SettingsManager::s_initialized = false; + + void SettingsManager::initialize() + { + if (s_initialized) + return; + + load_settings(); + s_initialized = true; + DONUT_INFO("Settings Manager initialized"); + } + + void SettingsManager::shutdown() + { + if (!s_initialized) + return; + + save_settings(); + s_initialized = false; + DONUT_INFO("Settings Manager shutdown"); + } + + void SettingsManager::load_settings() + { + std::string file_path = get_settings_file_path(); + + try + { + if (std::filesystem::exists(file_path)) + { + auto config = toml::parse(file_path); + + if (config.contains("simulation")) + { + auto sim = config["simulation"]; + s_settings.simulation.target_fps = toml::find_or(sim, "target_fps", 60); + s_settings.simulation.compute_height = toml::find_or(sim, "compute_height", 512); + s_settings.simulation.max_steps_moving = toml::find_or(sim, "max_steps_moving", 30000); + s_settings.simulation.max_steps_static = toml::find_or(sim, "max_steps_static", 15000); + s_settings.simulation.early_exit_distance = toml::find_or(sim, "early_exit_distance", 5e12f); + s_settings.simulation.gravity_enabled = toml::find_or(sim, "gravity_enabled", true); + + s_settings.simulation.target_fps = std::max(30, std::min(120, s_settings.simulation.target_fps)); + s_settings.simulation.compute_height = std::max(64, std::min(2048, s_settings.simulation.compute_height)); + s_settings.simulation.max_steps_moving = std::max(1000, std::min(60000, s_settings.simulation.max_steps_moving)); + s_settings.simulation.max_steps_static = std::max(1000, std::min(30000, s_settings.simulation.max_steps_static)); + s_settings.simulation.early_exit_distance = std::max(1e11f, std::min(1e13f, s_settings.simulation.early_exit_distance)); + } + + if (config.contains("graphics")) + { + auto gfx = config["graphics"]; + s_settings.graphics.render_api = toml::find_or(gfx, "render_api", std::string("OpenGL")); + s_settings.graphics.v_sync_enabled = toml::find_or(gfx, "vsync_enabled", true); + s_settings.graphics.show_fps = toml::find_or(gfx, "show_fps", true); + s_settings.graphics.show_performance_metrics = toml::find_or(gfx, "show_performance_metrics", true); + s_settings.graphics.show_debug_info = toml::find_or(gfx, "show_debug_info", false); + s_settings.graphics.enable_anti_aliasing = toml::find_or(gfx, "enable_anti_aliasing", true); + s_settings.graphics.selected_theme = toml::find_or(gfx, "selected_theme", std::string("Dark")); + + if (s_settings.graphics.render_api != "OpenGL" && + s_settings.graphics.render_api != "Vulkan") + s_settings.graphics.render_api = "OpenGL"; + if (s_settings.graphics.selected_theme != "Dark" && + s_settings.graphics.selected_theme != "Light" && + s_settings.graphics.selected_theme != "Blue") + s_settings.graphics.selected_theme = "Dark"; + } + + DONUT_INFO("Settings loaded from {}", file_path); + } + else + { + load_default_settings(); + save_settings(); + DONUT_INFO("No settings file found, created default settings"); + } + } + catch (const std::exception& e) + { + DONUT_ERROR("Failed to load settings: {}", e.what()); + load_default_settings(); + } + } + + void SettingsManager::save_settings() + { + std::string file_path = get_settings_file_path(); + + try + { + std::filesystem::path path(file_path); + std::filesystem::create_directories(path.parent_path()); + + toml::value simulation = toml::table + { + {"target_fps", s_settings.simulation.target_fps }, + {"compute_height", s_settings.simulation.compute_height }, + {"max_steps_moving", s_settings.simulation.max_steps_moving }, + {"max_steps_static", s_settings.simulation.max_steps_static }, + {"early_exit_distance", s_settings.simulation.early_exit_distance}, + {"gravity_enabled", s_settings.simulation.gravity_enabled } + }; + + toml::value graphics = toml::table + { + {"render_api", s_settings.graphics.render_api }, + {"vsync_enabled", s_settings.graphics.v_sync_enabled }, + {"show_fps", s_settings.graphics.show_fps }, + {"show_performance_metrics", s_settings.graphics.show_performance_metrics}, + {"show_debug_info", s_settings.graphics.show_debug_info }, + {"enable_anti_aliasing", s_settings.graphics.enable_anti_aliasing }, + {"selected_theme", s_settings.graphics.selected_theme } + }; + + toml::value config = toml::table + { + {"simulation", simulation}, + {"graphics", graphics} + }; + + std::ofstream file(file_path); + file << config; + file.close(); + + DONUT_INFO("Settings saved to {}", file_path); + } + catch (const std::exception& e) + DONUT_ERROR("Failed to save settings: {}", e.what()); + } + + void SettingsManager::set_simulation_settings(const SimulationSettings& settings) + { + s_settings.simulation = settings; + save_settings(); + } + + void SettingsManager::set_graphics_settings(const GraphicsSettings& settings) + { + s_settings.graphics = settings; + save_settings(); + } + + std::string SettingsManager::get_settings_file_path() + { + return "config/settings.toml"; + } + + void SettingsManager::load_default_settings() + { + s_settings.simulation.target_fps = 60; + s_settings.simulation.compute_height = 512; + s_settings.simulation.max_steps_moving = 30000; + s_settings.simulation.max_steps_static = 15000; + s_settings.simulation.early_exit_distance = 5e12f; + s_settings.simulation.gravity_enabled = true; + + s_settings.graphics.render_api = "OpenGL"; + s_settings.graphics.v_sync_enabled = true; + s_settings.graphics.show_fps = true; + s_settings.graphics.show_performance_metrics = true; + s_settings.graphics.show_debug_info = false; + s_settings.graphics.enable_anti_aliasing = true; + s_settings.graphics.selected_theme = "Dark"; + } +} diff --git a/src/core/settings_manager.h b/src/core/settings_manager.h new file mode 100644 index 0000000..1a36026 --- /dev/null +++ b/src/core/settings_manager.h @@ -0,0 +1,70 @@ +#pragma once + +#include <string> +#include <toml.hpp> + +namespace Donut +{ + struct SimulationSettings + { + int target_fps = 60; + int compute_height = 512; + int max_steps_moving = 30000; + int max_steps_static = 15000; + float early_exit_distance = 5e12f; + bool gravity_enabled = true; + }; + + struct GraphicsSettings + { + std::string render_api = "OpenGL"; + bool v_sync_enabled = true; + bool show_fps = true; + bool show_performance_metrics = true; + bool show_debug_info = false; + bool enable_anti_aliasing = true; + std::string selected_theme = "Dark"; + }; + + struct Settings + { + SimulationSettings simulation; + GraphicsSettings graphics; + }; + + class SettingsManager + { + public: + static void initialize(); + static void shutdown(); + + static void load_settings(); + static void save_settings(); + + static Settings& get_settings() { return s_settings; } + static const Settings& get_settings_const() { return s_settings; } + + static void set_simulation_settings(const SimulationSettings& settings); + static void set_graphics_settings(const GraphicsSettings& settings); + + static int get_target_fps() { return s_settings.simulation.target_fps; } + static int get_compute_height() { return s_settings.simulation.compute_height; } + static int get_max_steps_moving() { return s_settings.simulation.max_steps_moving; } + static int get_max_steps_static() { return s_settings.simulation.max_steps_static; } + static float get_early_exit_distance() { return s_settings.simulation.early_exit_distance; } + static bool get_gravity_enabled() { return s_settings.simulation.gravity_enabled; } + static std::string get_render_api() { return s_settings.graphics.render_api; } + static bool get_v_sync_enabled() { return s_settings.graphics.v_sync_enabled; } + static bool get_show_fps() { return s_settings.graphics.show_fps; } + static bool get_show_performance_metrics() { return s_settings.graphics.show_performance_metrics; } + static bool get_show_debug_info() { return s_settings.graphics.show_debug_info; } + static bool get_enable_anti_aliasing() { return s_settings.graphics.enable_anti_aliasing; } + static std::string get_selected_theme() { return s_settings.graphics.selected_theme; } + private: + static std::string get_settings_file_path(); + static void load_default_settings(); + private: + static Settings s_settings; + static bool s_initialized; + }; +} diff --git a/src/states/config_state.cpp b/src/states/config_state.cpp index 8cf24ef..1f1ef16 100644 --- a/src/states/config_state.cpp +++ b/src/states/config_state.cpp @@ -2,6 +2,7 @@ #include "rendering/renderer.h" #include "core/application.h" #include "core/theme_manager.h" +#include "core/settings_manager.h" #include <imgui.h> #include <imgui_internal.h> @@ -13,8 +14,22 @@ namespace Donut { DONUT_INFO("Entering Config State"); - m_selected_api = Renderer::get_api(); - m_selected_theme = static_cast<int>(ThemeManager::get_current_theme()); + const auto& settings = SettingsManager::get_settings_const(); + + m_selected_api = (settings.graphics.render_api == "Vulkan") ? RendererAPI::API::Vulkan : RendererAPI::API::OpenGL; + m_selected_theme = (settings.graphics.selected_theme == "Light") ? 1 : + (settings.graphics.selected_theme == "Blue") ? 2 : 0; + m_target_fps = settings.simulation.target_fps; + m_compute_height = settings.simulation.compute_height; + m_max_steps_moving = settings.simulation.max_steps_moving; + m_max_steps_static = settings.simulation.max_steps_static; + m_early_exit_distance = settings.simulation.early_exit_distance; + m_gravity_enabled = settings.simulation.gravity_enabled; + m_v_sync_enabled = settings.graphics.v_sync_enabled; + m_show_fps = settings.graphics.show_fps; + m_show_performance_metrics = settings.graphics.show_performance_metrics; + m_show_debug_info = settings.graphics.show_debug_info; + m_enable_anti_aliasing = settings.graphics.enable_anti_aliasing; } void ConfigState::on_exit() @@ -200,7 +215,7 @@ namespace Donut ImGui::Separator(); ImGui::Spacing(); - float button_width = (ImGui::GetWindowWidth() - 80) / 4.0f; + float button_width = (ImGui::GetWindowWidth() - 100) / 5.0f; if (ImGui::Button("Start Simulation", ImVec2(button_width, 35))) { @@ -217,6 +232,13 @@ namespace Donut apply_settings(); ImGui::SameLine(); + if (ImGui::Button("Save Settings", ImVec2(button_width, 35))) + { + apply_settings(); + DONUT_INFO("Settings saved manually"); + } + + ImGui::SameLine(); if (ImGui::Button("Exit", ImVec2(button_width, 35))) Application::get().close(); @@ -237,8 +259,29 @@ namespace Donut void ConfigState::apply_settings() { + SimulationSettings sim_settings; + sim_settings.target_fps = m_target_fps; + sim_settings.compute_height = m_compute_height; + sim_settings.max_steps_moving = m_max_steps_moving; + sim_settings.max_steps_static = m_max_steps_static; + sim_settings.early_exit_distance = m_early_exit_distance; + sim_settings.gravity_enabled = m_gravity_enabled; + + GraphicsSettings gfx_settings; + gfx_settings.render_api = (m_selected_api == RendererAPI::API::Vulkan) ? "Vulkan" : "OpenGL"; + gfx_settings.v_sync_enabled = m_v_sync_enabled; + gfx_settings.show_fps = m_show_fps; + gfx_settings.show_performance_metrics = m_show_performance_metrics; + gfx_settings.show_debug_info = m_show_debug_info; + gfx_settings.enable_anti_aliasing = m_enable_anti_aliasing; + gfx_settings.selected_theme = (m_selected_theme == 1) ? "Light" : + (m_selected_theme == 2) ? "Blue" : "Dark"; + + SettingsManager::set_simulation_settings(sim_settings); + SettingsManager::set_graphics_settings(gfx_settings); + RendererAPI::set_api(m_selected_api); - DONUT_INFO("Settings applied"); + DONUT_INFO("Settings applied and saved"); } void ConfigState::reset_to_defaults() @@ -257,6 +300,7 @@ namespace Donut m_enable_anti_aliasing = true; m_selected_theme = 0; - DONUT_INFO("Settings reset to defaults"); + apply_settings(); + DONUT_INFO("Settings reset to defaults and saved"); } }; diff --git a/src/states/simulation_state.cpp b/src/states/simulation_state.cpp index ff7f658..e71d498 100644 --- a/src/states/simulation_state.cpp +++ b/src/states/simulation_state.cpp @@ -3,6 +3,7 @@ #include "core/application.h" #include "core/window.h" #include "core/event.h" +#include "core/settings_manager.h" #include <imgui.h> #include <GLFW/glfw3.h> @@ -12,6 +13,17 @@ namespace Donut void SimulationState::on_enter() { DONUT_INFO("Entering Simulation State"); + + const auto& settings = SettingsManager::get_settings_const(); + + m_engine.set_target_fps(settings.simulation.target_fps); + m_engine.set_compute_height(settings.simulation.compute_height); + m_engine.set_max_steps_moving(settings.simulation.max_steps_moving); + m_engine.set_max_steps_static(settings.simulation.max_steps_static); + m_engine.set_early_exit_distance(settings.simulation.early_exit_distance); + m_engine.get_gravity() = settings.simulation.gravity_enabled; + + m_engine.update_compute_dimensions(); m_initialized = true; } @@ -92,8 +104,22 @@ namespace Donut ImGui::Begin("Simulation Controls", nullptr, ImGuiWindowFlags_NoCollapse); ImGui::TextColored(ImVec4(0.8f, 0.8f, 1.0f, 1.0f), "Black Hole Simulation"); + ImGui::SameLine(); if (ImGui::Button("Back to Config")) Application::get().get_state_manager().switch_to_state("Config"); + ImGui::SameLine(); + if (ImGui::Button("Save Settings")) + { + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.target_fps = m_engine.get_target_fps(); + settings.compute_height = m_engine.get_compute_height(); + settings.max_steps_moving = m_engine.get_max_steps_moving(); + settings.max_steps_static = m_engine.get_max_steps_static(); + settings.early_exit_distance = m_engine.get_early_exit_distance(); + settings.gravity_enabled = m_engine.get_gravity(); + SettingsManager::set_simulation_settings(settings); + DONUT_INFO("Simulation settings saved manually"); + } ImGui::Separator(); @@ -106,7 +132,12 @@ namespace Donut int target_fps = m_engine.get_target_fps(); if (ImGui::SliderInt("Target FPS", &target_fps, 30, 120)) + { m_engine.set_target_fps(target_fps); + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.target_fps = target_fps; + SettingsManager::set_simulation_settings(settings); + } ImGui::Spacing(); @@ -122,6 +153,9 @@ namespace Donut { m_engine.set_compute_height(compute_height); m_engine.update_compute_dimensions(); + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.compute_height = compute_height; + SettingsManager::set_simulation_settings(settings); } ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Compute Width: %d (auto-calculated)", m_engine.get_compute_width()); @@ -133,13 +167,28 @@ namespace Donut int max_steps_moving = m_engine.get_max_steps_moving(); if (ImGui::SliderInt("Max Steps (Moving)", &max_steps_moving, 1000, 60000)) + { m_engine.set_max_steps_moving(max_steps_moving); + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.max_steps_moving = max_steps_moving; + SettingsManager::set_simulation_settings(settings); + } int max_steps_static = m_engine.get_max_steps_static(); if (ImGui::SliderInt("Max Steps (Static)", &max_steps_static, 1000, 30000)) + { m_engine.set_max_steps_static(max_steps_static); + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.max_steps_static = max_steps_static; + SettingsManager::set_simulation_settings(settings); + } float early_exit_distance = m_engine.get_early_exit_distance(); if (ImGui::SliderFloat("Early Exit Distance", &early_exit_distance, 1e11f, 1e13f, "%.2e")) + { m_engine.set_early_exit_distance(early_exit_distance); + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.early_exit_distance = early_exit_distance; + SettingsManager::set_simulation_settings(settings); + } ImGui::Spacing(); @@ -147,7 +196,12 @@ namespace Donut ImGui::Separator(); bool& gravity = m_engine.get_gravity(); - ImGui::Checkbox("Gravity Enabled", &gravity); + if (ImGui::Checkbox("Gravity Enabled", &gravity)) + { + SimulationSettings settings = SettingsManager::get_settings_const().simulation; + settings.gravity_enabled = gravity; + SettingsManager::set_simulation_settings(settings); + } ImGui::Spacing(); |
