llevant el soport de opengl

This commit is contained in:
2026-03-21 17:11:26 +01:00
parent aa292dcd92
commit 43a6cc2d7a
10 changed files with 13 additions and 1220 deletions

View File

@@ -1,542 +0,0 @@
#include "core/rendering/opengl/opengl_shader.hpp"
#include <SDL3/SDL.h>
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <vector>
namespace Rendering {
OpenGLShader::~OpenGLShader() {
cleanup();
}
#ifndef __APPLE__
auto OpenGLShader::initGLExtensions() -> bool {
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
glUniform1f = (PFNGLUNIFORM1FPROC)SDL_GL_GetProcAddress("glUniform1f");
glUniform2f = (PFNGLUNIFORM2FPROC)SDL_GL_GetProcAddress("glUniform2f");
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)SDL_GL_GetProcAddress("glGenVertexArrays");
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)SDL_GL_GetProcAddress("glBindVertexArray");
glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)SDL_GL_GetProcAddress("glDeleteVertexArrays");
glGenBuffers = (PFNGLGENBUFFERSPROC)SDL_GL_GetProcAddress("glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)SDL_GL_GetProcAddress("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)SDL_GL_GetProcAddress("glBufferData");
glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)SDL_GL_GetProcAddress("glDeleteBuffers");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray");
return (glCreateShader != nullptr) && (glShaderSource != nullptr) && (glCompileShader != nullptr) && (glGetShaderiv != nullptr) &&
(glGetShaderInfoLog != nullptr) && (glDeleteShader != nullptr) && (glAttachShader != nullptr) && (glCreateProgram != nullptr) &&
(glLinkProgram != nullptr) && (glValidateProgram != nullptr) && (glGetProgramiv != nullptr) && (glGetProgramInfoLog != nullptr) &&
(glUseProgram != nullptr) && (glDeleteProgram != nullptr) && (glGetUniformLocation != nullptr) &&
(glUniform1f != nullptr) && (glUniform2f != nullptr) &&
(glGenVertexArrays != nullptr) && (glBindVertexArray != nullptr) && (glDeleteVertexArrays != nullptr) &&
(glGenBuffers != nullptr) && (glBindBuffer != nullptr) && (glBufferData != nullptr) && (glDeleteBuffers != nullptr) &&
(glVertexAttribPointer != nullptr) && (glEnableVertexAttribArray != nullptr);
}
#endif
void OpenGLShader::checkGLError(const char* operation) {
GLenum error = glGetError();
if (error != GL_NO_ERROR) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error OpenGL en %s: 0x%x",
operation,
error);
}
}
auto OpenGLShader::compileShader(const std::string& source, GLenum shader_type) -> GLuint {
if (source.empty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"ERROR: El código fuente del shader está vacío");
return 0;
}
GLuint shader_id = glCreateShader(shader_type);
if (shader_id == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear shader");
checkGLError("glCreateShader");
return 0;
}
const char* sources[1] = {source.c_str()};
glShaderSource(shader_id, 1, sources, nullptr);
checkGLError("glShaderSource");
glCompileShader(shader_id);
checkGLError("glCompileShader");
// Verificar compilación
GLint compiled = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled);
if (compiled != GL_TRUE) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error en compilación del shader");
GLint log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
std::vector<char> log(log_length);
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Log de compilación: %s",
log.data());
}
glDeleteShader(shader_id);
return 0;
}
return shader_id;
}
auto OpenGLShader::linkProgram(GLuint vertex_shader, GLuint fragment_shader) -> GLuint {
GLuint program = glCreateProgram();
if (program == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error al crear programa de shaders");
return 0;
}
glAttachShader(program, vertex_shader);
checkGLError("glAttachShader(vertex)");
glAttachShader(program, fragment_shader);
checkGLError("glAttachShader(fragment)");
glLinkProgram(program);
checkGLError("glLinkProgram");
// Verificar enlace
GLint linked = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (linked != GL_TRUE) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error al enlazar programa");
GLint log_length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
std::vector<char> log(log_length);
glGetProgramInfoLog(program, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Log de enlace: %s",
log.data());
}
glDeleteProgram(program);
return 0;
}
glValidateProgram(program);
checkGLError("glValidateProgram");
return program;
}
void OpenGLShader::createQuadGeometry() {
// Datos del quad: posición (x, y) + coordenadas de textura (u, v)
// Formato: x, y, u, v
float vertices[] = {
// Posición // TexCoords
-1.0F,
-1.0F,
0.0F,
0.0F, // Inferior izquierda
1.0F,
-1.0F,
1.0F,
0.0F, // Inferior derecha
1.0F,
1.0F,
1.0F,
1.0F, // Superior derecha
-1.0F,
1.0F,
0.0F,
1.0F // Superior izquierda
};
// Índices para dibujar el quad con dos triángulos
unsigned int indices[] = {
0,
1,
2, // Primer triángulo
2,
3,
0 // Segundo triángulo
};
// Generar y configurar VAO
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
checkGLError("glBindVertexArray");
// Generar y configurar VBO
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
checkGLError("glBufferData(VBO)");
// Generar y configurar EBO
glGenBuffers(1, &ebo_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
checkGLError("glBufferData(EBO)");
// Atributo 0: Posición (2 floats)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)nullptr);
glEnableVertexAttribArray(0);
checkGLError("glVertexAttribPointer(position)");
// Atributo 1: Coordenadas de textura (2 floats)
// NOLINTNEXTLINE(performance-no-int-to-ptr) - OpenGL uses pointer as buffer offset
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast<void*>(static_cast<uintptr_t>(2 * sizeof(float))));
glEnableVertexAttribArray(1);
checkGLError("glVertexAttribPointer(texcoord)");
// Desvincular
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
auto OpenGLShader::getTextureID(SDL_Texture* texture) -> GLuint {
if (texture == nullptr) {
return 1;
}
SDL_PropertiesID props = SDL_GetTextureProperties(texture);
GLuint texture_id = 0;
// Intentar obtener ID de textura OpenGL
texture_id = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
if (texture_id == 0) {
texture_id = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
}
if (texture_id == 0) {
texture_id = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", 1);
}
if (texture_id == 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener ID de textura OpenGL, usando 1 por defecto");
texture_id = 1;
}
return texture_id;
}
auto OpenGLShader::init(SDL_Window* window,
SDL_Texture* texture,
const std::string& vertex_source,
const std::string& fragment_source) -> bool {
window_ = window;
back_buffer_ = texture;
renderer_ = SDL_GetRenderer(window);
if (renderer_ == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error: No se pudo obtener el renderer");
return false;
}
// Obtener tamaños
SDL_GetWindowSize(window_, &window_width_, &window_height_);
SDL_GetTextureSize(back_buffer_, &texture_width_, &texture_height_);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"Initializing shaders: window=%dx%d, texture=%.0fx%.0f",
window_width_,
window_height_,
texture_width_,
texture_height_);
// Verificar que es OpenGL
const char* renderer_name = SDL_GetRendererName(renderer_);
if ((renderer_name == nullptr) || strncmp(renderer_name, "opengl", 6) != 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Renderer is not OpenGL: %s",
(renderer_name != nullptr) ? renderer_name : "unknown");
return false;
}
#ifndef __APPLE__
// Inicializar extensiones OpenGL en Windows/Linux
if (!initGLExtensions()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to initialize OpenGL extensions");
return false;
}
#endif
// Limpiar shader anterior si existe
if (program_id_ != 0) {
glDeleteProgram(program_id_);
program_id_ = 0;
}
// Compilar shaders
GLuint vertex_shader = compileShader(vertex_source, GL_VERTEX_SHADER);
GLuint fragment_shader = compileShader(fragment_source, GL_FRAGMENT_SHADER);
if (vertex_shader == 0 || fragment_shader == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to compile shaders");
if (vertex_shader != 0) {
glDeleteShader(vertex_shader);
}
if (fragment_shader != 0) {
glDeleteShader(fragment_shader);
}
return false;
}
// Enlazar programa
program_id_ = linkProgram(vertex_shader, fragment_shader);
// Limpiar shaders (ya no necesarios tras el enlace)
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
if (program_id_ == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create shader program");
return false;
}
// Crear geometría del quad
createQuadGeometry();
// Obtener ubicaciones de uniforms y configurar valores iniciales
glUseProgram(program_id_);
texture_size_location_ = glGetUniformLocation(program_id_, "TextureSize");
if (texture_size_location_ != -1) {
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"Configuring TextureSize uniform: %.0fx%.0f",
texture_width_,
texture_height_);
glUniform2f(texture_size_location_, texture_width_, texture_height_);
checkGLError("glUniform2f(TextureSize)");
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Uniform 'TextureSize' not found in shader");
}
// Uniforms PostFX
vignette_location_ = glGetUniformLocation(program_id_, "uVignette");
scanlines_location_ = glGetUniformLocation(program_id_, "uScanlines");
chroma_location_ = glGetUniformLocation(program_id_, "uChroma");
output_height_location_ = glGetUniformLocation(program_id_, "uOutputHeight");
mask_location_ = glGetUniformLocation(program_id_, "uMask");
gamma_location_ = glGetUniformLocation(program_id_, "uGamma");
curvature_location_ = glGetUniformLocation(program_id_, "uCurvature");
bleeding_location_ = glGetUniformLocation(program_id_, "uBleeding");
if (vignette_location_ != -1) { glUniform1f(vignette_location_, postfx_vignette_); }
if (scanlines_location_ != -1) { glUniform1f(scanlines_location_, postfx_scanlines_); }
if (chroma_location_ != -1) { glUniform1f(chroma_location_, postfx_chroma_); }
if (mask_location_ != -1) { glUniform1f(mask_location_, postfx_mask_); }
if (gamma_location_ != -1) { glUniform1f(gamma_location_, postfx_gamma_); }
if (curvature_location_ != -1) { glUniform1f(curvature_location_, postfx_curvature_); }
if (bleeding_location_ != -1) { glUniform1f(bleeding_location_, postfx_bleeding_); }
glUseProgram(0);
is_initialized_ = true;
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"** OpenGL 3.3 Shader Backend initialized successfully");
return true;
}
void OpenGLShader::render() {
if (!is_initialized_ || program_id_ == 0) {
// Fallback: renderizado SDL normal
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
SDL_SetRenderTarget(renderer_, nullptr);
SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, back_buffer_, nullptr, nullptr);
SDL_RenderPresent(renderer_);
return;
}
// Obtener tamaño actual de ventana (puede haber cambiado)
int current_width;
int current_height;
SDL_GetWindowSize(window_, &current_width, &current_height);
// Guardar estados OpenGL
GLint old_program;
glGetIntegerv(GL_CURRENT_PROGRAM, &old_program);
GLint old_viewport[4];
glGetIntegerv(GL_VIEWPORT, old_viewport);
GLboolean was_texture_enabled = glIsEnabled(GL_TEXTURE_2D);
GLint old_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture);
GLint old_vao;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
// Preparar renderizado
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
SDL_SetRenderTarget(renderer_, nullptr);
SDL_RenderClear(renderer_);
// Obtener y bindear textura
GLuint texture_id = getTextureID(back_buffer_);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);
checkGLError("glBindTexture");
// Usar nuestro programa
glUseProgram(program_id_);
checkGLError("glUseProgram");
// Pasar uniforms PostFX
if (vignette_location_ != -1) { glUniform1f(vignette_location_, postfx_vignette_); }
if (scanlines_location_ != -1) { glUniform1f(scanlines_location_, postfx_scanlines_); }
if (chroma_location_ != -1) { glUniform1f(chroma_location_, postfx_chroma_); }
if (mask_location_ != -1) { glUniform1f(mask_location_, postfx_mask_); }
if (gamma_location_ != -1) { glUniform1f(gamma_location_, postfx_gamma_); }
if (curvature_location_ != -1) { glUniform1f(curvature_location_, postfx_curvature_); }
if (bleeding_location_ != -1) { glUniform1f(bleeding_location_, postfx_bleeding_); }
// Configurar viewport (obtener tamaño lógico de SDL)
int logical_w;
int logical_h;
SDL_RendererLogicalPresentation mode;
SDL_GetRenderLogicalPresentation(renderer_, &logical_w, &logical_h, &mode);
if (logical_w == 0 || logical_h == 0) {
logical_w = current_width;
logical_h = current_height;
}
// Calcular viewport considerando aspect ratio
int viewport_x = 0;
int viewport_y = 0;
int viewport_w = current_width;
int viewport_h = current_height;
if (mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE) {
int scale_x = current_width / logical_w;
int scale_y = current_height / logical_h;
int scale = (scale_x < scale_y) ? scale_x : scale_y;
scale = std::max(scale, 1);
viewport_w = logical_w * scale;
viewport_h = logical_h * scale;
viewport_x = (current_width - viewport_w) / 2;
viewport_y = (current_height - viewport_h) / 2;
} else {
float window_aspect = static_cast<float>(current_width) / current_height;
float logical_aspect = static_cast<float>(logical_w) / logical_h;
if (window_aspect > logical_aspect) {
viewport_w = static_cast<int>(logical_aspect * current_height);
viewport_x = (current_width - viewport_w) / 2;
} else {
viewport_h = static_cast<int>(current_width / logical_aspect);
viewport_y = (current_height - viewport_h) / 2;
}
}
glViewport(viewport_x, viewport_y, viewport_w, viewport_h);
checkGLError("glViewport");
if (output_height_location_ != -1) {
glUniform1f(output_height_location_, static_cast<float>(viewport_h));
}
// Dibujar quad usando VAO
glBindVertexArray(vao_);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
checkGLError("glDrawElements");
// Presentar
SDL_GL_SwapWindow(window_);
// Restaurar estados OpenGL
glUseProgram(old_program);
glBindTexture(GL_TEXTURE_2D, old_texture);
if (was_texture_enabled == 0U) {
glDisable(GL_TEXTURE_2D);
}
glBindVertexArray(old_vao);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
}
void OpenGLShader::setPostFXParams(const PostFXParams& p) {
postfx_vignette_ = p.vignette;
postfx_scanlines_ = p.scanlines;
postfx_chroma_ = p.chroma;
postfx_mask_ = p.mask;
postfx_gamma_ = p.gamma;
postfx_curvature_ = p.curvature;
postfx_bleeding_ = p.bleeding;
}
void OpenGLShader::setTextureSize(float width, float height) {
if (!is_initialized_ || program_id_ == 0) {
return;
}
texture_width_ = width;
texture_height_ = height;
GLint old_program;
glGetIntegerv(GL_CURRENT_PROGRAM, &old_program);
glUseProgram(program_id_);
if (texture_size_location_ != -1) {
glUniform2f(texture_size_location_, width, height);
checkGLError("glUniform2f(TextureSize)");
}
glUseProgram(old_program);
}
void OpenGLShader::cleanup() {
if (vao_ != 0) {
glDeleteVertexArrays(1, &vao_);
vao_ = 0;
}
if (vbo_ != 0) {
glDeleteBuffers(1, &vbo_);
vbo_ = 0;
}
if (ebo_ != 0) {
glDeleteBuffers(1, &ebo_);
ebo_ = 0;
}
if (program_id_ != 0) {
glDeleteProgram(program_id_);
program_id_ = 0;
}
is_initialized_ = false;
window_ = nullptr;
renderer_ = nullptr;
back_buffer_ = nullptr;
}
} // namespace Rendering

