afegits tots els valors d'escala que dona sdl3

This commit is contained in:
2026-04-16 19:15:35 +02:00
parent a3fc1119ae
commit 52431adb0e
14 changed files with 165 additions and 98 deletions

View File

@@ -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"));

View File

@@ -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__

View File

@@ -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<int>(Options::video.scaling_mode);
int step = (dir >= 0) ? 1 : -1;
cur = ((cur + step) % N + N) % N;
Options::video.scaling_mode = static_cast<Options::ScalingMode>(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);
}

View File

@@ -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)

View File

@@ -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<int>(sw) / static_cast<int>(logical_w), static_cast<int>(sh) / static_cast<int>(logical_h)));
vw = logical_w * static_cast<float>(SCALE);
vh = logical_h * static_cast<float>(SCALE);
} else {
const float SCALE = std::min(
static_cast<float>(sw) / logical_w,
static_cast<float>(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<float>(sw);
vh = static_cast<float>(sh);
break;
case Options::ScalingMode::LETTERBOX: {
const float SCALE = std::min(static_cast<float>(sw) / logical_w,
static_cast<float>(sh) / logical_h);
vw = logical_w * SCALE;
vh = logical_h * SCALE;
break;
}
case Options::ScalingMode::OVERSCAN: {
const float SCALE = std::max(static_cast<float>(sw) / logical_w,
static_cast<float>(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<int>(sw) / static_cast<int>(logical_w),
static_cast<int>(sh) / static_cast<int>(logical_h)));
vw = logical_w * static_cast<float>(SCALE);
vh = logical_h * static_cast<float>(SCALE);
break;
}
}
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
vy = std::floor((static_cast<float>(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));
}

View File

@@ -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

View File

@@ -5,6 +5,8 @@
#include <string>
#include <utility>
#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