diff --git a/CLAUDE.md b/CLAUDE.md index ce84138..df754a4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -148,7 +148,7 @@ Follows the pattern from `jaildoctors_dilemma`, persists to YAML: | F6 | Toggle supersampling | | F7 | Cycle shader type (PostFX ↔ CRT-Pi) | | F8 | Cycle shader presets | -| F9 | Toggle stretch filter (nearest ↔ linear) | +| F9 | Cycle texture filter (nearest ↔ linear) — sempre aplicat, independent de 4:3 | | F10 | Cycle render info (off → top → bottom → off) | | F11 | Toggle pause (Director skips `scene->tick()` + `JA_PauseMusic`/`JA_ResumeMusic`) | | F12 | Toggle floating options menu | @@ -225,7 +225,7 @@ JD8_Flip produces ABGR byte order: `0xFF000000 + R + (G<<8) + (B<<16)`. SDL text | File | Content | |------|---------| -| `~/.config/jailgames/aee/config.yaml` | Main config: video (incl. `vsync`, `integer_scale`), audio (incl. `enabled` master + `music_*` + `sound_*`), window, render_info (incl. `show_time`), game, shader selection, controls (només moviment del jugador) | +| `~/.config/jailgames/aee/config.yaml` | Main config: video (incl. `vsync`, `scaling_mode`, `texture_filter`), audio (incl. `enabled` master + `music_*` + `sound_*`), window, render_info (incl. `show_time`), game, shader selection, controls (només moviment del jugador) | | `~/.config/jailgames/aee/keys.yaml` | UI key overrides (només entrades que difereixen del default de [data/input/keys.yaml](data/input/keys.yaml)). Generat per `KeyConfig::saveOverrides()` | | `~/.config/jailgames/aee/postfx.yaml` | PostFX shader presets (6 defaults: CRT, NTSC, CURVED, SCANLINES, SUBTLE, CRT LIVE) | | `~/.config/jailgames/aee/crtpi.yaml` | CRT-Pi shader presets (4 defaults: DEFAULT, CURVED, SHARP, MINIMAL) | diff --git a/data/input/keys.yaml b/data/input/keys.yaml index ac201d5..fb7cdfc 100644 --- a/data/input/keys.yaml +++ b/data/input/keys.yaml @@ -36,9 +36,9 @@ keys: - id: next_shader_preset code: "F8" desc: "Pròxim preset del shader" - - id: toggle_stretch_filter + - id: cycle_texture_filter code: "F9" - desc: "Filtre 4:3 (nearest / linear)" + desc: "Filtre de textura (nearest / linear)" - id: toggle_render_info code: "F10" desc: "Mostra info de renderitzat" diff --git a/data/locale/ca.yaml b/data/locale/ca.yaml index 99d92fb..8bdb1ff 100644 --- a/data/locale/ca.yaml +++ b/data/locale/ca.yaml @@ -23,10 +23,10 @@ menu: aspect_4_3: "Aspecte 4:3" supersampling: "Supersampling" vsync: "Vsync" - integer_scale: "Escala entera" + scaling_mode: "Escala" shader_type: "Tipus shader" preset: "Preset" - stretch_filter: "Filtre 4:3" + texture_filter: "Filtre textura" render_info: "Render info" uptime: "Temps de joc" master_enable: "Àudio" @@ -55,6 +55,11 @@ menu: press_key: "" empty: "(Buit)" unknown: "---" + scaling_disabled: "Sense escala" + scaling_stretch: "Estirada" + scaling_letterbox: "Letterbox" + scaling_overscan: "Overscan" + scaling_integer: "Entera" window: title: "© 2000 Aventures en Egipte — JailDesigner" diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index 9bcadbf..a8083a1 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -20,7 +20,7 @@ namespace GlobalInputs { static bool ss_prev = false; static bool next_shader_prev = false; static bool next_preset_prev = false; - static bool stretch_filter_prev = false; + static bool texture_filter_prev = false; static bool render_info_prev = false; auto handle() -> bool { @@ -106,14 +106,16 @@ namespace GlobalInputs { if (next_preset) consumed = true; next_preset_prev = next_preset; - // F9 — Toggle filtre d'estirament 4:3 (NEAREST ↔ LINEAR) - bool stretch_filter = JI_KeyPressed(KeyConfig::scancode("toggle_stretch_filter")); - if (stretch_filter && !stretch_filter_prev) { - Screen::get()->toggleStretchFilter(); - Overlay::showNotification(Options::video.stretch_filter_linear ? Locale::get("notifications.filter_linear") : Locale::get("notifications.filter_nearest")); + // F9 — Cicla filtre de textura (NEAREST ↔ LINEAR), sempre aplicat + bool texture_filter = JI_KeyPressed(KeyConfig::scancode("cycle_texture_filter")); + if (texture_filter && !texture_filter_prev) { + Screen::get()->cycleTextureFilter(+1); + Overlay::showNotification(Options::video.texture_filter == Options::TextureFilter::LINEAR + ? Locale::get("notifications.filter_linear") + : Locale::get("notifications.filter_nearest")); } - if (stretch_filter) consumed = true; - stretch_filter_prev = stretch_filter; + if (texture_filter) consumed = true; + texture_filter_prev = texture_filter; // F10 — Toggle render info (FPS, driver, shader) bool render_info = JI_KeyPressed(KeyConfig::scancode("toggle_render_info")); diff --git a/source/core/rendering/menu.cpp b/source/core/rendering/menu.cpp index e028fa5..bb2a8cb 100644 --- a/source/core/rendering/menu.cpp +++ b/source/core/rendering/menu.cpp @@ -151,9 +151,20 @@ namespace Menu { p.items.push_back({Locale::get("menu.items.vsync"), ItemKind::Toggle, [] { return onOff(Options::video.vsync); }, [](int) { Screen::get()->toggleVSync(); }, nullptr, nullptr, nullptr}); - p.items.push_back({Locale::get("menu.items.integer_scale"), ItemKind::Toggle, [] { return onOff(Options::video.integer_scale); }, [](int) { Screen::get()->toggleIntegerScale(); }, nullptr, nullptr, nullptr}); + p.items.push_back({Locale::get("menu.items.scaling_mode"), ItemKind::Cycle, [] { + switch (Options::video.scaling_mode) { + case Options::ScalingMode::DISABLED: return std::string(Locale::get("menu.values.scaling_disabled")); + case Options::ScalingMode::STRETCH: return std::string(Locale::get("menu.values.scaling_stretch")); + case Options::ScalingMode::LETTERBOX: return std::string(Locale::get("menu.values.scaling_letterbox")); + case Options::ScalingMode::OVERSCAN: return std::string(Locale::get("menu.values.scaling_overscan")); + case Options::ScalingMode::INTEGER: return std::string(Locale::get("menu.values.scaling_integer")); + } + return std::string(Locale::get("menu.values.scaling_integer")); }, [](int dir) { Screen::get()->cycleScalingMode(dir); }, nullptr, nullptr, nullptr}); - p.items.push_back({Locale::get("menu.items.stretch_filter"), ItemKind::Toggle, [] { return std::string(Options::video.stretch_filter_linear ? Locale::get("menu.values.linear") : Locale::get("menu.values.nearest")); }, [](int) { Screen::get()->toggleStretchFilter(); }, nullptr, nullptr, nullptr}); + p.items.push_back({Locale::get("menu.items.texture_filter"), ItemKind::Cycle, [] { + return std::string(Options::video.texture_filter == Options::TextureFilter::LINEAR + ? Locale::get("menu.values.linear") + : Locale::get("menu.values.nearest")); }, [](int dir) { Screen::get()->cycleTextureFilter(dir); }, nullptr, nullptr, nullptr}); // Bloc shaders: no disponible a WASM (NO_SHADERS, sense SDL3 GPU a WebGL2) #ifndef __EMSCRIPTEN__ diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 5e12249..88a2d3a 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -98,11 +98,10 @@ void Screen::initShaders() { std::cout << "GPU driver: " << gpu_driver_ << '\n'; // Aplica opcions de vídeo - shader_backend_->setScaleMode(Options::video.integer_scale); + shader_backend_->setScalingMode(Options::video.scaling_mode); shader_backend_->setVSync(Options::video.vsync); - shader_backend_->setStretchFilter(Options::video.stretch_filter_linear); + shader_backend_->setTextureFilter(Options::video.texture_filter); shader_backend_->setStretch4_3(Options::video.aspect_ratio_4_3); - shader_backend_->setLinearUpscale(Options::video.linear_upscale); shader_backend_->setDownscaleAlgo(Options::video.downscale_algo); if (Options::video.supersampling) { @@ -211,10 +210,14 @@ void Screen::toggleAspectRatio() { } } -void Screen::toggleIntegerScale() { - Options::video.integer_scale = !Options::video.integer_scale; +void Screen::cycleScalingMode(int dir) { + constexpr int N = 5; // DISABLED, STRETCH, LETTERBOX, OVERSCAN, INTEGER + int cur = static_cast(Options::video.scaling_mode); + int step = (dir >= 0) ? 1 : -1; + cur = ((cur + step) % N + N) % N; + Options::video.scaling_mode = static_cast(cur); if (shader_backend_) { - shader_backend_->setScaleMode(Options::video.integer_scale); + shader_backend_->setScalingMode(Options::video.scaling_mode); } else { applyFallbackPresentation(); } @@ -227,10 +230,15 @@ void Screen::toggleVSync() { } } -void Screen::toggleStretchFilter() { - Options::video.stretch_filter_linear = !Options::video.stretch_filter_linear; +void Screen::cycleTextureFilter(int dir) { + // NEAREST <-> LINEAR (només 2 valors, dir no importa més enllà de canviar) + (void)dir; + Options::video.texture_filter = + (Options::video.texture_filter == Options::TextureFilter::LINEAR) + ? Options::TextureFilter::NEAREST + : Options::TextureFilter::LINEAR; if (shader_backend_) { - shader_backend_->setStretchFilter(Options::video.stretch_filter_linear); + shader_backend_->setTextureFilter(Options::video.texture_filter); } else { applyFallbackPresentation(); } @@ -389,22 +397,27 @@ void Screen::updateRenderInfo() { } void Screen::applyFallbackPresentation() { - // Fallback SDL_Renderer (p.ex. emscripten/WebGL2 sense shaders GPU): tria - // el mode de presentació lògica segons 4:3 i integer_scale, i aplica el - // filtre de la textura segons stretch_filter_linear. Sense açò, el path - // fallback mostrava sempre LETTERBOX i ignorava les tres flags. - SDL_ScaleMode scale = Options::video.stretch_filter_linear ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST; + // Fallback SDL_Renderer (p.ex. emscripten/WebGL2 sense shaders GPU). + // Filtre global (texture_filter) s'aplica sempre, independent de 4:3. + SDL_ScaleMode scale = (Options::video.texture_filter == Options::TextureFilter::LINEAR) + ? SDL_SCALEMODE_LINEAR + : SDL_SCALEMODE_NEAREST; if (texture_) SDL_SetTextureScaleMode(texture_, scale); - SDL_RendererLogicalPresentation mode; + // Si 4:3 actiu, la finestra ja té aspect 4:3 (alçada × 1.2); STRETCH és + // l'única opció viable al path fallback (el GPU path fa l'upscale 4:3 abans + // d'escollir el mode de finestra; en fallback no tenim eixa capa intermèdia). + SDL_RendererLogicalPresentation mode = SDL_LOGICAL_PRESENTATION_LETTERBOX; if (Options::video.aspect_ratio_4_3) { - // La finestra ja té aspect 4:3 (alçada × 1.2); STRETCH estira la - // textura 320×200 fins a omplir-la exactament. mode = SDL_LOGICAL_PRESENTATION_STRETCH; - } else if (Options::video.integer_scale) { - mode = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; } else { - mode = SDL_LOGICAL_PRESENTATION_LETTERBOX; + switch (Options::video.scaling_mode) { + case Options::ScalingMode::DISABLED: mode = SDL_LOGICAL_PRESENTATION_DISABLED; break; + case Options::ScalingMode::STRETCH: mode = SDL_LOGICAL_PRESENTATION_STRETCH; break; + case Options::ScalingMode::LETTERBOX: mode = SDL_LOGICAL_PRESENTATION_LETTERBOX; break; + case Options::ScalingMode::OVERSCAN: mode = SDL_LOGICAL_PRESENTATION_OVERSCAN; break; + case Options::ScalingMode::INTEGER: mode = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; break; + } } SDL_SetRenderLogicalPresentation(renderer_, GAME_WIDTH, GAME_HEIGHT, mode); } diff --git a/source/core/rendering/screen.hpp b/source/core/rendering/screen.hpp index 400ce4f..e472ec3 100644 --- a/source/core/rendering/screen.hpp +++ b/source/core/rendering/screen.hpp @@ -26,9 +26,9 @@ class Screen { void toggleShaders(); void toggleSupersampling(); void toggleAspectRatio(); - void toggleIntegerScale(); + void cycleScalingMode(int dir); // Cicla DISABLED/STRETCH/LETTERBOX/OVERSCAN/INTEGER void toggleVSync(); - void toggleStretchFilter(); + void cycleTextureFilter(int dir); // Cicla NEAREST/LINEAR void nextShaderType(); // Cicla PostFX ↔ CrtPi (F7) void prevShaderType(); // Cicla al revés void nextPreset(); // Cicla presets del shader actiu (F8) diff --git a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp index 8e9811c..6e884ad 100644 --- a/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp +++ b/source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp @@ -814,7 +814,7 @@ namespace Rendering { // ---- Upscale pass: scene_texture_ → scaled_texture_ ---- // Si 4:3 actiu, l'estirament s'aplica ací directament (320x200 → W*factor × H*factor*1.2) - // El filtre per al 4:3 és configurable (stretch_filter_linear_). + // El filtre s'aplica sempre (texture_filter_linear_), independent de 4:3. // L'effective_scene/height reflecteix la textura real que veuen els shaders. // Sense SS ni stretch: scene_texture_ a game_height_. // Amb SS o stretch: scaled_texture_ a l'alçada escalada (amb o sense 4:3). @@ -827,9 +827,8 @@ namespace Rendering { upscale_target.load_op = SDL_GPU_LOADOP_DONT_CARE; upscale_target.store_op = SDL_GPU_STOREOP_STORE; - // Triar filtre: si 4:3 actiu, usar el filtre configurable per a l'estirament. - // Si no, usar el filtre d'upscale normal (linear_upscale_). - bool use_linear = stretch_4_3_ ? stretch_filter_linear_ : linear_upscale_; + // Filtre global: s'aplica sempre (ja no depèn de 4:3). + bool use_linear = texture_filter_linear_; SDL_GPURenderPass* upass = SDL_BeginGPURenderPass(cmd, &upscale_target, 1, nullptr); if (upass != nullptr) { @@ -872,16 +871,38 @@ namespace Rendering { float vy = 0.0F; float vw = 0.0F; float vh = 0.0F; - if (integer_scale_) { - const int SCALE = std::max(1, std::min(static_cast(sw) / static_cast(logical_w), static_cast(sh) / static_cast(logical_h))); - vw = logical_w * static_cast(SCALE); - vh = logical_h * static_cast(SCALE); - } else { - const float SCALE = std::min( - static_cast(sw) / logical_w, - static_cast(sh) / logical_h); - vw = logical_w * SCALE; - vh = logical_h * SCALE; + switch (scaling_mode_) { + case Options::ScalingMode::DISABLED: + // 1:1, sense escala (pot ser diminut en finestres grans) + vw = logical_w; + vh = logical_h; + break; + case Options::ScalingMode::STRETCH: + // Omple tota la finestra, escala no uniforme + vw = static_cast(sw); + vh = static_cast(sh); + break; + case Options::ScalingMode::LETTERBOX: { + const float SCALE = std::min(static_cast(sw) / logical_w, + static_cast(sh) / logical_h); + vw = logical_w * SCALE; + vh = logical_h * SCALE; + break; + } + case Options::ScalingMode::OVERSCAN: { + const float SCALE = std::max(static_cast(sw) / logical_w, + static_cast(sh) / logical_h); + vw = logical_w * SCALE; + vh = logical_h * SCALE; + break; + } + case Options::ScalingMode::INTEGER: { + const int SCALE = std::max(1, std::min(static_cast(sw) / static_cast(logical_w), + static_cast(sh) / static_cast(logical_h))); + vw = logical_w * static_cast(SCALE); + vh = logical_h * static_cast(SCALE); + break; + } } vx = std::floor((static_cast(sw) - vw) * 0.5F); vy = std::floor((static_cast(sh) - vh) * 0.5F); @@ -1193,8 +1214,8 @@ namespace Rendering { } } - void SDL3GPUShader::setScaleMode(bool integer_scale) { - integer_scale_ = integer_scale; + void SDL3GPUShader::setScalingMode(Options::ScalingMode mode) { + scaling_mode_ = mode; } void SDL3GPUShader::setStretch4_3(bool enabled) { @@ -1221,10 +1242,6 @@ namespace Rendering { } } - void SDL3GPUShader::setLinearUpscale(bool linear) { - linear_upscale_ = linear; - } - void SDL3GPUShader::setDownscaleAlgo(int algo) { downscale_algo_ = std::max(0, std::min(algo, 2)); } diff --git a/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp b/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp index e3b476c..3c201ad 100644 --- a/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp +++ b/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp @@ -96,15 +96,12 @@ namespace Rendering { // Activa/desactiva VSync en el swapchain void setVSync(bool vsync) override; - // Activa/desactiva escalado entero (integer scale) - void setScaleMode(bool integer_scale) override; + // Selecciona el mode de presentació lògica (DISABLED/STRETCH/LETTERBOX/OVERSCAN/INTEGER) + void setScalingMode(Options::ScalingMode mode) override; // Establece factor de supersampling (1 = off, 3 = 3×SS) void setOversample(int factor) override; - // Activa/desactiva interpolación LINEAR en el upscale (false = NEAREST) - void setLinearUpscale(bool linear) override; - // Selecciona algoritmo de downscale: 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3 void setDownscaleAlgo(int algo) override; @@ -123,7 +120,11 @@ namespace Rendering { // Estirament vertical 4:3 (fusionat amb l'upscale pass) void setStretch4_3(bool enabled) override; [[nodiscard]] auto isStretch4_3() const -> bool override { return stretch_4_3_; } - void setStretchFilter(bool linear) override { stretch_filter_linear_ = linear; } + + // Filtre de textura global (sempre aplicat, independent de 4:3) + void setTextureFilter(Options::TextureFilter filter) override { + texture_filter_linear_ = (filter == Options::TextureFilter::LINEAR); + } private: static auto createShaderMSL(SDL_GPUDevice* device, @@ -176,10 +177,9 @@ namespace Rendering { std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige) bool is_initialized_ = false; bool vsync_ = true; - bool integer_scale_ = false; - bool linear_upscale_ = false; // Upscale NEAREST (false) o LINEAR (true) - bool stretch_4_3_ = false; // Estirament vertical 4:3 - bool stretch_filter_linear_ = false; // Filtre per a l'estirament 4:3 (false=NEAREST, true=LINEAR) + Options::ScalingMode scaling_mode_ = Options::ScalingMode::INTEGER; + bool stretch_4_3_ = false; // Estirament vertical 4:3 + bool texture_filter_linear_ = false; // Filtre global (false=NEAREST, true=LINEAR) }; } // namespace Rendering diff --git a/source/core/rendering/shader_backend.hpp b/source/core/rendering/shader_backend.hpp index de7fe9a..36ac31f 100644 --- a/source/core/rendering/shader_backend.hpp +++ b/source/core/rendering/shader_backend.hpp @@ -5,6 +5,8 @@ #include #include +#include "game/options.hpp" + namespace Rendering { /** @brief Identificador del shader de post-procesado activo */ @@ -105,9 +107,9 @@ namespace Rendering { virtual void setVSync(bool /*vsync*/) {} /** - * @brief Activa o desactiva el escalado entero (integer scale) + * @brief Selecciona el mode d'escala de la finestra (mapeja SDL_RendererLogicalPresentation). */ - virtual void setScaleMode(bool /*integer_scale*/) {} + virtual void setScalingMode(Options::ScalingMode /*mode*/) {} /** * @brief Establece el factor de supersampling (1 = off, 3 = 3× SS) @@ -116,13 +118,6 @@ namespace Rendering { */ virtual void setOversample(int /*factor*/) {} - /** - * @brief Activa/desactiva interpolación LINEAR en el paso de upscale (SS). - * Por defecto NEAREST (false). Solo tiene efecto con supersampling activo. - */ - virtual void setLinearUpscale(bool /*linear*/) {} - [[nodiscard]] virtual auto isLinearUpscale() const -> bool { return false; } - /** * @brief Selecciona el algoritmo de downscale tras el PostFX (SS activo). * 0 = bilinear legacy (comportamiento actual, sin textura intermedia), @@ -179,9 +174,9 @@ namespace Rendering { [[nodiscard]] virtual auto isStretch4_3() const -> bool { return false; } /** - * @brief Filtre per a l'estirament 4:3 (false=NEAREST, true=LINEAR). + * @brief Filtre de textura global per a l'upscale final (sempre aplicat). */ - virtual void setStretchFilter(bool /*linear*/) {} + virtual void setTextureFilter(Options::TextureFilter /*filter*/) {} }; } // namespace Rendering diff --git a/source/game/defaults.hpp b/source/game/defaults.hpp index 0312a05..7a9b783 100644 --- a/source/game/defaults.hpp +++ b/source/game/defaults.hpp @@ -17,12 +17,10 @@ namespace Defaults::Video { constexpr bool GPU_ACCELERATION = true; constexpr bool SHADER_ENABLED = false; constexpr bool SUPERSAMPLING = false; - constexpr bool INTEGER_SCALE = true; constexpr bool VSYNC = true; - constexpr bool ASPECT_RATIO_4_3 = false; // CRT original estira 200→240 - constexpr bool STRETCH_FILTER_LINEAR = false; // Filtre per a l'estirament 4:3 (false=NEAREST) - constexpr int DOWNSCALE_ALGO = 1; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 - constexpr bool LINEAR_UPSCALE = false; + constexpr bool ASPECT_RATIO_4_3 = false; // CRT original estira 200→240 + constexpr int DOWNSCALE_ALGO = 1; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 + // TextureFilter i ScalingMode viuen a Options (requereixen #include, evitem dependència circular). } // namespace Defaults::Video namespace Defaults::Audio { diff --git a/source/game/options.cpp b/source/game/options.cpp index e8eff68..9e5b2a0 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -123,18 +123,24 @@ namespace Options { video.shader_enabled = node["shader_enabled"].get_value(); if (node.contains("supersampling")) video.supersampling = node["supersampling"].get_value(); - if (node.contains("integer_scale")) - video.integer_scale = node["integer_scale"].get_value(); + if (node.contains("scaling_mode")) { + auto s = node["scaling_mode"].get_value(); + if (s == "disabled") video.scaling_mode = ScalingMode::DISABLED; + else if (s == "stretch") video.scaling_mode = ScalingMode::STRETCH; + else if (s == "letterbox") video.scaling_mode = ScalingMode::LETTERBOX; + else if (s == "overscan") video.scaling_mode = ScalingMode::OVERSCAN; + else video.scaling_mode = ScalingMode::INTEGER; + } if (node.contains("vsync")) video.vsync = node["vsync"].get_value(); if (node.contains("aspect_ratio_4_3")) video.aspect_ratio_4_3 = node["aspect_ratio_4_3"].get_value(); - if (node.contains("stretch_filter_linear")) - video.stretch_filter_linear = node["stretch_filter_linear"].get_value(); + if (node.contains("texture_filter")) { + auto s = node["texture_filter"].get_value(); + video.texture_filter = (s == "linear") ? TextureFilter::LINEAR : TextureFilter::NEAREST; + } if (node.contains("downscale_algo")) video.downscale_algo = node["downscale_algo"].get_value(); - if (node.contains("linear_upscale")) - video.linear_upscale = node["linear_upscale"].get_value(); if (node.contains("current_shader")) video.current_shader = node["current_shader"].get_value(); if (node.contains("current_postfx_preset")) @@ -277,12 +283,21 @@ namespace Options { file << " gpu_acceleration: " << (video.gpu_acceleration ? "true" : "false") << "\n"; file << " shader_enabled: " << (video.shader_enabled ? "true" : "false") << "\n"; file << " supersampling: " << (video.supersampling ? "true" : "false") << "\n"; - file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n"; + { + const char* m = "integer"; + switch (video.scaling_mode) { + case ScalingMode::DISABLED: m = "disabled"; break; + case ScalingMode::STRETCH: m = "stretch"; break; + case ScalingMode::LETTERBOX: m = "letterbox"; break; + case ScalingMode::OVERSCAN: m = "overscan"; break; + case ScalingMode::INTEGER: m = "integer"; break; + } + file << " scaling_mode: " << m << " # disabled|stretch|letterbox|overscan|integer\n"; + } file << " vsync: " << (video.vsync ? "true" : "false") << "\n"; file << " aspect_ratio_4_3: " << (video.aspect_ratio_4_3 ? "true" : "false") << "\n"; - file << " stretch_filter_linear: " << (video.stretch_filter_linear ? "true" : "false") << " # filtre 4:3: false=nearest, true=linear\n"; + file << " texture_filter: " << (video.texture_filter == TextureFilter::LINEAR ? "linear" : "nearest") << " # nearest|linear\n"; file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n"; - file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n"; file << " current_shader: " << video.current_shader << "\n"; file << " current_postfx_preset: " << video.current_postfx_preset << "\n"; file << " current_crtpi_preset: " << video.current_crtpi_preset << "\n"; diff --git a/source/game/options.hpp b/source/game/options.hpp index a9319fb..4ce5fd5 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -23,17 +23,28 @@ namespace Options { TOP = 1, BOTTOM = 2 }; + // Filtre de textura per a l'upscale final (sempre, no només en 4:3) + enum class TextureFilter { NEAREST = 0, + LINEAR = 1 }; + + // Mode de presentació lògica (escala finestra): mapeja directament + // als valors de SDL_RendererLogicalPresentation. + enum class ScalingMode { DISABLED = 0, + STRETCH = 1, + LETTERBOX = 2, + OVERSCAN = 3, + INTEGER = 4 }; + // Opcions de vídeo struct Video { bool gpu_acceleration{Defaults::Video::GPU_ACCELERATION}; bool shader_enabled{Defaults::Video::SHADER_ENABLED}; bool supersampling{Defaults::Video::SUPERSAMPLING}; - bool integer_scale{Defaults::Video::INTEGER_SCALE}; + ScalingMode scaling_mode{ScalingMode::INTEGER}; bool vsync{Defaults::Video::VSYNC}; bool aspect_ratio_4_3{Defaults::Video::ASPECT_RATIO_4_3}; - bool stretch_filter_linear{Defaults::Video::STRETCH_FILTER_LINEAR}; + TextureFilter texture_filter{TextureFilter::NEAREST}; int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; - bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; std::string current_shader{"postfx"}; // "postfx" o "crtpi" std::string current_postfx_preset{"CRT"}; // Nom del preset PostFX actiu std::string current_crtpi_preset{"DEFAULT"}; // Nom del preset CrtPi actiu diff --git a/source/main.cpp b/source/main.cpp index 94f0aef..7b6b997 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -74,8 +74,8 @@ SDL_AppResult SDL_AppInit(void** /*appstate*/, int /*argc*/, char* /*argv*/[]) { Options::window.fullscreen = false; Options::window.zoom = 1; Options::video.aspect_ratio_4_3 = true; - Options::video.integer_scale = true; - Options::video.stretch_filter_linear = true; + Options::video.scaling_mode = Options::ScalingMode::INTEGER; + Options::video.texture_filter = Options::TextureFilter::LINEAR; #endif // Carrega textos (idioma per defecte: valencià)