View File

@@ -1,119 +0,0 @@
#pragma once
#include "core/rendering/shader_backend.hpp"
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#else
#include <SDL3/SDL_opengl.h>
#endif
namespace Rendering {
/**
* @brief Backend de shaders usando OpenGL 3.3 Core Profile
*
* Implementa el renderizado de shaders usando APIs modernas de OpenGL:
* - VAO (Vertex Array Objects)
* - VBO (Vertex Buffer Objects)
* - Shaders GLSL #version 330 core
*/
class OpenGLShader : public ShaderBackend {
public:
OpenGLShader() = default;
~OpenGLShader() override;
auto init(SDL_Window* window,
SDL_Texture* texture,
const std::string& vertex_source,
const std::string& fragment_source) -> bool override;
void render() override;
void setTextureSize(float width, float height) override;
void setPostFXParams(const PostFXParams& p) override;
void cleanup() final;
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
private:
// Funciones auxiliares
auto initGLExtensions() -> bool;
auto compileShader(const std::string& source, GLenum shader_type) -> GLuint;
auto linkProgram(GLuint vertex_shader, GLuint fragment_shader) -> GLuint;
void createQuadGeometry();
static auto getTextureID(SDL_Texture* texture) -> GLuint;
static void checkGLError(const char* operation);
// Estado SDL
SDL_Window* window_ = nullptr;
SDL_Renderer* renderer_ = nullptr;
SDL_Texture* back_buffer_ = nullptr;
// Estado OpenGL
GLuint program_id_ = 0;
GLuint vao_ = 0; // Vertex Array Object
GLuint vbo_ = 0; // Vertex Buffer Object
GLuint ebo_ = 0; // Element Buffer Object
// Ubicaciones de uniforms
GLint texture_size_location_ = -1;
GLint vignette_location_ = -1;
GLint scanlines_location_ = -1;
GLint chroma_location_ = -1;
GLint output_height_location_ = -1;
GLint mask_location_ = -1;
GLint gamma_location_ = -1;
GLint curvature_location_ = -1;
GLint bleeding_location_ = -1;
// Valores cacheados de PostFX
float postfx_vignette_ = 0.6F;
float postfx_scanlines_ = 0.7F;
float postfx_chroma_ = 0.15F;
float postfx_mask_ = 0.0F;
float postfx_gamma_ = 0.0F;
float postfx_curvature_ = 0.0F;
float postfx_bleeding_ = 0.0F;
// Tamaños
int window_width_ = 0;
int window_height_ = 0;
float texture_width_ = 0.0F;
float texture_height_ = 0.0F;
// Estado
bool is_initialized_ = false;
#ifndef __APPLE__
// NOLINTBEGIN
// Punteros a funciones OpenGL en Windows/Linux
PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr;
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLUNIFORM1FPROC glUniform1f = nullptr;
PFNGLUNIFORM2FPROC glUniform2f = nullptr;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
PFNGLBUFFERDATAPROC glBufferData = nullptr;
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
// NOLINTEND
#endif
};
} // namespace Rendering

