From f9c1c4843d92eccc57ec9ef55e0b7e7f8bdae4b8 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 1 Apr 2026 18:57:32 +0200 Subject: [PATCH] reestructurat el apartat de video de config.yaml --- source/core/input/global_inputs.cpp | 16 +- source/core/rendering/render_info.cpp | 10 +- source/core/rendering/screen.cpp | 44 ++--- source/game/defaults.hpp | 2 +- source/game/options.cpp | 260 ++++++++++++++++---------- source/game/options.hpp | 56 ++++-- source/game/ui/console.cpp | 48 ++--- source/utils/defines.hpp | 2 +- 8 files changed, 256 insertions(+), 182 deletions(-) diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index 9862dc8..190bbe6 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -92,21 +92,21 @@ namespace GlobalInputs { void handleToggleShaders() { Screen::get()->toggleShaders(); - Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.shaders_enabled" : "ui.shaders_disabled")}); // NOLINT(readability-static-accessed-through-instance) + Notifier::get()->show({Locale::get()->get(Options::video.shader.enabled ? "ui.shaders_enabled" : "ui.shaders_disabled")}); // NOLINT(readability-static-accessed-through-instance) } void handleNextShaderPreset() { - if (Options::current_shader == Rendering::ShaderType::CRTPI) { + if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) { if (!Options::crtpi_presets.empty()) { - Options::current_crtpi_preset = (Options::current_crtpi_preset + 1) % static_cast(Options::crtpi_presets.size()); + Options::video.shader.current_crtpi_preset = (Options::video.shader.current_crtpi_preset + 1) % static_cast(Options::crtpi_presets.size()); Screen::get()->reloadCrtPi(); - Notifier::get()->show({Locale::get()->get("ui.crtpi") + " " + Options::crtpi_presets[static_cast(Options::current_crtpi_preset)].name}); // NOLINT(readability-static-accessed-through-instance) + Notifier::get()->show({Locale::get()->get("ui.crtpi") + " " + Options::crtpi_presets[static_cast(Options::video.shader.current_crtpi_preset)].name}); // NOLINT(readability-static-accessed-through-instance) } } else { if (!Options::postfx_presets.empty()) { - Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast(Options::postfx_presets.size()); + Options::video.shader.current_postfx_preset = (Options::video.shader.current_postfx_preset + 1) % static_cast(Options::postfx_presets.size()); Screen::get()->reloadPostFX(); - Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast(Options::current_postfx_preset)].name}); // NOLINT(readability-static-accessed-through-instance) + Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast(Options::video.shader.current_postfx_preset)].name}); // NOLINT(readability-static-accessed-through-instance) } } } @@ -114,7 +114,7 @@ namespace GlobalInputs { void handleNextShader() { Screen::get()->nextShader(); Notifier::get()->show({Locale::get()->get("ui.shader") + " " + // NOLINT(readability-static-accessed-through-instance) - (Options::current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX")}); + (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX")}); } void handleNextPalette() { @@ -165,7 +165,7 @@ namespace GlobalInputs { if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) { return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4 } - if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) { + if (Options::video.shader.enabled && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) { return InputAction::NEXT_SHADER_PRESET; // Shift+F4 } return InputAction::TOGGLE_SHADER; // F4 diff --git a/source/core/rendering/render_info.cpp b/source/core/rendering/render_info.cpp index 6f67919..7763d3c 100644 --- a/source/core/rendering/render_info.cpp +++ b/source/core/rendering/render_info.cpp @@ -89,20 +89,20 @@ void RenderInfo::render() const { line += " | " + zoom_str + "x"; // PostFX: muestra shader + preset y supersampling, o nada si está desactivado - if (Options::video.postfx) { - const bool IS_CRTPI = (Options::current_shader == Rendering::ShaderType::CRTPI); + if (Options::video.shader.enabled) { + const bool IS_CRTPI = (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI); const std::string SHADER_NAME = IS_CRTPI ? "crtpi" : "postfx"; std::string preset_name = "-"; if (IS_CRTPI) { if (!Options::crtpi_presets.empty()) { - preset_name = Options::crtpi_presets[static_cast(Options::current_crtpi_preset)].name; + preset_name = Options::crtpi_presets[static_cast(Options::video.shader.current_crtpi_preset)].name; } } else { if (!Options::postfx_presets.empty()) { - preset_name = Options::postfx_presets[static_cast(Options::current_postfx_preset)].name; + preset_name = Options::postfx_presets[static_cast(Options::video.shader.current_postfx_preset)].name; } } - const bool SHOW_SS = Options::video.supersampling && !IS_CRTPI; + const bool SHOW_SS = Options::video.supersampling.enabled && !IS_CRTPI; line += " | " + SHADER_NAME + " " + preset_name + (SHOW_SS ? " (ss)" : ""); } diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index d3ca9ca..e364335 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -239,11 +239,11 @@ void Screen::renderNotifications() const { // Activa/desactiva todos los shaders respetando el shader actualmente seleccionado void Screen::toggleShaders() { - Options::video.postfx = !Options::video.postfx; + Options::video.shader.enabled = !Options::video.shader.enabled; if (shader_backend_ && shader_backend_->isHardwareAccelerated()) { - if (Options::video.postfx) { + if (Options::video.shader.enabled) { // Activar: usar el shader actualmente seleccionado - if (Options::current_shader == Rendering::ShaderType::CRTPI) { + if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) { shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI); applyCurrentCrtPiPreset(); } else { @@ -262,10 +262,10 @@ void Screen::toggleShaders() { // Recarga el shader del preset actual sin toggle void Screen::reloadPostFX() { - if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) { + if (Options::video.shader.enabled && shader_backend_ && shader_backend_->isHardwareAccelerated()) { // El backend ya está activo: solo actualizar uniforms, sin recrear el pipeline applyCurrentPostFXPreset(); - } else if (Options::video.postfx) { + } else if (Options::video.shader.enabled) { initShaders(); } } @@ -505,14 +505,14 @@ auto loadData(const std::string& filepath) -> std::vector { } void Screen::setLinearUpscale(bool linear) { - Options::video.linear_upscale = linear; + Options::video.supersampling.linear_upscale = linear; if (shader_backend_ && shader_backend_->isHardwareAccelerated()) { shader_backend_->setLinearUpscale(linear); } } void Screen::setDownscaleAlgo(int algo) { - Options::video.downscale_algo = algo; + Options::video.supersampling.downscale_algo = algo; if (shader_backend_ && shader_backend_->isHardwareAccelerated()) { shader_backend_->setDownscaleAlgo(algo); } @@ -525,8 +525,8 @@ auto Screen::getSsTextureSize() const -> std::pair { // Activa/desactiva el supersampling global (Ctrl+F4) void Screen::toggleSupersampling() { - Options::video.supersampling = !Options::video.supersampling; - if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) { + Options::video.supersampling.enabled = !Options::video.supersampling.enabled; + if (Options::video.shader.enabled && shader_backend_ && shader_backend_->isHardwareAccelerated()) { applyCurrentPostFXPreset(); } } @@ -534,11 +534,11 @@ void Screen::toggleSupersampling() { // Aplica los parámetros del preset actual al backend de shaders void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member-functions-to-static) if (shader_backend_ && !Options::postfx_presets.empty()) { - const auto& p = Options::postfx_presets[static_cast(Options::current_postfx_preset)]; - // Supersampling es un toggle global (Options::video.supersampling), no por preset. + const auto& p = Options::postfx_presets[static_cast(Options::video.shader.current_postfx_preset)]; + // Supersampling es un toggle global (Options::video.supersampling.enabled), no por preset. // setOversample primero: puede recrear texturas antes de que setPostFXParams // decida si hornear scanlines en CPU o aplicarlas en GPU. - shader_backend_->setOversample(Options::video.supersampling ? 3 : 1); + shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1); Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding, .flicker = p.flicker}; shader_backend_->setPostFXParams(params); } @@ -547,7 +547,7 @@ void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member- // Aplica los parámetros del preset CrtPi actual al backend de shaders void Screen::applyCurrentCrtPiPreset() { // NOLINT(readability-convert-member-functions-to-static) if (shader_backend_ && !Options::crtpi_presets.empty()) { - const auto& p = Options::crtpi_presets[static_cast(Options::current_crtpi_preset)]; + const auto& p = Options::crtpi_presets[static_cast(Options::video.shader.current_crtpi_preset)]; Rendering::CrtPiParams params{ .scanline_weight = p.scanline_weight, .scanline_gap_brightness = p.scanline_gap_brightness, @@ -570,9 +570,9 @@ void Screen::applyCurrentCrtPiPreset() { // NOLINT(readability-convert-member-f // Cambia el shader de post-procesado activo y aplica el preset correspondiente void Screen::setActiveShader(Rendering::ShaderType type) { - Options::current_shader = type; + Options::video.shader.current_shader = type; if (!shader_backend_) { return; } - if (!Options::video.postfx) { + if (!Options::video.shader.enabled) { // Shaders desactivados: guardar preferencia pero mantener pass-through shader_backend_->setActiveShader(Rendering::ShaderType::POSTFX); shader_backend_->setPostFXParams(Rendering::PostFXParams{}); @@ -588,7 +588,7 @@ void Screen::setActiveShader(Rendering::ShaderType type) { // Cicla al siguiente shader disponible (preparado para futura UI) void Screen::nextShader() { - const Rendering::ShaderType NEXT = (Options::current_shader == Rendering::ShaderType::POSTFX) + const Rendering::ShaderType NEXT = (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX) ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX; setActiveShader(NEXT); @@ -603,7 +603,7 @@ void Screen::initShaders() { if (!shader_backend_) { shader_backend_ = std::make_unique(); const std::string fallback_driver = "none"; - shader_backend_->setPreferredDriver(Options::video.gpu_acceleration ? Options::video.gpu_preferred_driver : fallback_driver); + shader_backend_->setPreferredDriver(Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : fallback_driver); } shader_backend_->init(window_, tex, "", ""); gpu_driver_ = shader_backend_->getDriverName(); @@ -611,10 +611,10 @@ void Screen::initShaders() { // Propagar flags de vsync, integer scale, upscale y downscale al backend GPU shader_backend_->setVSync(Options::video.vertical_sync); shader_backend_->setScaleMode(Options::video.integer_scale); - shader_backend_->setLinearUpscale(Options::video.linear_upscale); - shader_backend_->setDownscaleAlgo(Options::video.downscale_algo); + shader_backend_->setLinearUpscale(Options::video.supersampling.linear_upscale); + shader_backend_->setDownscaleAlgo(Options::video.supersampling.downscale_algo); - if (Options::video.postfx) { + if (Options::video.shader.enabled) { applyCurrentPostFXPreset(); } else { // Pass-through: todos los efectos a 0, el shader solo copia la textura @@ -622,8 +622,8 @@ void Screen::initShaders() { } // Restaurar el shader activo guardado en config (y sus parámetros CrtPi si aplica) - shader_backend_->setActiveShader(Options::current_shader); - if (Options::current_shader == Rendering::ShaderType::CRTPI) { + shader_backend_->setActiveShader(Options::video.shader.current_shader); + if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) { applyCurrentCrtPiPreset(); } } diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index b34f56c..c3f996f 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -25,7 +25,7 @@ namespace Defaults::Video { constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana) constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto - constexpr bool POSTFX = false; // PostFX desactivado por defecto + constexpr bool SHADER_ENABLED = false; // Shaders de post-procesado desactivados por defecto constexpr bool SUPERSAMPLING = false; // Supersampling desactivado por defecto constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto diff --git a/source/game/options.cpp b/source/game/options.cpp index f01911c..fcd28cf 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -297,9 +297,80 @@ namespace Options { } } - // Carga los campos básicos de configuración de video + // Helper: carga la sección gpu desde YAML + void loadGPUConfigFromYaml(const fkyaml::node& gpu_node) { + if (gpu_node.contains("acceleration")) { + try { + video.gpu.acceleration = gpu_node["acceleration"].get_value(); + } catch (...) { + video.gpu.acceleration = Defaults::Video::GPU_ACCELERATION; + } + } + if (gpu_node.contains("preferred_driver")) { + try { + video.gpu.preferred_driver = gpu_node["preferred_driver"].get_value(); + } catch (...) { + video.gpu.preferred_driver = ""; + } + } + } + + // Helper: carga la sección supersampling desde YAML + void loadSupersamplingConfigFromYaml(const fkyaml::node& ss_node) { + if (ss_node.contains("enabled")) { + try { + video.supersampling.enabled = ss_node["enabled"].get_value(); + } catch (...) { + video.supersampling.enabled = Defaults::Video::SUPERSAMPLING; + } + } + if (ss_node.contains("linear_upscale")) { + try { + video.supersampling.linear_upscale = ss_node["linear_upscale"].get_value(); + } catch (...) { + video.supersampling.linear_upscale = Defaults::Video::LINEAR_UPSCALE; + } + } + if (ss_node.contains("downscale_algo")) { + try { + video.supersampling.downscale_algo = ss_node["downscale_algo"].get_value(); + } catch (...) { + video.supersampling.downscale_algo = Defaults::Video::DOWNSCALE_ALGO; + } + } + } + + // Helper: carga la sección shader desde YAML + void loadShaderConfigFromYaml(const fkyaml::node& sh_node) { + if (sh_node.contains("enabled")) { + try { + video.shader.enabled = sh_node["enabled"].get_value(); + } catch (...) { + video.shader.enabled = Defaults::Video::SHADER_ENABLED; + } + } + if (sh_node.contains("current_shader")) { + try { + const std::string s = sh_node["current_shader"].get_value(); + video.shader.current_shader = (s == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX; + } catch (...) { + video.shader.current_shader = Rendering::ShaderType::POSTFX; + } + } + if (sh_node.contains("current_postfx_preset")) { + try { + video.shader.current_postfx_preset_name = sh_node["current_postfx_preset"].get_value(); + } catch (...) {} + } + if (sh_node.contains("current_crtpi_preset")) { + try { + video.shader.current_crtpi_preset_name = sh_node["current_crtpi_preset"].get_value(); + } catch (...) {} + } + } + + // Carga los campos básicos de configuración de video (nivel video:) void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) { - // fullscreen (antes era "mode") if (vid.contains("fullscreen")) { try { video.fullscreen = vid["fullscreen"].get_value(); @@ -308,7 +379,6 @@ namespace Options { } } - // filter (ahora es string) if (vid.contains("filter")) { try { auto filter_str = vid["filter"].get_value(); @@ -318,47 +388,6 @@ namespace Options { } } - if (vid.contains("postfx")) { - try { - video.postfx = vid["postfx"].get_value(); - } catch (...) { - video.postfx = Defaults::Video::POSTFX; - } - } - - if (vid.contains("supersampling")) { - try { - video.supersampling = vid["supersampling"].get_value(); - } catch (...) { - video.supersampling = Defaults::Video::SUPERSAMPLING; - } - } - - if (vid.contains("current_postfx_preset")) { - try { - current_postfx_preset = vid["current_postfx_preset"].get_value(); - } catch (...) { - current_postfx_preset = 0; - } - } - - if (vid.contains("current_crtpi_preset")) { - try { - current_crtpi_preset = vid["current_crtpi_preset"].get_value(); - } catch (...) { - current_crtpi_preset = 0; - } - } - - if (vid.contains("current_shader")) { - try { - const std::string s = vid["current_shader"].get_value(); - current_shader = (s == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX; - } catch (...) { - current_shader = Rendering::ShaderType::POSTFX; - } - } - if (vid.contains("vertical_sync")) { try { video.vertical_sync = vid["vertical_sync"].get_value(); @@ -383,38 +412,6 @@ namespace Options { } } - if (vid.contains("linear_upscale")) { - try { - video.linear_upscale = vid["linear_upscale"].get_value(); - } catch (...) { - video.linear_upscale = Defaults::Video::LINEAR_UPSCALE; - } - } - - if (vid.contains("downscale_algo")) { - try { - video.downscale_algo = vid["downscale_algo"].get_value(); - } catch (...) { - video.downscale_algo = Defaults::Video::DOWNSCALE_ALGO; - } - } - - if (vid.contains("gpu_acceleration")) { - try { - video.gpu_acceleration = vid["gpu_acceleration"].get_value(); - } catch (...) { - video.gpu_acceleration = Defaults::Video::GPU_ACCELERATION; - } - } - - if (vid.contains("gpu_preferred_driver")) { - try { - video.gpu_preferred_driver = vid["gpu_preferred_driver"].get_value(); - } catch (...) { - video.gpu_preferred_driver = ""; - } - } - loadPaletteFromYaml(vid); } @@ -424,10 +421,18 @@ namespace Options { const auto& vid = yaml["video"]; loadBasicVideoFieldsFromYaml(vid); - // Lee border if (vid.contains("border")) { loadBorderConfigFromYaml(vid["border"]); } + if (vid.contains("gpu")) { + loadGPUConfigFromYaml(vid["gpu"]); + } + if (vid.contains("supersampling")) { + loadSupersamplingConfigFromYaml(vid["supersampling"]); + } + if (vid.contains("shader")) { + loadShaderConfigFromYaml(vid["shader"]); + } } } @@ -666,6 +671,25 @@ namespace Options { } } + // Helper: retorna el nombre del preset PostFX actual (para guardar en config) + auto currentPostFXPresetName() -> std::string { + const auto idx = static_cast(video.shader.current_postfx_preset); + if (idx < postfx_presets.size()) { + return postfx_presets[idx].name; + } + // Presets no cargados aún: devolver el nombre almacenado del config + return video.shader.current_postfx_preset_name; + } + + // Helper: retorna el nombre del preset CrtPi actual (para guardar en config) + auto currentCrtPiPresetName() -> std::string { + const auto idx = static_cast(video.shader.current_crtpi_preset); + if (idx < crtpi_presets.size()) { + return crtpi_presets[idx].name; + } + return video.shader.current_crtpi_preset_name; + } + // Guarda las opciones al fichero configurado auto saveToFile() -> bool { // Abre el fichero para escritura @@ -712,24 +736,27 @@ namespace Options { file << "# VIDEO \n"; file << "video:\n"; file << " fullscreen: " << (video.fullscreen ? "true" : "false") << "\n"; - file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n"; - file << " postfx: " << (video.postfx ? "true" : "false") << "\n"; - file << " supersampling: " << (video.supersampling ? "true" : "false") << "\n"; - file << " current_postfx_preset: " << current_postfx_preset << "\n"; - file << " current_crtpi_preset: " << current_crtpi_preset << "\n"; - file << " current_shader: " << (current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n"; file << " vertical_sync: " << (video.vertical_sync ? "true" : "false") << "\n"; file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n"; file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n"; - file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n"; - file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n"; - file << " gpu_acceleration: " << (video.gpu_acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n"; - file << " gpu_preferred_driver: \"" << video.gpu_preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n"; + file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n"; file << " palette: " << video.palette << "\n"; file << " border:\n"; file << " enabled: " << (video.border.enabled ? "true" : "false") << "\n"; file << " width: " << video.border.width << "\n"; file << " height: " << video.border.height << "\n"; + file << " gpu:\n"; + file << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n"; + file << " preferred_driver: \"" << video.gpu.preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n"; + file << " supersampling:\n"; + file << " enabled: " << (video.supersampling.enabled ? "true" : "false") << "\n"; + file << " linear_upscale: " << (video.supersampling.linear_upscale ? "true" : "false") << "\n"; + file << " downscale_algo: " << video.supersampling.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n"; + file << " shader:\n"; + file << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n"; + file << " current_shader: " << (video.shader.current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n"; + file << " current_postfx_preset: " << currentPostFXPresetName() << "\n"; + file << " current_crtpi_preset: " << currentCrtPiPresetName() << "\n"; file << "\n"; // KEYBOARD CONTROLS @@ -773,6 +800,40 @@ namespace Options { return true; } + // Resuelve el nombre del preset PostFX a índice dentro del vector de presets + void resolvePostFXPresetName() { + const auto& name = video.shader.current_postfx_preset_name; + if (name.empty()) { + video.shader.current_postfx_preset = 0; + return; + } + for (int i = 0; i < static_cast(postfx_presets.size()); ++i) { + if (postfx_presets[static_cast(i)].name == name) { + video.shader.current_postfx_preset = i; + return; + } + } + std::cout << "PostFX preset '" << name << "' not found, defaulting to first preset\n"; + video.shader.current_postfx_preset = 0; + } + + // Resuelve el nombre del preset CrtPi a índice dentro del vector de presets + void resolveCrtPiPresetName() { + const auto& name = video.shader.current_crtpi_preset_name; + if (name.empty()) { + video.shader.current_crtpi_preset = 0; + return; + } + for (int i = 0; i < static_cast(crtpi_presets.size()); ++i) { + if (crtpi_presets[static_cast(i)].name == name) { + video.shader.current_crtpi_preset = i; + return; + } + } + std::cout << "CrtPi preset '" << name << "' not found, defaulting to first preset\n"; + video.shader.current_crtpi_preset = 0; + } + // Establece la ruta del fichero de PostFX void setPostFXFile(const std::string& path) { postfx_file_path = path; @@ -824,14 +885,11 @@ namespace Options { } } - // Preservar el índice cargado desde config.yaml; clampar al rango válido. + // Resolver el nombre del preset a índice if (!postfx_presets.empty()) { - current_postfx_preset = std::clamp( - current_postfx_preset, - 0, - static_cast(postfx_presets.size()) - 1); + resolvePostFXPresetName(); } else { - current_postfx_preset = 0; + video.shader.current_postfx_preset = 0; } std::cout << "PostFX file loaded: " << postfx_presets.size() << " preset(s)\n"; @@ -936,7 +994,7 @@ namespace Options { postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}); postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F}); postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F}); - current_postfx_preset = 0; + video.shader.current_postfx_preset = 0; return true; } @@ -967,7 +1025,7 @@ namespace Options { crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false}); crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true}); crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false}); - current_crtpi_preset = 0; + video.shader.current_crtpi_preset = 0; return true; } out << "# JailDoctor's Dilemma - CrtPi Shader Presets\n"; @@ -1048,7 +1106,7 @@ namespace Options { crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false}); crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true}); crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false}); - current_crtpi_preset = 0; + video.shader.current_crtpi_preset = 0; return true; } @@ -1107,13 +1165,11 @@ namespace Options { } } + // Resolver el nombre del preset a índice if (!crtpi_presets.empty()) { - current_crtpi_preset = std::clamp( - current_crtpi_preset, - 0, - static_cast(crtpi_presets.size()) - 1); + resolveCrtPiPresetName(); } else { - current_crtpi_preset = 0; + video.shader.current_crtpi_preset = 0; } std::cout << "CrtPi file loaded: " << crtpi_presets.size() << " preset(s)\n"; @@ -1124,7 +1180,7 @@ namespace Options { // Cargar defaults en memoria en caso de error crtpi_presets.clear(); crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false}); - current_crtpi_preset = 0; + video.shader.current_crtpi_preset = 0; return false; } } diff --git a/source/game/options.hpp b/source/game/options.hpp index b3d874b..708de4b 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -75,22 +75,42 @@ namespace Options { float height{Defaults::Border::HEIGHT}; // Alto del borde }; + // Estructura para las opciones de GPU + struct GPU { + bool acceleration{Defaults::Video::GPU_ACCELERATION}; // Usar aceleración GPU; false = path SDL fallback directo + std::string preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque. + }; + + // Estructura para las opciones de supersampling + struct Supersampling { + bool enabled{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo + bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false) + int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 + }; + + // Estructura para las opciones de shader (dentro de Video) + struct ShaderConfig { + bool enabled{Defaults::Video::SHADER_ENABLED}; // Indica si se usan shaders de post-procesado + Rendering::ShaderType current_shader{Rendering::ShaderType::POSTFX}; // Shader de post-procesado activo + std::string current_postfx_preset_name; // Nombre del preset PostFX leído del config + std::string current_crtpi_preset_name; // Nombre del preset CrtPi leído del config + int current_postfx_preset{0}; // Índice resuelto del preset PostFX + int current_crtpi_preset{0}; // Índice resuelto del preset CrtPi + }; + // Estructura para las opciones de video struct Video { - bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa - Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen - bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no - bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no - bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo - bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa - bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa - bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false) - int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 - Border border{}; // Borde de la pantalla - std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego - std::string info; // Información sobre el modo de vídeo - bool gpu_acceleration{Defaults::Video::GPU_ACCELERATION}; // Usar aceleración GPU; false = path SDL fallback directo - std::string gpu_preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque. + bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa + Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen + bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no + bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa + bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa + std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego + std::string info; // Información sobre el modo de vídeo + Border border{}; // Borde de la pantalla + GPU gpu{}; // Opciones de aceleración GPU + Supersampling supersampling{}; // Opciones de supersampling + ShaderConfig shader{}; // Opciones de shader post-procesado }; // Estructura para las opciones de musica @@ -172,17 +192,12 @@ namespace Options { // --- Variables PostFX --- inline std::vector postfx_presets{}; // Lista de presets de PostFX - inline int current_postfx_preset{0}; // Índice del preset de PostFX actual inline std::string postfx_file_path{}; // Ruta del fichero postfx.yaml // --- Variables CrtPi --- inline std::vector crtpi_presets{}; // Lista de presets del shader CRT-Pi - inline int current_crtpi_preset{0}; // Índice del preset CRT-Pi actual inline std::string crtpi_file_path{}; // Ruta del fichero crtpi.yaml - // --- Shader activo --- - inline Rendering::ShaderType current_shader{Rendering::ShaderType::POSTFX}; // Shader de post-procesado activo - // --- Funciones públicas --- void setConfigFile(const std::string& path); // Establece la ruta del fichero de configuración auto loadFromFile() -> bool; // Carga las opciones desde el fichero configurado @@ -193,4 +208,7 @@ namespace Options { void setCrtPiFile(const std::string& path); // Establece la ruta del fichero de CrtPi auto loadCrtPiFromFile() -> bool; // Carga los presets de CrtPi desde el fichero (crea defaults si no existe) + void resolvePostFXPresetName(); // Resuelve el nombre del preset PostFX a índice + void resolveCrtPiPresetName(); // Resuelve el nombre del preset CrtPi a índice + } // namespace Options \ No newline at end of file diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 0d46c0f..d4a1d2e 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -150,23 +150,23 @@ static const std::vector COMMANDS = { if (!Screen::get()->isHardwareAccelerated()) { return "No GPU acceleration"; } static const std::array DOWNSCALE_NAMES = {"Bilinear", "Lanczos2", "Lanczos3"}; if (!args.empty() && args[0] == "SIZE") { - if (!Options::video.supersampling) { return "Supersampling is OFF: no texture"; } + if (!Options::video.supersampling.enabled) { return "Supersampling is OFF: no texture"; } const auto [w, h] = Screen::get()->getSsTextureSize(); if (w == 0) { return "SS texture: not active"; } return "SS texture: " + std::to_string(w) + "x" + std::to_string(h); } if (!args.empty() && args[0] == "UPSCALE") { if (args.size() == 1) { - Screen::get()->setLinearUpscale(!Options::video.linear_upscale); - return std::string("Upscale: ") + (Options::video.linear_upscale ? "Linear" : "Nearest"); + Screen::get()->setLinearUpscale(!Options::video.supersampling.linear_upscale); + return std::string("Upscale: ") + (Options::video.supersampling.linear_upscale ? "Linear" : "Nearest"); } if (args[1] == "NEAREST") { - if (!Options::video.linear_upscale) { return "Upscale already Nearest"; } + if (!Options::video.supersampling.linear_upscale) { return "Upscale already Nearest"; } Screen::get()->setLinearUpscale(false); return "Upscale: Nearest"; } if (args[1] == "LINEAR") { - if (Options::video.linear_upscale) { return "Upscale already Linear"; } + if (Options::video.supersampling.linear_upscale) { return "Upscale already Linear"; } Screen::get()->setLinearUpscale(true); return "Upscale: Linear"; } @@ -174,14 +174,14 @@ static const std::vector COMMANDS = { } if (!args.empty() && args[0] == "DOWNSCALE") { if (args.size() == 1) { - return std::string("Downscale: ") + std::string(DOWNSCALE_NAMES[static_cast(Options::video.downscale_algo)]); + return std::string("Downscale: ") + std::string(DOWNSCALE_NAMES[static_cast(Options::video.supersampling.downscale_algo)]); } int algo = -1; if (args[1] == "BILINEAR") { algo = 0; } if (args[1] == "LANCZOS2") { algo = 1; } if (args[1] == "LANCZOS3") { algo = 2; } if (algo == -1) { return "usage: ss downscale [bilinear|lanczos2|lanczos3]"; } - if (Options::video.downscale_algo == algo) { + if (Options::video.supersampling.downscale_algo == algo) { return std::string("Downscale already ") + std::string(DOWNSCALE_NAMES[static_cast(algo)]); } Screen::get()->setDownscaleAlgo(algo); @@ -189,15 +189,15 @@ static const std::vector COMMANDS = { } if (args.empty()) { Screen::get()->toggleSupersampling(); - return std::string("PostFX Supersampling ") + (Options::video.supersampling ? "ON" : "OFF"); + return std::string("PostFX Supersampling ") + (Options::video.supersampling.enabled ? "ON" : "OFF"); } if (args[0] == "ON") { - if (Options::video.supersampling) { return "Supersampling already ON"; } + if (Options::video.supersampling.enabled) { return "Supersampling already ON"; } Screen::get()->toggleSupersampling(); return "PostFX Supersampling ON"; } if (args[0] == "OFF") { - if (!Options::video.supersampling) { return "Supersampling already OFF"; } + if (!Options::video.supersampling.enabled) { return "Supersampling already OFF"; } Screen::get()->toggleSupersampling(); return "PostFX Supersampling OFF"; } @@ -214,15 +214,15 @@ static const std::vector COMMANDS = { if (!Screen::get()->isHardwareAccelerated()) { return "No GPU acceleration"; } if (args.empty()) { Screen::get()->toggleShaders(); - return std::string("Shader ") + (Options::video.postfx ? "ON" : "OFF"); + return std::string("Shader ") + (Options::video.shader.enabled ? "ON" : "OFF"); } if (args[0] == "ON") { - if (Options::video.postfx) { return "Shader already ON"; } + if (Options::video.shader.enabled) { return "Shader already ON"; } Screen::get()->toggleShaders(); return "Shader ON"; } if (args[0] == "OFF") { - if (!Options::video.postfx) { return "Shader already OFF"; } + if (!Options::video.shader.enabled) { return "Shader already OFF"; } Screen::get()->toggleShaders(); return "Shader OFF"; } @@ -237,27 +237,27 @@ static const std::vector COMMANDS = { if (args[0] == "NEXT") { // SHADER NEXT PRESET → cicla presets del shader activo if (args.size() >= 2 && args[1] == "PRESET") { - if (Options::current_shader == Rendering::ShaderType::CRTPI) { + if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) { if (Options::crtpi_presets.empty()) { return "No CrtPi presets available"; } - Options::current_crtpi_preset = - (Options::current_crtpi_preset + 1) % + Options::video.shader.current_crtpi_preset = + (Options::video.shader.current_crtpi_preset + 1) % static_cast(Options::crtpi_presets.size()); Screen::get()->reloadCrtPi(); return "CrtPi preset: " + - Options::crtpi_presets[static_cast(Options::current_crtpi_preset)].name; + Options::crtpi_presets[static_cast(Options::video.shader.current_crtpi_preset)].name; } if (Options::postfx_presets.empty()) { return "No PostFX presets available"; } - Options::current_postfx_preset = - (Options::current_postfx_preset + 1) % + Options::video.shader.current_postfx_preset = + (Options::video.shader.current_postfx_preset + 1) % static_cast(Options::postfx_presets.size()); Screen::get()->reloadPostFX(); return "PostFX preset: " + - Options::postfx_presets[static_cast(Options::current_postfx_preset)].name; + Options::postfx_presets[static_cast(Options::video.shader.current_postfx_preset)].name; } // SHADER NEXT → cicla entre tipos de shader (PostFX ↔ CrtPi) Screen::get()->nextShader(); return std::string("Shader: ") + - (Options::current_shader == Rendering::ShaderType::CRTPI ? "CrtPi" : "PostFX"); + (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI ? "CrtPi" : "PostFX"); } return "usage: shader [on|off|next [preset]|postfx|crtpi]"; }, @@ -373,12 +373,12 @@ static const std::vector COMMANDS = { return "Not allowed in kiosk mode"; } if (args[0] == "AUTO") { - Options::video.gpu_preferred_driver.clear(); + Options::video.gpu.preferred_driver.clear(); Options::saveToFile(); return "Driver: auto (restart)"; } if (args[0] == "NONE") { - Options::video.gpu_preferred_driver = "none"; + Options::video.gpu.preferred_driver = "none"; Options::saveToFile(); return "Driver: none (SDL fallback, restart)"; } @@ -394,7 +394,7 @@ static const std::vector COMMANDS = { if (!found) { return "Unknown driver: " + driver_lower + ". Use DRIVER LIST or NONE"; } - Options::video.gpu_preferred_driver = driver_lower; + Options::video.gpu.preferred_driver = driver_lower; Options::saveToFile(); return "Driver: " + driver_lower + " (restart)"; }, diff --git a/source/utils/defines.hpp b/source/utils/defines.hpp index 624cd6e..42b0aaf 100644 --- a/source/utils/defines.hpp +++ b/source/utils/defines.hpp @@ -6,7 +6,7 @@ namespace Texts { constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner"; constexpr const char* COPYRIGHT = "@2022 JailDesigner"; - constexpr const char* VERSION = "1.11"; // Versión por defecto + constexpr const char* VERSION = "1.12"; // Versión por defecto } // namespace Texts // Tamaño de bloque