diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp new file mode 100644 index 0000000..074a7e9 --- /dev/null +++ b/source/core/input/global_inputs.cpp @@ -0,0 +1,42 @@ +#include "core/input/global_inputs.hpp" + +#include "core/input/input.h" +#include "core/rendering/screen.h" + +namespace GlobalInputs { + + auto handle(Screen *screen, Input *input) -> bool { + if (screen == nullptr || input == nullptr) { return false; } + + if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { + screen->toggleVideoMode(); + return true; + } + if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { + screen->decWindowZoom(); + return true; + } + if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { + screen->incWindowZoom(); + return true; + } + if (input->checkInput(input_prev_preset, REPEAT_FALSE)) { + screen->prevPreset(); + return true; + } + if (input->checkInput(input_next_preset, REPEAT_FALSE)) { + screen->nextPreset(); + return true; + } + if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { + screen->toggleShaderEnabled(); + return true; + } + if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { + screen->toggleActiveShader(); + return true; + } + return false; + } + +} // namespace GlobalInputs diff --git a/source/core/input/global_inputs.hpp b/source/core/input/global_inputs.hpp new file mode 100644 index 0000000..a78a7a1 --- /dev/null +++ b/source/core/input/global_inputs.hpp @@ -0,0 +1,13 @@ +#pragma once + +class Input; +class Screen; + +namespace GlobalInputs { + // Gestiona els atalls globals disponibles en qualsevol escena: zoom de + // finestra (F1/F2), fullscreen (F3), presets de shader (F8/F9), toggle + // shader (F10) i tipus de shader POSTFX↔CRTPI (F11). Retorna true si ha + // consumit alguna tecla (per si la capa cridant vol suprimir-la del + // processament específic de l'escena). + auto handle(Screen *screen, Input *input) -> bool; +} // namespace GlobalInputs diff --git a/source/core/input/input.h b/source/core/input/input.h index b9d00d0..47498b9 100644 --- a/source/core/input/input.h +++ b/source/core/input/input.h @@ -35,7 +35,8 @@ enum inputs_e { input_window_dec_size, // GPU / shaders (hotkeys provisionales hasta que haya menú de opciones) - input_toggle_gpu, + input_prev_preset, + input_next_preset, input_toggle_shader, input_toggle_shader_type, diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 63426ab..7aaad23 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -452,7 +452,7 @@ void Screen::registerEmscriptenEventCallbacks() { // ============================================================================ #ifndef NO_SHADERS -// Aplica al backend el preset del shader actiu segons options. +// Aplica al backend el shader actiu + els seus presets PostFX i CrtPi. // Només s'ha de cridar quan `videoShaderEnabled=true` (en cas contrari el // blit() ja força POSTFX+zero params per a desactivar els efectes sense // tocar els paràmetres emmagatzemats). @@ -461,16 +461,8 @@ void Screen::applyShaderParams() { return; } shader_backend_->setActiveShader(Options::video.shader.current_shader); - - // Preset per defecte (carregador YAML pendent). Valors estil "CRT" de CCAE. - Rendering::PostFXParams POSTFX; - POSTFX.vignette = 0.15F; - POSTFX.scanlines = 0.7F; - POSTFX.chroma = 0.2F; - shader_backend_->setPostFXParams(POSTFX); - - // CrtPi: defaults del struct ja raonables (scanline_weight=6.0, bloom=3.5…). - shader_backend_->setCrtPiParams(Rendering::CrtPiParams{}); + applyCurrentPostFXPreset(); + applyCurrentCrtPiPreset(); } #endif @@ -491,6 +483,22 @@ void Screen::initShaders() { if (shader_backend_->isHardwareAccelerated()) { shader_backend_->setScaleMode(Options::video.integer_scale); shader_backend_->setVSync(Options::video.vsync); + + // Resol els índexs de preset a partir del nom emmagatzemat al config. + // Si el nom no existeix (preset esborrat del YAML), es queda en 0. + for (int i = 0; i < static_cast(Options::postfx_presets.size()); ++i) { + if (Options::postfx_presets[i].name == Options::video.shader.current_postfx_preset_name) { + Options::current_postfx_preset = i; + break; + } + } + for (int i = 0; i < static_cast(Options::crtpi_presets.size()); ++i) { + if (Options::crtpi_presets[i].name == Options::video.shader.current_crtpi_preset_name) { + Options::current_crtpi_preset = i; + break; + } + } + applyShaderParams(); // aplica preset del shader actiu } #endif @@ -508,22 +516,6 @@ void Screen::shutdownShaders() { #endif } -void Screen::setGpuAcceleration(bool enabled) { - if (Options::video.gpu.acceleration == enabled) { return; } - Options::video.gpu.acceleration = enabled; - // Soft toggle: el backend es manté viu (vegeu shutdownShaders). El canvi - // s'aplica al proper arrencada. S'emet una notificació perquè l'usuari - // sap que ha tocat la tecla però el canvi no és immediat. - const color_t YELLOW = {0xFF, 0xFF, 0x00}; - const color_t BLACK = {0x00, 0x00, 0x00}; - const Uint32 DUR_MS = 2500; - notify(enabled ? "GPU: ON (restart)" : "GPU: OFF (restart)", YELLOW, BLACK, DUR_MS); -} - -void Screen::toggleGpuAcceleration() { - setGpuAcceleration(!Options::video.gpu.acceleration); -} - auto Screen::isGpuAccelerated() const -> bool { #ifndef NO_SHADERS return shader_backend_ && shader_backend_->isHardwareAccelerated(); @@ -585,3 +577,137 @@ void Screen::toggleActiveShader() { : Rendering::ShaderType::POSTFX; #endif } + +// ============================================================================ +// Presets de shaders +// ============================================================================ + +void Screen::applyCurrentPostFXPreset() { +#ifndef NO_SHADERS + if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) { return; } + if (Options::postfx_presets.empty()) { return; } + if (Options::current_postfx_preset < 0 + || Options::current_postfx_preset >= static_cast(Options::postfx_presets.size())) { + Options::current_postfx_preset = 0; + } + const auto &PRESET = Options::postfx_presets[Options::current_postfx_preset]; + Rendering::PostFXParams p; + p.vignette = PRESET.vignette; + p.scanlines = PRESET.scanlines; + p.chroma = PRESET.chroma; + p.mask = PRESET.mask; + p.gamma = PRESET.gamma; + p.curvature = PRESET.curvature; + p.bleeding = PRESET.bleeding; + p.flicker = PRESET.flicker; + shader_backend_->setPostFXParams(p); +#endif +} + +void Screen::applyCurrentCrtPiPreset() { +#ifndef NO_SHADERS + if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) { return; } + if (Options::crtpi_presets.empty()) { return; } + if (Options::current_crtpi_preset < 0 + || Options::current_crtpi_preset >= static_cast(Options::crtpi_presets.size())) { + Options::current_crtpi_preset = 0; + } + const auto &PRESET = Options::crtpi_presets[Options::current_crtpi_preset]; + Rendering::CrtPiParams p; + p.scanline_weight = PRESET.scanline_weight; + p.scanline_gap_brightness = PRESET.scanline_gap_brightness; + p.bloom_factor = PRESET.bloom_factor; + p.input_gamma = PRESET.input_gamma; + p.output_gamma = PRESET.output_gamma; + p.mask_brightness = PRESET.mask_brightness; + p.curvature_x = PRESET.curvature_x; + p.curvature_y = PRESET.curvature_y; + p.mask_type = PRESET.mask_type; + p.enable_scanlines = PRESET.enable_scanlines; + p.enable_multisample = PRESET.enable_multisample; + p.enable_gamma = PRESET.enable_gamma; + p.enable_curvature = PRESET.enable_curvature; + p.enable_sharper = PRESET.enable_sharper; + shader_backend_->setCrtPiParams(p); +#endif +} + +auto Screen::getCurrentPresetName() const -> const char* { +#ifndef NO_SHADERS + if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) { return "---"; } + if (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX) { + if (Options::current_postfx_preset >= 0 + && Options::current_postfx_preset < static_cast(Options::postfx_presets.size())) { + return Options::postfx_presets[Options::current_postfx_preset].name.c_str(); + } + } else { + if (Options::current_crtpi_preset >= 0 + && Options::current_crtpi_preset < static_cast(Options::crtpi_presets.size())) { + return Options::crtpi_presets[Options::current_crtpi_preset].name.c_str(); + } + } +#endif + return "---"; +} + +auto Screen::nextPreset() -> bool { +#ifndef NO_SHADERS + if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) { return false; } + if (!Options::video.shader.enabled) { return false; } + + if (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX) { + if (Options::postfx_presets.empty()) { return false; } + const int N = static_cast(Options::postfx_presets.size()); + Options::current_postfx_preset = (Options::current_postfx_preset + 1) % N; + Options::video.shader.current_postfx_preset_name = + Options::postfx_presets[Options::current_postfx_preset].name; + applyCurrentPostFXPreset(); + } else { + if (Options::crtpi_presets.empty()) { return false; } + const int N = static_cast(Options::crtpi_presets.size()); + Options::current_crtpi_preset = (Options::current_crtpi_preset + 1) % N; + Options::video.shader.current_crtpi_preset_name = + Options::crtpi_presets[Options::current_crtpi_preset].name; + applyCurrentCrtPiPreset(); + } + + const color_t GREEN = {0x00, 0xFF, 0x80}; + const color_t BLACK = {0x00, 0x00, 0x00}; + const Uint32 DUR_MS = 1500; + notify(std::string("Preset: ") + getCurrentPresetName(), GREEN, BLACK, DUR_MS); + return true; +#else + return false; +#endif +} + +auto Screen::prevPreset() -> bool { +#ifndef NO_SHADERS + if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) { return false; } + if (!Options::video.shader.enabled) { return false; } + + if (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX) { + if (Options::postfx_presets.empty()) { return false; } + const int N = static_cast(Options::postfx_presets.size()); + Options::current_postfx_preset = (Options::current_postfx_preset - 1 + N) % N; + Options::video.shader.current_postfx_preset_name = + Options::postfx_presets[Options::current_postfx_preset].name; + applyCurrentPostFXPreset(); + } else { + if (Options::crtpi_presets.empty()) { return false; } + const int N = static_cast(Options::crtpi_presets.size()); + Options::current_crtpi_preset = (Options::current_crtpi_preset - 1 + N) % N; + Options::video.shader.current_crtpi_preset_name = + Options::crtpi_presets[Options::current_crtpi_preset].name; + applyCurrentCrtPiPreset(); + } + + const color_t GREEN = {0x00, 0xFF, 0x80}; + const color_t BLACK = {0x00, 0x00, 0x00}; + const Uint32 DUR_MS = 1500; + notify(std::string("Preset: ") + getCurrentPresetName(), GREEN, BLACK, DUR_MS); + return true; +#else + return false; +#endif +} diff --git a/source/core/rendering/screen.h b/source/core/rendering/screen.h index 5865257..f8c9cf2 100644 --- a/source/core/rendering/screen.h +++ b/source/core/rendering/screen.h @@ -63,8 +63,6 @@ class Screen { // GPU / shaders (post-procesado). En builds con NO_SHADERS (Emscripten) son no-op. void initShaders(); // Crea el backend GPU si no existe y lo inicializa void shutdownShaders(); // Libera el backend GPU - void setGpuAcceleration(bool enabled); // Crea/destruye el backend según valor, persiste options - void toggleGpuAcceleration(); // Alterna aceleración GPU auto isGpuAccelerated() const -> bool; // true si el backend existe y reporta hardware OK void setShaderEnabled(bool enabled); // Activa o desactiva el post-procesado (persiste) void toggleShaderEnabled(); // Alterna post-procesado @@ -75,6 +73,14 @@ class Screen { #endif void toggleActiveShader(); // Alterna POSTFX ↔ CRTPI + // Presets de shaders (PostFX/CrtPi). Operen sobre el shader actiu. + // Retornen false si GPU off / shaders off / llista buida (igual que a aee_plus). + auto nextPreset() -> bool; + auto prevPreset() -> bool; + auto getCurrentPresetName() const -> const char*; + void applyCurrentPostFXPreset(); // Escriu el preset PostFX actiu al backend + void applyCurrentCrtPiPreset(); // Escriu el preset CrtPi actiu al backend + private: // Helpers internos de setVideoMode void applyFullscreen(bool fullscreen); // SDL_SetWindowFullscreen + visibilidad del cursor diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 5876464..994ab21 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -64,6 +64,12 @@ Director::Director(int argc, const char *argv[]) { Options::setConfigFile(systemFolder + "/config.yaml"); Options::loadFromFile(); + // Presets de shaders (creats amb defaults si no existeixen). + Options::setPostFXFile(systemFolder + "/postfx.yaml"); + Options::loadPostFXFromFile(); + Options::setCrtPiFile(systemFolder + "/crtpi.yaml"); + Options::loadCrtPiFromFile(); + // Inicializa el sistema de recursos (pack + fallback). // En wasm siempre se usa filesystem (MEMFS) porque el propio --preload-file // de emscripten ya empaqueta data/ — no hay resources.pack. @@ -202,7 +208,8 @@ void Director::initInput() { input->bindKey(input_window_dec_size, SDL_SCANCODE_F1); input->bindKey(input_window_inc_size, SDL_SCANCODE_F2); input->bindKey(input_window_fullscreen, SDL_SCANCODE_F3); - input->bindKey(input_toggle_gpu, SDL_SCANCODE_F9); + input->bindKey(input_prev_preset, SDL_SCANCODE_F8); + input->bindKey(input_next_preset, SDL_SCANCODE_F9); input->bindKey(input_toggle_shader, SDL_SCANCODE_F10); input->bindKey(input_toggle_shader_type, SDL_SCANCODE_F11); diff --git a/source/game/game.cpp b/source/game/game.cpp index 4c5cd04..921f2c6 100644 --- a/source/game/game.cpp +++ b/source/game/game.cpp @@ -8,6 +8,7 @@ #include // for basic_ostream, char_traits, operator<< #include "core/audio/jail_audio.hpp" // for JA_PlaySound, JA_DeleteSound, JA_LoadSound +#include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for inputs_e, Input, REPEAT_TRUE, REPEAT_FALSE #include "core/locale/lang.h" // for Lang #include "core/rendering/fade.h" // for Fade, FADE_CENTER @@ -2517,30 +2518,8 @@ void Game::checkGameInput() { demo.keys.fireLeft = 0; demo.keys.fireRight = 0; - // Comprueba las teclas de cambiar el tamaño de la centana y el modo de video - if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { - screen->toggleVideoMode(); - } - - else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { - screen->decWindowZoom(); - } - - else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { - screen->incWindowZoom(); - } - - else if (input->checkInput(input_toggle_gpu, REPEAT_FALSE)) { - screen->toggleGpuAcceleration(); - } - - else if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { - screen->toggleShaderEnabled(); - } - - else if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { - screen->toggleActiveShader(); - } + // Atalls globals (zoom finestra, fullscreen, shaders, presets, ...) + GlobalInputs::handle(screen, input); // Modo Demo activo if (demo.enabled) { diff --git a/source/game/options.cpp b/source/game/options.cpp index 432fa29..9355d01 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -22,6 +22,14 @@ namespace Options { Settings settings; std::vector inputs; + std::vector postfx_presets; + std::string postfx_file_path; + int current_postfx_preset = 0; + + std::vector crtpi_presets; + std::string crtpi_file_path; + int current_crtpi_preset = 0; + // --- Helpers locals --- namespace { void parseBoolField(const fkyaml::node &node, const std::string &key, bool &target) { @@ -339,4 +347,212 @@ namespace Options { return true; } + // ======================================================================== + // Presets de shaders (postfx.yaml / crtpi.yaml) + // + // Els defaults viuen en una única font (defaultPostFXPresets / defaultCrtPiPresets). + // Generem el YAML a partir d'ells el primer cop i els usem també com a + // fallback si el YAML és absent o corrupte. Si algú toca els valors, ho fa + // en un sol lloc. + // ======================================================================== + + namespace { + void parseFloatField(const fkyaml::node &node, const std::string &key, float &target) { + if (node.contains(key)) { + try { + target = node[key].get_value(); + } catch (...) {} + } + } + + auto defaultPostFXPresets() -> const std::vector & { + static const std::vector DEFAULTS = { + {"CRT", 0.6F, 0.7F, 0.15F, 0.6F, 0.8F}, + {"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F}, + {"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F}, + {"SCANLINES", 0.0F, 0.8F}, + {"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F}, + {"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F}, + }; + return DEFAULTS; + } + + auto defaultCrtPiPresets() -> const std::vector & { + static const std::vector DEFAULTS = { + {"Default", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false}, + {"Curved", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false}, + {"Sharp", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true}, + {"Minimal", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false}, + }; + return DEFAULTS; + } + + void writePostFXDefaults(std::ostream &out) { + out << "# Coffee Crisis - PostFX Shader Presets\n\n"; + out << "presets:\n"; + for (const auto &p : defaultPostFXPresets()) { + out << " - name: \"" << p.name << "\"\n"; + out << " vignette: " << p.vignette << "\n"; + out << " scanlines: " << p.scanlines << "\n"; + out << " chroma: " << p.chroma << "\n"; + out << " mask: " << p.mask << "\n"; + out << " gamma: " << p.gamma << "\n"; + out << " curvature: " << p.curvature << "\n"; + out << " bleeding: " << p.bleeding << "\n"; + out << " flicker: " << p.flicker << "\n"; + } + } + + void writeCrtPiDefaults(std::ostream &out) { + out << "# Coffee Crisis - CrtPi Shader Presets\n\n"; + out << "presets:\n"; + for (const auto &p : defaultCrtPiPresets()) { + out << " - name: \"" << p.name << "\"\n"; + out << " scanline_weight: " << p.scanline_weight << "\n"; + out << " scanline_gap_brightness: " << p.scanline_gap_brightness << "\n"; + out << " bloom_factor: " << p.bloom_factor << "\n"; + out << " input_gamma: " << p.input_gamma << "\n"; + out << " output_gamma: " << p.output_gamma << "\n"; + out << " mask_brightness: " << p.mask_brightness << "\n"; + out << " curvature_x: " << p.curvature_x << "\n"; + out << " curvature_y: " << p.curvature_y << "\n"; + out << " mask_type: " << p.mask_type << "\n"; + out << " enable_scanlines: " << boolToString(p.enable_scanlines) << "\n"; + out << " enable_multisample: " << boolToString(p.enable_multisample) << "\n"; + out << " enable_gamma: " << boolToString(p.enable_gamma) << "\n"; + out << " enable_curvature: " << boolToString(p.enable_curvature) << "\n"; + out << " enable_sharper: " << boolToString(p.enable_sharper) << "\n"; + } + } + } // namespace + + void setPostFXFile(const std::string &path) { + postfx_file_path = path; + } + + auto loadPostFXFromFile() -> bool { + postfx_presets.clear(); + current_postfx_preset = 0; + + std::ifstream file(postfx_file_path); + if (!file.is_open()) { + // No existeix: escriu el YAML a partir dels defaults i copia'ls a memòria. + std::ofstream out(postfx_file_path); + if (out.is_open()) { + writePostFXDefaults(out); + out.close(); + } + postfx_presets = defaultPostFXPresets(); + return true; + } + + const std::string CONTENT((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + file.close(); + + try { + auto yaml = fkyaml::node::deserialize(CONTENT); + if (yaml.contains("presets")) { + for (const auto &p : yaml["presets"]) { + PostFXPreset preset; + if (p.contains("name")) { + try { preset.name = p["name"].get_value(); } catch (...) {} + } + parseFloatField(p, "vignette", preset.vignette); + parseFloatField(p, "scanlines", preset.scanlines); + parseFloatField(p, "chroma", preset.chroma); + parseFloatField(p, "mask", preset.mask); + parseFloatField(p, "gamma", preset.gamma); + parseFloatField(p, "curvature", preset.curvature); + parseFloatField(p, "bleeding", preset.bleeding); + parseFloatField(p, "flicker", preset.flicker); + postfx_presets.push_back(preset); + } + } + std::cout << "PostFX loaded: " << postfx_presets.size() << " preset(s)\n"; + } catch (const fkyaml::exception &e) { + std::cout << "Error parsing PostFX YAML: " << e.what() << ". Using defaults.\n"; + postfx_presets = defaultPostFXPresets(); + return false; + } + + if (postfx_presets.empty()) { + postfx_presets = defaultPostFXPresets(); + } + return true; + } + + void setCrtPiFile(const std::string &path) { + crtpi_file_path = path; + } + + auto loadCrtPiFromFile() -> bool { + crtpi_presets.clear(); + current_crtpi_preset = 0; + + std::ifstream file(crtpi_file_path); + if (!file.is_open()) { + std::ofstream out(crtpi_file_path); + if (out.is_open()) { + writeCrtPiDefaults(out); + out.close(); + } + crtpi_presets = defaultCrtPiPresets(); + return true; + } + + const std::string CONTENT((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + file.close(); + + try { + auto yaml = fkyaml::node::deserialize(CONTENT); + if (yaml.contains("presets")) { + for (const auto &p : yaml["presets"]) { + CrtPiPreset preset; + if (p.contains("name")) { + try { preset.name = p["name"].get_value(); } catch (...) {} + } + parseFloatField(p, "scanline_weight", preset.scanline_weight); + parseFloatField(p, "scanline_gap_brightness", preset.scanline_gap_brightness); + parseFloatField(p, "bloom_factor", preset.bloom_factor); + parseFloatField(p, "input_gamma", preset.input_gamma); + parseFloatField(p, "output_gamma", preset.output_gamma); + parseFloatField(p, "mask_brightness", preset.mask_brightness); + parseFloatField(p, "curvature_x", preset.curvature_x); + parseFloatField(p, "curvature_y", preset.curvature_y); + if (p.contains("mask_type")) { + try { preset.mask_type = p["mask_type"].get_value(); } catch (...) {} + } + if (p.contains("enable_scanlines")) { + try { preset.enable_scanlines = p["enable_scanlines"].get_value(); } catch (...) {} + } + if (p.contains("enable_multisample")) { + try { preset.enable_multisample = p["enable_multisample"].get_value(); } catch (...) {} + } + if (p.contains("enable_gamma")) { + try { preset.enable_gamma = p["enable_gamma"].get_value(); } catch (...) {} + } + if (p.contains("enable_curvature")) { + try { preset.enable_curvature = p["enable_curvature"].get_value(); } catch (...) {} + } + if (p.contains("enable_sharper")) { + try { preset.enable_sharper = p["enable_sharper"].get_value(); } catch (...) {} + } + crtpi_presets.push_back(preset); + } + } + std::cout << "CrtPi loaded: " << crtpi_presets.size() << " preset(s)\n"; + } catch (const fkyaml::exception &e) { + std::cout << "Error parsing CrtPi YAML: " << e.what() << ". Using defaults.\n"; + crtpi_presets = defaultCrtPiPresets(); + return false; + } + + if (crtpi_presets.empty()) { + crtpi_presets = defaultCrtPiPresets(); + } + return true; + } + } // namespace Options diff --git a/source/game/options.hpp b/source/game/options.hpp index a162835..0e6f25d 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -88,6 +88,38 @@ namespace Options { std::string config_file; }; + // Preset PostFX + struct PostFXPreset { + std::string name; + float vignette{0.0F}; + float scanlines{0.0F}; + float chroma{0.0F}; + float mask{0.0F}; + float gamma{0.0F}; + float curvature{0.0F}; + float bleeding{0.0F}; + float flicker{0.0F}; + }; + + // Preset CrtPi + struct CrtPiPreset { + std::string name; + float scanline_weight{6.0F}; + float scanline_gap_brightness{0.12F}; + float bloom_factor{3.5F}; + float input_gamma{2.4F}; + float output_gamma{2.2F}; + float mask_brightness{0.80F}; + float curvature_x{0.05F}; + float curvature_y{0.10F}; + int mask_type{2}; + bool enable_scanlines{true}; + bool enable_multisample{true}; + bool enable_gamma{true}; + bool enable_curvature{false}; + bool enable_sharper{false}; + }; + // --- Variables globales --- extern Window window; extern Video video; @@ -96,10 +128,26 @@ namespace Options { extern Settings settings; extern std::vector inputs; // [0]=KEYBOARD, [1]=GAMECONTROLLER per defecte + // Presets de shaders (carregats de postfx.yaml / crtpi.yaml al config folder) + extern std::vector postfx_presets; + extern std::string postfx_file_path; + extern int current_postfx_preset; // Índex dins `postfx_presets` + + extern std::vector crtpi_presets; + extern std::string crtpi_file_path; + extern int current_crtpi_preset; // Índex dins `crtpi_presets` + // --- Funciones --- void init(); // Reinicia a defaults i omple `inputs` void setConfigFile(const std::string &file_path); // Ruta del config.yaml auto loadFromFile() -> bool; // Carrega el YAML; si no existeix, crea'l amb defaults auto saveToFile() -> bool; // Guarda el YAML + // Presets de shaders. Si el fitxer no existeix, l'escriu amb els defaults + // i deixa els presets carregats en memòria. + void setPostFXFile(const std::string &path); + auto loadPostFXFromFile() -> bool; + void setCrtPiFile(const std::string &path); + auto loadCrtPiFromFile() -> bool; + } // namespace Options diff --git a/source/game/scenes/instructions.cpp b/source/game/scenes/instructions.cpp index bc61938..da7efe4 100644 --- a/source/game/scenes/instructions.cpp +++ b/source/game/scenes/instructions.cpp @@ -6,8 +6,9 @@ #include // for char_traits, basic_ostream, operator<< #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic -#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e +#include "core/audio/jail_audio.hpp" // for JA_StopMusic +#include "core/input/global_inputs.hpp" // for GlobalInputs::handle +#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/locale/lang.h" // for Lang #include "core/rendering/screen.h" // for Screen #include "core/rendering/sprite.h" // for Sprite @@ -218,33 +219,12 @@ void Instructions::checkInput() { if (input->checkInput(input_exit, REPEAT_FALSE)) { quitRequested = true; finished = true; - } else + return; + } #endif - if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { - screen->toggleVideoMode(); - } + if (GlobalInputs::handle(screen, input)) { return; } - else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { - screen->decWindowZoom(); - } - - else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { - screen->incWindowZoom(); - } - - else if (input->checkInput(input_toggle_gpu, REPEAT_FALSE)) { - screen->toggleGpuAcceleration(); - } - - else if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { - screen->toggleShaderEnabled(); - } - - else if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { - screen->toggleActiveShader(); - } - - else if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { + if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { if (mode == m_auto) { finished = true; } else { diff --git a/source/game/scenes/intro.cpp b/source/game/scenes/intro.cpp index 5310de3..082eabd 100644 --- a/source/game/scenes/intro.cpp +++ b/source/game/scenes/intro.cpp @@ -4,8 +4,9 @@ #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic, JA_DeleteMusic, JA_LoadMusic -#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e +#include "core/audio/jail_audio.hpp" // for JA_StopMusic, JA_DeleteMusic, JA_LoadMusic +#include "core/input/global_inputs.hpp" // for GlobalInputs::handle +#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e #include "core/locale/lang.h" // for Lang #include "core/rendering/screen.h" // for Screen #include "core/rendering/smartsprite.h" // for SmartSprite @@ -194,33 +195,12 @@ void Intro::checkInput() { #ifndef __EMSCRIPTEN__ if (input->checkInput(input_exit, REPEAT_FALSE)) { section->name = SECTION_PROG_QUIT; - } else + return; + } #endif - if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { - screen->toggleVideoMode(); - } + if (GlobalInputs::handle(screen, input)) { return; } - else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { - screen->decWindowZoom(); - } - - else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { - screen->incWindowZoom(); - } - - else if (input->checkInput(input_toggle_gpu, REPEAT_FALSE)) { - screen->toggleGpuAcceleration(); - } - - else if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { - screen->toggleShaderEnabled(); - } - - else if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { - screen->toggleActiveShader(); - } - - else if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { + if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { JA_StopMusic(); section->name = SECTION_PROG_TITLE; section->subsection = SUBSECTION_TITLE_1; diff --git a/source/game/scenes/logo.cpp b/source/game/scenes/logo.cpp index 4056217..2fd7fdc 100644 --- a/source/game/scenes/logo.cpp +++ b/source/game/scenes/logo.cpp @@ -5,9 +5,10 @@ #include // for min #include // for basic_string -#include "core/audio/jail_audio.hpp" // for JA_StopMusic -#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e -#include "core/rendering/screen.h" // for Screen +#include "core/audio/jail_audio.hpp" // for JA_StopMusic +#include "core/input/global_inputs.hpp" // for GlobalInputs::handle +#include "core/input/input.h" // for Input, REPEAT_FALSE, inputs_e +#include "core/rendering/screen.h" // for Screen #include "core/rendering/sprite.h" // for Sprite #include "core/rendering/texture.h" // for Texture #include "core/resources/asset.h" // for Asset @@ -77,33 +78,12 @@ void Logo::checkInput() { #ifndef __EMSCRIPTEN__ if (input->checkInput(input_exit, REPEAT_FALSE)) { section->name = SECTION_PROG_QUIT; - } else + return; + } #endif - if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { - screen->toggleVideoMode(); - } + if (GlobalInputs::handle(screen, input)) { return; } - else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { - screen->decWindowZoom(); - } - - else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { - screen->incWindowZoom(); - } - - else if (input->checkInput(input_toggle_gpu, REPEAT_FALSE)) { - screen->toggleGpuAcceleration(); - } - - else if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { - screen->toggleShaderEnabled(); - } - - else if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { - screen->toggleActiveShader(); - } - - else if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { + if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE)) { section->name = SECTION_PROG_TITLE; section->subsection = SUBSECTION_TITLE_1; } diff --git a/source/game/scenes/title.cpp b/source/game/scenes/title.cpp index c0775b8..1c6e796 100644 --- a/source/game/scenes/title.cpp +++ b/source/game/scenes/title.cpp @@ -7,6 +7,7 @@ #include // for basic_string, operator+, char_traits #include "core/audio/jail_audio.hpp" // for JA_StopMusic, JA_GetMusicState, JA_Play... +#include "core/input/global_inputs.hpp" // for GlobalInputs::handle #include "core/input/input.h" // for Input, INPUT_USE_GAMECONTROLLER, INPUT_... #include "core/locale/lang.h" // for Lang, ba_BA, en_UK, es_ES #include "core/rendering/animatedsprite.h" // for AnimatedSprite @@ -643,31 +644,10 @@ void Title::checkInput() { #ifndef __EMSCRIPTEN__ if (input->checkInput(input_exit, REPEAT_FALSE)) { section->name = SECTION_PROG_QUIT; - } else + return; + } #endif - if (input->checkInput(input_window_fullscreen, REPEAT_FALSE)) { - screen->toggleVideoMode(); - } - - else if (input->checkInput(input_window_dec_size, REPEAT_FALSE)) { - screen->decWindowZoom(); - } - - else if (input->checkInput(input_window_inc_size, REPEAT_FALSE)) { - screen->incWindowZoom(); - } - - else if (input->checkInput(input_toggle_gpu, REPEAT_FALSE)) { - screen->toggleGpuAcceleration(); - } - - else if (input->checkInput(input_toggle_shader, REPEAT_FALSE)) { - screen->toggleShaderEnabled(); - } - - else if (input->checkInput(input_toggle_shader_type, REPEAT_FALSE)) { - screen->toggleActiveShader(); - } + GlobalInputs::handle(screen, input); } // Actualiza el tileado de fondo