View File

@@ -9,10 +9,7 @@
#include <iterator> // Para istreambuf_iterator, operator==
#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/input/mouse.hpp" // Para updateCursorVisibility
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
#include "core/rendering/text.hpp" // Para Text
@@ -223,8 +220,6 @@ void Screen::togglePostFX() {
// Recarga el shader del preset actual sin toggle
void Screen::reloadPostFX() {
if (Options::video.postfx) {
vertex_shader_source_.clear();
fragment_shader_source_.clear();
initShaders();
}
}
@@ -446,38 +441,6 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
return Resource::Helper::loadFile(filepath);
}
// Carga el contenido de los archivos GLSL
void Screen::loadShaders() {
if (vertex_shader_source_.empty()) {
// Detectar si necesitamos OpenGL ES (Raspberry Pi)
// Intentar cargar versión ES primero si existe
auto data = loadData(Resource::List::get()->get("crtpi_vertex_es.glsl"));
if (data.empty()) {
data = loadData(Resource::List::get()->get("crtpi_vertex.glsl"));
std::cout << "Usando shaders OpenGL Desktop 3.3\n";
} else {
std::cout << "Usando shaders OpenGL ES 3.0 (Raspberry Pi)\n";
}
if (!data.empty()) {
vertex_shader_source_ = std::string(data.begin(), data.end());
}
}
if (fragment_shader_source_.empty()) {
// Intentar cargar versión ES primero si existe
auto data = loadData(Resource::List::get()->get("crtpi_fragment_es.glsl"));
if (data.empty()) {
data = loadData(Resource::List::get()->get("crtpi_fragment.glsl"));
}
if (!data.empty()) {
fragment_shader_source_ = std::string(data.begin(), data.end());
}
}
}
// Aplica los parámetros del preset actual al backend de shaders
void Screen::applyCurrentPostFXPreset() {
if (shader_backend_ && !Options::postfx_presets.empty()) {
@@ -496,20 +459,10 @@ void Screen::initShaders() {
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
// 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
applyCurrentPostFXPreset();
}
@@ -576,38 +529,12 @@ auto Screen::initSDLVideo() -> bool {
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal")) {
std::cout << "WARNING: Failed to set Metal hint!\n";
}
#else
// Configurar hint de render driver
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) {
std::cout << "WARNING: Failed to set OpenGL hint!\n";
}
#ifdef _WIN32
// Windows: Pedir explícitamente OpenGL 3.3 Core Profile
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
std::cout << "Solicitando OpenGL 3.3 Core Profile\n";
#else
// Linux: Dejar que SDL elija (Desktop 3.3 en PC, ES 3.0 en RPi automáticamente)
std::cout << "Usando OpenGL por defecto del sistema\n";
#endif
#endif
// Crear ventana
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_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.
SDL_WindowFlags window_flags = 0;
#else
SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL;
#endif
if (Options::video.fullscreen) {
window_flags |= SDL_WINDOW_FULLSCREEN;
}
@@ -622,20 +549,11 @@ auto Screen::initSDLVideo() -> bool {
// Crear renderer
renderer_ = SDL_CreateRenderer(window_, nullptr);
if (renderer_ == nullptr) {
// Fallback: reintentar sin forzar OpenGL (SDL elige el mejor disponible)
std::cerr << "WARNING: OpenGL renderer failed (" << SDL_GetError() << "), trying auto-select...\n";
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "");
renderer_ = SDL_CreateRenderer(window_, nullptr);
if (renderer_ == nullptr) {
std::cerr << "FATAL: Failed to create renderer! SDL Error: " << SDL_GetError() << '\n';
SDL_DestroyWindow(window_);
window_ = nullptr;
SDL_Quit();
return false;
}
// Sin OpenGL garantizado, deshabilitar shaders
Options::video.postfx = false;
std::cout << "WARNING: PostFX disabled (OpenGL not available)\n";
std::cerr << "FATAL: Failed to create renderer! SDL Error: " << SDL_GetError() << '\n';
SDL_DestroyWindow(window_);
window_ = nullptr;
SDL_Quit();
return false;
}
// Configurar renderer

View File

@@ -116,7 +116,6 @@ class Screen {
void renderOverlays(); // Renderiza todos los overlays
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
void initShaders(); // Inicializa los shaders
void loadShaders(); // Carga el contenido del archivo GLSL
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset actual al backend
void renderInfo(); // Muestra información por pantalla
void getDisplayInfo(); // Obtiene información sobre la pantalla
@@ -156,10 +155,8 @@ class Screen {
DisplayMonitor display_monitor_; // Información de la pantalla
// Shaders
std::string info_resolution_; // Texto con la información de la pantalla
std::string vertex_shader_source_; // Almacena el vertex shader
std::string fragment_shader_source_; // Almacena el fragment shader
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
std::string info_resolution_; // Texto con la información de la pantalla
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
#ifdef _DEBUG
bool show_debug_info_{true}; // Indica si ha de mostrar la información de debug