#include "core/input/global_inputs.hpp" #include #include #include #include "core/input/key_config.hpp" #include "core/locale/locale.hpp" #include "core/rendering/notifier.hpp" #include "core/rendering/render_info.hpp" #include "core/rendering/screen.hpp" #include "core/system/event_buffer.hpp" #include "game/options.hpp" #include "utils/defaults.hpp" namespace GlobalInputs { namespace { // Finestra per a confirmar l'eixida amb una segona pulsació d'Escape. constexpr float EXIT_WINDOW_S = 1.5F; constexpr int MIN_ZOOM = 1; constexpr int MAX_ZOOM = 6; float exit_window_s = 0.0F; bool quit_requested = false; // Canvia uniforms i shader actiu sense recrear la finestra. void reapplyShader() { Screen::get().setActiveShader(Options::buildActiveShader()); Screen::get().applyPostFXParams(Options::buildPostFXParams()); Screen::get().applyCrtPiParams(Options::buildCrtPiParams()); } void notifyLocale(const std::string& key) { Notifier::get().notify(Locale::get().text(key)); } void onDecZoom() { if (Options::window.fullscreen) { return; } if (Options::window.zoom <= MIN_ZOOM) { return; } Options::window.zoom--; Screen::get().setWindowZoom(Options::window.zoom); Options::saveToFile(); Notifier::get().notify(Locale::get().text("input.zoom") + " x" + std::to_string(Options::window.zoom)); } void onIncZoom() { if (Options::window.fullscreen) { return; } if (Options::window.zoom >= MAX_ZOOM) { return; } Options::window.zoom++; Screen::get().setWindowZoom(Options::window.zoom); Options::saveToFile(); Notifier::get().notify(Locale::get().text("input.zoom") + " x" + std::to_string(Options::window.zoom)); } void onFullscreen() { Options::window.fullscreen = !Options::window.fullscreen; Screen::get().setFullscreen(Options::window.fullscreen); Options::saveToFile(); notifyLocale(Options::window.fullscreen ? "input.fullscreen_on" : "input.fullscreen_off"); } void onToggleVSync() { Options::video.vsync = !Options::video.vsync; Screen::get().setVSync(Options::video.vsync); Options::saveToFile(); notifyLocale(Options::video.vsync ? "input.vsync_on" : "input.vsync_off"); } void onToggleShader() { Options::video.shader.enabled = !Options::video.shader.enabled; reapplyShader(); Options::saveToFile(); notifyLocale(Options::video.shader.enabled ? "input.shader_on" : "input.shader_off"); } void onNextShader() { Options::video.shader.current_shader = (Options::video.shader.current_shader == "crtpi") ? "postfx" : "crtpi"; reapplyShader(); Options::saveToFile(); Notifier::get().notify(Locale::get().text("input.shader") + ": " + Options::video.shader.current_shader); } // Busca l'entrada actual al vector de presets i passa a la següent // (wrap-around). Si no en troba cap s'evita el canvi silenciosament. void onNextPreset() { const bool IS_CRTPI = Options::video.shader.current_shader == "crtpi"; if (IS_CRTPI) { if (Options::crtpi_presets.empty()) { return; } auto it = std::ranges::find_if(Options::crtpi_presets, [](const auto& preset) { return preset.name == Options::video.shader.current_crtpi_preset; }); std::size_t idx = (it == Options::crtpi_presets.end()) ? 0 : std::distance(Options::crtpi_presets.begin(), it); idx = (idx + 1) % Options::crtpi_presets.size(); Options::video.shader.current_crtpi_preset = Options::crtpi_presets[idx].name; } else { if (Options::postfx_presets.empty()) { return; } auto it = std::ranges::find_if(Options::postfx_presets, [](const auto& preset) { return preset.name == Options::video.shader.current_postfx_preset; }); std::size_t idx = (it == Options::postfx_presets.end()) ? 0 : std::distance(Options::postfx_presets.begin(), it); idx = (idx + 1) % Options::postfx_presets.size(); Options::video.shader.current_postfx_preset = Options::postfx_presets[idx].name; } reapplyShader(); Options::saveToFile(); const std::string& name = IS_CRTPI ? Options::video.shader.current_crtpi_preset : Options::video.shader.current_postfx_preset; Notifier::get().notify(Locale::get().text("input.preset") + ": " + name); } void onNextScalingMode() { using Mode = Defaults::ScalingMode; Options::video.scaling_mode = static_cast((static_cast(Options::video.scaling_mode) + 1) % 5); Screen::get().setScalingMode(Options::video.scaling_mode); Options::saveToFile(); const char* mode_key = nullptr; switch (Options::video.scaling_mode) { case Mode::DISABLED: mode_key = "input.scaling_disabled"; break; case Mode::STRETCH: mode_key = "input.scaling_stretch"; break; case Mode::LETTERBOX: mode_key = "input.scaling_letterbox"; break; case Mode::OVERSCAN: mode_key = "input.scaling_overscan"; break; case Mode::INTEGER: mode_key = "input.scaling_integer"; break; } notifyLocale(mode_key); } void onToggleRenderInfo() { RenderInfo::get().toggle(); } void onExit() { if (exit_window_s > 0.0F) { quit_requested = true; return; } exit_window_s = EXIT_WINDOW_S; // La notificació dura el doble de la finestra; si l'usuari no // prem una segona volta abans del timeout, es desarmarà sol. Notifier::get().notify(Locale::get().text("input.press_again_exit"), Notification::DEFAULT.text_color, Notification::DEFAULT.bg_color, static_cast(EXIT_WINDOW_S * 1000.0F)); } } // namespace void update(int delta_ms) { exit_window_s = std::max(0.0F, exit_window_s - (static_cast(delta_ms) / 1000.0F)); for (const auto& event : EventBuffer::events) { if (event.type != SDL_EVENT_KEY_DOWN) { continue; } const auto SC = event.key.scancode; if (SC == KeyConfig::get().scancode("dec_zoom")) { onDecZoom(); } else if (SC == KeyConfig::get().scancode("inc_zoom")) { onIncZoom(); } else if (SC == KeyConfig::get().scancode("fullscreen")) { onFullscreen(); } else if (SC == KeyConfig::get().scancode("toggle_shader")) { onToggleShader(); } else if (SC == KeyConfig::get().scancode("toggle_vsync")) { onToggleVSync(); } else if (SC == KeyConfig::get().scancode("next_shader")) { onNextShader(); } else if (SC == KeyConfig::get().scancode("next_preset")) { onNextPreset(); } else if (SC == KeyConfig::get().scancode("next_scaling_mode")) { onNextScalingMode(); } else if (SC == KeyConfig::get().scancode("toggle_render_info")) { onToggleRenderInfo(); } else if (SC == KeyConfig::get().scancode("exit")) { onExit(); } } } auto wantsQuit() -> bool { return quit_requested; } } // namespace GlobalInputs