treballant en postfx

This commit is contained in:
2026-03-21 13:31:42 +01:00
parent 8aad52f33f
commit 2b2eb31c67
11 changed files with 613 additions and 25 deletions

View File

@@ -10,7 +10,10 @@
#include <string> // Para char_traits, string, operator+, operator==
#include "core/input/mouse.hpp" // Para updateCursorVisibility
#ifndef __APPLE__
#include "core/rendering/opengl/opengl_shader.hpp" // Para OpenGLShader
#endif
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
#include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource
@@ -124,13 +127,16 @@ void Screen::start() { setRendererSurface(nullptr); }
void Screen::render() {
fps_.increment();
// Renderiza todos los overlays
// Renderiza todos los overlays (escribe en game_surface_ CPU-side)
renderOverlays();
// Copia la surface a la textura
surfaceToTexture();
// En el path SDL3GPU, los píxeles se suben directamente desde la Surface.
// En el path SDL_Renderer, primero copiamos la surface a la SDL_Texture.
if (!(Options::video.shaders && shader_backend_ && shader_backend_->isHardwareAccelerated())) {
surfaceToTexture();
}
// Copia la textura al renderizador
// Copia la textura al renderizador (o hace el present GPU)
textureToRenderer();
}
@@ -206,7 +212,12 @@ void Screen::renderNotifications() const {
// Cambia el estado de los shaders
void Screen::toggleShaders() {
Options::video.shaders = !Options::video.shaders;
initShaders();
if (!Options::video.shaders && shader_backend_) {
// Al desactivar shaders, limpiar el backend para liberar el swapchain de GPU
shader_backend_->cleanup();
} else {
initShaders();
}
}
// Actualiza la lógica de la clase (versión nueva con delta_time para escenas migradas)
@@ -304,13 +315,42 @@ void Screen::surfaceToTexture() {
}
}
// Copia la textura al renderizador
// Copia la textura al renderizador (o hace el present GPU)
void Screen::textureToRenderer() {
SDL_Texture* texture_to_render = Options::video.border.enabled ? border_texture_ : game_texture_;
if (Options::video.shaders && shader_backend_) {
if (Options::video.shaders && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
// ---- SDL3 GPU path: convertir Surface → ARGB → upload → PostFX → present ----
if (Options::video.border.enabled) {
// El border_surface_ solo tiene el color de borde; hay que componer encima el game_surface_
const int BORDER_W = static_cast<int>(border_surface_->getWidth());
const int BORDER_H = static_cast<int>(border_surface_->getHeight());
pixel_buffer_.resize(static_cast<size_t>(BORDER_W * BORDER_H));
border_surface_->toARGBBuffer(pixel_buffer_.data());
// Compositar game_surface_ en la posición correcta dentro del buffer
const int GAME_W = static_cast<int>(game_surface_->getWidth());
const int GAME_H = static_cast<int>(game_surface_->getHeight());
const int OFF_X = static_cast<int>(game_surface_dstrect_.x);
const int OFF_Y = static_cast<int>(game_surface_dstrect_.y);
std::vector<Uint32> game_pixels(static_cast<size_t>(GAME_W * GAME_H));
game_surface_->toARGBBuffer(game_pixels.data());
for (int y = 0; y < GAME_H; ++y) {
for (int x = 0; x < GAME_W; ++x) {
pixel_buffer_[static_cast<size_t>(((OFF_Y + y) * BORDER_W) + (OFF_X + x))] = game_pixels[static_cast<size_t>((y * GAME_W) + x)];
}
}
shader_backend_->uploadPixels(pixel_buffer_.data(), BORDER_W, BORDER_H);
} else {
const int GAME_W = static_cast<int>(game_surface_->getWidth());
const int GAME_H = static_cast<int>(game_surface_->getHeight());
pixel_buffer_.resize(static_cast<size_t>(GAME_W * GAME_H));
game_surface_->toARGBBuffer(pixel_buffer_.data());
shader_backend_->uploadPixels(pixel_buffer_.data(), GAME_W, GAME_H);
}
shader_backend_->render();
} else {
// ---- SDL_Renderer path (fallback / no-shader) ----
SDL_SetRenderTarget(renderer_, nullptr);
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
@@ -437,19 +477,25 @@ void Screen::loadShaders() {
// Inicializa los shaders
void Screen::initShaders() {
#ifndef __APPLE__
if (Options::video.shaders) {
loadShaders();
if (!shader_backend_) {
shader_backend_ = std::make_unique<Rendering::OpenGLShader>();
}
shader_backend_->init(window_, Options::video.border.enabled ? border_texture_ : game_texture_, vertex_shader_source_, fragment_shader_source_);
// shader_backend_->init(window_, shaders_texture_, vertex_shader_source_, fragment_shader_source_);
if (!Options::video.shaders) {
return;
}
SDL_Texture* tex = Options::video.border.enabled ? border_texture_ : game_texture_;
#ifdef __APPLE__
// macOS: usar SDL3 GPU API (Metal) via SDL3GPUShader
if (!shader_backend_) {
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
}
shader_backend_->init(window_, tex, "", "");
#else
// En macOS, OpenGL está deprecated y rinde mal
// TODO: Implementar backend de Metal para shaders en macOS
std::cout << "WARNING: Shaders no disponibles en macOS (OpenGL deprecated). Usa Metal backend.\n";
// Win/Linux: usar OpenGL + GLSL
loadShaders();
if (!shader_backend_) {
shader_backend_ = std::make_unique<Rendering::OpenGLShader>();
}
shader_backend_->init(window_, tex, vertex_shader_source_, fragment_shader_source_);
#endif
}
@@ -537,7 +583,9 @@ auto Screen::initSDLVideo() -> bool {
const auto WINDOW_WIDTH = Options::video.border.enabled ? Options::game.width + (Options::video.border.width * 2) : Options::game.width;
const auto WINDOW_HEIGHT = Options::video.border.enabled ? Options::game.height + (Options::video.border.height * 2) : Options::game.height;
#ifdef __APPLE__
SDL_WindowFlags window_flags = SDL_WINDOW_METAL;
// SDL_WINDOW_METAL no es necesario: SDL3GPU autodetecta Metal via SDL_CreateGPUDevice.
// SDL_Renderer también usará Metal si está disponible (via hint o autoselección).
SDL_WindowFlags window_flags = 0;
#elif defined(LINUX_BUILD)
// En Linux, SDL_WINDOW_OPENGL puede entrar en conflicto con el backend del renderer;
// el hint SDL_HINT_RENDER_DRIVER="opengl" es suficiente para seleccionar OpenGL.