filtre nearest o linear per al pipeline sdl

This commit is contained in:
2026-04-15 11:10:00 +02:00
parent 5ef278ce70
commit 8bab2da2ed
6 changed files with 69 additions and 8 deletions

View File

@@ -86,6 +86,7 @@
"[SERVICE_MENU] SUPERSAMPLING": "Supermostreig", "[SERVICE_MENU] SUPERSAMPLING": "Supermostreig",
"[SERVICE_MENU] VSYNC": "Sincronisme vertical", "[SERVICE_MENU] VSYNC": "Sincronisme vertical",
"[SERVICE_MENU] INTEGER_SCALE": "Escalat sencer", "[SERVICE_MENU] INTEGER_SCALE": "Escalat sencer",
"[SERVICE_MENU] FILTER": "Filtre",
"[SERVICE_MENU] MAIN_VOLUME": "Volumen general", "[SERVICE_MENU] MAIN_VOLUME": "Volumen general",
"[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica", "[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica",
"[SERVICE_MENU] SFX_VOLUME": "Volumen dels sons", "[SERVICE_MENU] SFX_VOLUME": "Volumen dels sons",

View File

@@ -85,6 +85,7 @@
"[SERVICE_MENU] SUPERSAMPLING": "Supersampling", "[SERVICE_MENU] SUPERSAMPLING": "Supersampling",
"[SERVICE_MENU] VSYNC": "V-Sync", "[SERVICE_MENU] VSYNC": "V-Sync",
"[SERVICE_MENU] INTEGER_SCALE": "Integer Scale", "[SERVICE_MENU] INTEGER_SCALE": "Integer Scale",
"[SERVICE_MENU] FILTER": "Filter",
"[SERVICE_MENU] MAIN_VOLUME": "Main Volume", "[SERVICE_MENU] MAIN_VOLUME": "Main Volume",
"[SERVICE_MENU] MUSIC_VOLUME": "Music Volume", "[SERVICE_MENU] MUSIC_VOLUME": "Music Volume",
"[SERVICE_MENU] SFX_VOLUME": "Sound Volume", "[SERVICE_MENU] SFX_VOLUME": "Sound Volume",

View File

@@ -85,6 +85,7 @@
"[SERVICE_MENU] SUPERSAMPLING": "Supersampling", "[SERVICE_MENU] SUPERSAMPLING": "Supersampling",
"[SERVICE_MENU] VSYNC": "Sincronismo vertical", "[SERVICE_MENU] VSYNC": "Sincronismo vertical",
"[SERVICE_MENU] INTEGER_SCALE": "Escalado proporcional", "[SERVICE_MENU] INTEGER_SCALE": "Escalado proporcional",
"[SERVICE_MENU] FILTER": "Filtro",
"[SERVICE_MENU] MAIN_VOLUME": "Volumen general", "[SERVICE_MENU] MAIN_VOLUME": "Volumen general",
"[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica", "[SERVICE_MENU] MUSIC_VOLUME": "Volumen de la musica",
"[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos", "[SERVICE_MENU] SFX_VOLUME": "Volumen de los efectos",

View File

