migrat, amb ajuda de claude, a sdl3gpu (postfx i crtpi) igual que el JDD

This commit is contained in:
2026-04-03 15:08:06 +02:00
parent 3c2a5c9b37
commit 93fe17c3b2
34 changed files with 20728 additions and 3312 deletions

View File

@@ -8,16 +8,16 @@
#include <string> // Para basic_string, operator+, char_traits, to_string, string
#include <vector> // Para vector
#include "asset.hpp" // Para Asset
#include "mouse.hpp" // Para updateCursorVisibility
#include "options.hpp" // Para Video, video, Window, window
#include "param.hpp" // Para Param, param, ParamGame, ParamDebug
#include "asset.hpp" // Para Asset
#include "mouse.hpp" // Para updateCursorVisibility
#include "options.hpp" // Para Video, video, Window, window
#include "param.hpp" // Para Param, param, ParamGame, ParamDebug
#include "rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
#include "text.hpp" // Para Text
#include "texture.hpp" // Para Texture
#include "ui/logger.hpp" // Para info
#include "ui/notifier.hpp" // Para Notifier
#include "ui/service_menu.hpp" // Para ServiceMenu
#include "text.hpp" // Para Text
#include "texture.hpp" // Para Texture
#include "ui/logger.hpp" // Para info
#include "ui/notifier.hpp" // Para Notifier
#include "ui/service_menu.hpp" // Para ServiceMenu
// Singleton
Screen* Screen::instance = nullptr;
@@ -25,7 +25,7 @@ Screen* Screen::instance = nullptr;
// Inicializa la instancia única del singleton
void Screen::init() {
Screen::instance = new Screen();
Screen::initPostFX(); // Llamar aquí para que Screen::get() ya devuelva la instancia
Screen::initShaders(); // Llamar aquí para que Screen::get() ya devuelva la instancia
}
// Libera la instancia
@@ -68,7 +68,6 @@ Screen::Screen()
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
SDL_RenderClear(renderer_);
SDL_RenderPresent(renderer_);
}
// Destructor
@@ -112,13 +111,11 @@ void Screen::renderPresent() {
SDL_Surface* surface = SDL_RenderReadPixels(renderer_, nullptr);
if (surface != nullptr) {
if (surface->format == SDL_PIXELFORMAT_ARGB8888) {
std::memcpy(pixel_buffer_.data(), surface->pixels,
pixel_buffer_.size() * sizeof(Uint32));
std::memcpy(pixel_buffer_.data(), surface->pixels, pixel_buffer_.size() * sizeof(Uint32));
} else {
SDL_Surface* converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
if (converted != nullptr) {
std::memcpy(pixel_buffer_.data(), converted->pixels,
pixel_buffer_.size() * sizeof(Uint32));
std::memcpy(pixel_buffer_.data(), converted->pixels, pixel_buffer_.size() * sizeof(Uint32));
SDL_DestroySurface(converted);
}
}
@@ -256,26 +253,35 @@ void Screen::renderInfo() const {
}
}
#endif
// Inicializa PostFX (SDL3GPU)
void Screen::initPostFX() {
// Inicializa shaders (SDL3GPU)
void Screen::initShaders() {
#ifndef NO_SHADERS
auto* self = Screen::get();
if (self == nullptr) {
SDL_Log("Screen::initPostFX: instance is null, skipping");
SDL_Log("Screen::initShaders: instance is null, skipping");
return;
}
if (!self->shader_backend_) {
self->shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
const std::string FALLBACK_DRIVER = "none";
self->shader_backend_->setPreferredDriver(
Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : FALLBACK_DRIVER);
}
if (!self->shader_backend_->isHardwareAccelerated()) {
const bool ok = self->shader_backend_->init(self->window_, self->game_canvas_, "", "");
SDL_Log("Screen::initPostFX: SDL3GPUShader::init() = %s", ok ? "OK" : "FAILED");
SDL_Log("Screen::initShaders: SDL3GPUShader::init() = %s", ok ? "OK" : "FAILED");
}
if (self->shader_backend_ && self->shader_backend_->isHardwareAccelerated()) {
self->shader_backend_->setLinearUpscale(Options::video.supersampling.linear_upscale);
self->shader_backend_->setDownscaleAlgo(Options::video.supersampling.downscale_algo);
self->shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1);
self->shader_backend_->setActiveShader(Options::video.shader.current_shader);
}
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
self->applyCurrentCrtPiPreset();
} else {
self->applyCurrentPostFXPreset();
}
SDL_Log("Screen::initPostFX: presets=%d current=%d postfx=%s",
static_cast<int>(Options::postfx_presets.size()),
Options::current_postfx_preset,
Options::video.postfx ? "ON" : "OFF");
self->applyCurrentPostFXPreset();
#endif
}
@@ -438,11 +444,34 @@ void Screen::getDisplayInfo() {
}
}
// Alterna entre activar y desactivar los efectos PostFX
void Screen::togglePostFX() {
Options::video.postfx = !Options::video.postfx;
// Alterna activar/desactivar shaders
void Screen::toggleShaders() {
Options::video.shader.enabled = !Options::video.shader.enabled;
auto* self = Screen::get();
if (self != nullptr) {
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
self->applyCurrentCrtPiPreset();
} else {
self->applyCurrentPostFXPreset();
}
}
}
// Cambia entre PostFX y CrtPi
void Screen::nextShader() {
auto* self = Screen::get();
if (self == nullptr || !self->shader_backend_ || !self->shader_backend_->isHardwareAccelerated()) { return; }
const auto NEXT = (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX)
? Rendering::ShaderType::CRTPI
: Rendering::ShaderType::POSTFX;
Options::video.shader.current_shader = NEXT;
self->shader_backend_->setActiveShader(NEXT);
if (NEXT == Rendering::ShaderType::CRTPI) {
self->applyCurrentCrtPiPreset();
} else {
self->applyCurrentPostFXPreset();
}
}
@@ -450,49 +479,87 @@ void Screen::togglePostFX() {
// Avanza al siguiente preset PostFX
void Screen::nextPostFXPreset() {
if (Options::postfx_presets.empty()) { return; }
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
Options::video.shader.current_postfx_preset = (Options::video.shader.current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
auto* self = Screen::get();
if (self != nullptr) {
self->applyCurrentPostFXPreset();
}
}
// Alterna entre activar y desactivar el supersampling 3x
// Avanza al siguiente preset CrtPi
void Screen::nextCrtPiPreset() {
if (Options::crtpi_presets.empty()) { return; }
Options::video.shader.current_crtpi_preset = (Options::video.shader.current_crtpi_preset + 1) % static_cast<int>(Options::crtpi_presets.size());
auto* self = Screen::get();
if (self != nullptr) {
self->applyCurrentCrtPiPreset();
}
}
// Alterna supersampling
void Screen::toggleSupersampling() {
Options::video.supersampling = (Options::video.supersampling % 3) + 1;
Options::video.supersampling.enabled = !Options::video.supersampling.enabled;
auto* self = Screen::get();
if (self != nullptr && self->shader_backend_ && self->shader_backend_->isHardwareAccelerated()) {
self->applyCurrentPostFXPreset();
self->shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1);
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
self->applyCurrentCrtPiPreset();
} else {
self->applyCurrentPostFXPreset();
}
}
}
// Aplica el preset PostFX activo al backend
void Screen::applyCurrentPostFXPreset() {
if (!shader_backend_) { return; }
// setOversample PRIMERO: puede recrear texturas antes de que setPostFXParams
// decida si hornear scanlines en CPU o aplicarlas en GPU.
shader_backend_->setOversample(Options::video.supersampling);
shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1);
Rendering::PostFXParams p{};
if (Options::video.postfx && !Options::postfx_presets.empty()) {
const auto& preset = Options::postfx_presets.at(static_cast<size_t>(Options::current_postfx_preset));
p.vignette = preset.vignette;
if (Options::video.shader.enabled && !Options::postfx_presets.empty()) {
const auto& preset = Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset));
p.vignette = preset.vignette;
p.scanlines = preset.scanlines;
p.chroma = preset.chroma;
p.mask = preset.mask;
p.gamma = preset.gamma;
p.chroma = preset.chroma;
p.mask = preset.mask;
p.gamma = preset.gamma;
p.curvature = preset.curvature;
p.bleeding = preset.bleeding;
p.flicker = preset.flicker;
SDL_Log("Screen::applyCurrentPostFXPreset: preset='%s' scan=%.2f vign=%.2f chroma=%.2f ss=%d×",
preset.name.c_str(), p.scanlines, p.vignette, p.chroma, Options::video.supersampling);
} else {
SDL_Log("Screen::applyCurrentPostFXPreset: PostFX=%s presets=%d → passthrough",
Options::video.postfx ? "ON" : "OFF",
static_cast<int>(Options::postfx_presets.size()));
p.bleeding = preset.bleeding;
p.flicker = preset.flicker;
SDL_Log("Screen::applyCurrentPostFXPreset: preset='%s' scan=%.2f vign=%.2f chroma=%.2f",
preset.name.c_str(),
p.scanlines,
p.vignette,
p.chroma);
}
shader_backend_->setPostFXParams(p);
}
// Aplica el preset CrtPi activo al backend
void Screen::applyCurrentCrtPiPreset() {
if (!shader_backend_) { return; }
if (Options::video.shader.enabled && !Options::crtpi_presets.empty()) {
const auto& preset = Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset));
Rendering::CrtPiParams p{
.scanline_weight = preset.scanline_weight,
.scanline_gap_brightness = preset.scanline_gap_brightness,
.bloom_factor = preset.bloom_factor,
.input_gamma = preset.input_gamma,
.output_gamma = preset.output_gamma,
.mask_brightness = preset.mask_brightness,
.curvature_x = preset.curvature_x,
.curvature_y = preset.curvature_y,
.mask_type = preset.mask_type,
.enable_scanlines = preset.enable_scanlines,
.enable_multisample = preset.enable_multisample,
.enable_gamma = preset.enable_gamma,
.enable_curvature = preset.enable_curvature,
.enable_sharper = preset.enable_sharper,
};
shader_backend_->setCrtPiParams(p);
SDL_Log("Screen::applyCurrentCrtPiPreset: preset='%s'", preset.name.c_str());
}
}
// Alterna entre activar y desactivar el escalado entero
void Screen::toggleIntegerScale() {
Options::video.integer_scale = !Options::video.integer_scale;