@@ -94,7 +94,7 @@ Screen::Screen()
// Crea la textura de destino // Crea la textura de destino
game_canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); game_canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureScaleMode(game_canvas_, SDL_SCALEMODE_NEAREST); SDL_SetTextureScaleMode(game_canvas_, Options::video.scale_mode);
// Inicializar buffer de píxeles para SDL3GPU // Inicializar buffer de píxeles para SDL3GPU
pixel_buffer_.resize(static_cast<size_t>(param.game.width) * static_cast<size_t>(param.game.height)); pixel_buffer_.resize(static_cast<size_t>(param.game.width) * static_cast<size_t>(param.game.height));
@@ -670,6 +670,25 @@ void Screen::toggleVSync() {
} }
} }
// Aplica Options::video.scale_mode a la textura del canvas de juego
void Screen::applyFilter() {
SDL_SetTextureScaleMode(game_canvas_, Options::video.scale_mode);
}
// Alterna el modo de filtrado entre nearest y linear
void Screen::toggleFilter() {
Options::video.scale_mode = (Options::video.scale_mode == SDL_SCALEMODE_NEAREST)
? SDL_SCALEMODE_LINEAR
: SDL_SCALEMODE_NEAREST;
applyFilter();
}
// Devuelve true si el backend SDL3GPU está activo y con aceleración hardware
auto Screen::isHardwareAccelerated() -> bool {
auto* self = Screen::get();
return self != nullptr && self->shader_backend_ && self->shader_backend_->isHardwareAccelerated();
}
// Establece el estado del V-Sync // Establece el estado del V-Sync
void Screen::setVSync(bool enabled) { void Screen::setVSync(bool enabled) {
Options::video.vsync = enabled; Options::video.vsync = enabled;

View File

@@ -49,6 +49,8 @@ class Screen {
static void nextPostFXPreset(); // Avanza al siguiente preset PostFX static void nextPostFXPreset(); // Avanza al siguiente preset PostFX
static void nextCrtPiPreset(); // Avanza al siguiente preset CrtPi static void nextCrtPiPreset(); // Avanza al siguiente preset CrtPi
static void toggleSupersampling(); // Alterna supersampling static void toggleSupersampling(); // Alterna supersampling
void toggleFilter(); // Alterna SDL_SCALEMODE_NEAREST ↔ SDL_SCALEMODE_LINEAR
void applyFilter(); // Aplica Options::video.scale_mode a game_canvas_
void toggleIntegerScale(); void toggleIntegerScale();
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
void setVSync(bool enabled); // Establece el estado del V-Sync void setVSync(bool enabled); // Establece el estado del V-Sync
@@ -60,6 +62,7 @@ class Screen {
void hide() { SDL_HideWindow(window_); } // Oculta la ventana void hide() { SDL_HideWindow(window_); } // Oculta la ventana
void getSingletons(); // Obtiene los punteros a los singletones void getSingletons(); // Obtiene los punteros a los singletones
[[nodiscard]] static auto getVSync() -> bool { return Options::video.vsync; } // Obtiene el valor de V-Sync [[nodiscard]] static auto getVSync() -> bool { return Options::video.vsync; } // Obtiene el valor de V-Sync
[[nodiscard]] static auto isHardwareAccelerated() -> bool; // True si SDL3GPU está activo
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; } // Obtiene el puntero al texto de Screen [[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; } // Obtiene el puntero al texto de Screen
// --- Display Monitor getters --- // --- Display Monitor getters ---

View File

@@ -466,6 +466,24 @@ void ServiceMenu::initializeOptions() {
SettingsGroup::VIDEO, SettingsGroup::VIDEO,
&Options::video.integer_scale)); &Options::video.integer_scale));
// FILTER: Nearest / Linear (solo visible en el fallback SDL, sin GPU acelerada)
{
std::vector<std::string> filter_values = {"Nearest", "Linear"};
auto filter_getter = []() -> std::string {
return (Options::video.scale_mode == SDL_SCALEMODE_LINEAR) ? "Linear" : "Nearest";
};
auto filter_setter = [](const std::string& val) {
Options::video.scale_mode = (val == "Linear") ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST;
if (Screen::get() != nullptr) { Screen::get()->applyFilter(); }
};
options_.push_back(std::make_unique<ListOption>(
Lang::getText("[SERVICE_MENU] FILTER"),
SettingsGroup::VIDEO,
filter_values,
filter_getter,
filter_setter));
}
// AUDIO // AUDIO
options_.push_back(std::make_unique<BoolOption>( options_.push_back(std::make_unique<BoolOption>(
Lang::getText("[SERVICE_MENU] AUDIO"), Lang::getText("[SERVICE_MENU] AUDIO"),
@@ -644,26 +662,44 @@ void ServiceMenu::setHiddenOptions() {
} }
} }
// Las opciones de shader solo tienen sentido cuando SDL3GPU está activo.
// Las opciones de filtro SDL solo tienen sentido en el fallback sin GPU.
// Ambos checks son runtime para cubrir tanto builds sin shaders como fallos de inicialización.
const bool HW_ACCEL = Screen::isHardwareAccelerated();
{
auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] FILTER"));
if (option != nullptr) {
option->setHidden(HW_ACCEL);
}
}
{
auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] SHADER"));
if (option != nullptr) {
option->setHidden(!HW_ACCEL);
}
}
{ {
auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] SHADER_PRESET")); auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] SHADER_PRESET"));
if (option != nullptr) { if (option != nullptr) {
option->setHidden(!Options::video.shader.enabled); option->setHidden(!HW_ACCEL || !Options::video.shader.enabled);
} }
} }
{ {
auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] SUPERSAMPLING")); auto* option = getOptionByCaption(Lang::getText("[SERVICE_MENU] SUPERSAMPLING"));
if (option != nullptr) { if (option != nullptr) {
option->setHidden(!Options::video.shader.enabled || Options::video.shader.current_shader != Rendering::ShaderType::POSTFX); option->setHidden(!HW_ACCEL || !Options::video.shader.enabled || Options::video.shader.current_shader != Rendering::ShaderType::POSTFX);
} }
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
// En la versión web no tiene sentido exponer: shaders (build sin shaders), // En la versión web no tiene sentido exponer: permitir apagar el sistema
// permitir apagar el sistema (no aplica al navegador) ni salir del juego // (no aplica al navegador) ni salir del juego (lo gestiona el navegador).
// (lo gestiona el navegador). // SHADER ya queda oculto por el check de HW_ACCEL de arriba.
for (const auto& caption : { for (const auto& caption : {
Lang::getText("[SERVICE_MENU] SHADER"),
Lang::getText("[SERVICE_MENU] ENABLE_SHUTDOWN"), Lang::getText("[SERVICE_MENU] ENABLE_SHUTDOWN"),
Lang::getText("[SERVICE_MENU] QUIT")}) { Lang::getText("[SERVICE_MENU] QUIT")}) {
auto* option = getOptionByCaption(caption); auto* option = getOptionByCaption(caption);