forked from jaildesigner-jailgames/jaildoctors_dilemma
llevant el soport de opengl
This commit is contained in:
@@ -10,13 +10,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|||||||
# Exportar comandos de compilación para herramientas de análisis
|
# Exportar comandos de compilación para herramientas de análisis
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# Establece la política CMP0072 para indicar cómo se debe seleccionar la implementación de OpenGL.
|
|
||||||
# En este caso, se elige la opción "GLVND", que utiliza bibliotecas modernas y modulares (libOpenGL, libGLX),
|
|
||||||
# en lugar de la biblioteca OpenGL clásica (libGL). Esto mejora la compatibilidad con drivers recientes
|
|
||||||
# y evita ambigüedades cuando se encuentran múltiples implementaciones de OpenGL en el sistema.
|
|
||||||
cmake_policy(SET CMP0072 NEW)
|
|
||||||
set(OpenGL_GL_PREFERENCE GLVND)
|
|
||||||
|
|
||||||
# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA ---
|
# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA ---
|
||||||
find_package(Git QUIET)
|
find_package(Git QUIET)
|
||||||
if(GIT_FOUND)
|
if(GIT_FOUND)
|
||||||
@@ -110,18 +103,10 @@ set(APP_SOURCES
|
|||||||
source/main.cpp
|
source/main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fuentes del sistema de renderizado
|
# Fuentes del sistema de renderizado (SDL3 GPU para todas las plataformas)
|
||||||
# En macOS usamos SDL3 GPU (Metal), no OpenGL
|
set(RENDERING_SOURCES
|
||||||
if(APPLE)
|
|
||||||
set(RENDERING_SOURCES
|
|
||||||
source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp
|
source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp
|
||||||
)
|
)
|
||||||
else()
|
|
||||||
set(RENDERING_SOURCES
|
|
||||||
source/core/rendering/opengl/opengl_shader.cpp
|
|
||||||
source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Fuentes de debug (solo en modo Debug)
|
# Fuentes de debug (solo en modo Debug)
|
||||||
set(DEBUG_SOURCES
|
set(DEBUG_SOURCES
|
||||||
@@ -160,7 +145,7 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:RELEASE_B
|
|||||||
# Configuración específica para cada plataforma
|
# Configuración específica para cada plataforma
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 mingw32 opengl32)
|
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 mingw32)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
||||||
@@ -169,19 +154,6 @@ elseif(UNIX AND NOT APPLE)
|
|||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Configuración común para OpenGL (no requerido en macOS: usamos SDL3 GPU API / Metal)
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE opengl32)
|
|
||||||
elseif(NOT APPLE)
|
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
if(OPENGL_FOUND)
|
|
||||||
message(STATUS "OpenGL encontrado: ${OPENGL_LIBRARIES}")
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES})
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "OpenGL no encontrado")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Especificar la ubicación del ejecutable
|
# Especificar la ubicación del ejecutable
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
|
||||||
|
|||||||
@@ -56,17 +56,6 @@ assets:
|
|||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/steam-lords.pal
|
path: ${PREFIX}/data/palette/steam-lords.pal
|
||||||
|
|
||||||
# SHADERS
|
|
||||||
shaders:
|
|
||||||
- type: DATA
|
|
||||||
path: ${PREFIX}/data/shaders/crtpi_vertex.glsl
|
|
||||||
- type: DATA
|
|
||||||
path: ${PREFIX}/data/shaders/crtpi_fragment.glsl
|
|
||||||
- type: DATA
|
|
||||||
path: ${PREFIX}/data/shaders/crtpi_vertex_es.glsl
|
|
||||||
- type: DATA
|
|
||||||
path: ${PREFIX}/data/shaders/crtpi_fragment_es.glsl
|
|
||||||
|
|
||||||
# INPUT
|
# INPUT
|
||||||
input:
|
input:
|
||||||
- type: DATA
|
- type: DATA
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
#version 330 core
|
|
||||||
|
|
||||||
// Configuración
|
|
||||||
#define SCANLINES
|
|
||||||
#define MULTISAMPLE
|
|
||||||
|
|
||||||
#define SCANLINE_WEIGHT 6.0
|
|
||||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
|
||||||
#define BLOOM_FACTOR 3.5
|
|
||||||
|
|
||||||
// Inputs desde vertex shader
|
|
||||||
in vec2 vTexCoord;
|
|
||||||
in float vFilterWidth;
|
|
||||||
|
|
||||||
// Output
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
// Uniforms existentes
|
|
||||||
uniform sampler2D Texture;
|
|
||||||
uniform vec2 TextureSize;
|
|
||||||
uniform float uVignette; // 0 = sin viñeta, 1 = máxima
|
|
||||||
uniform float uScanlines; // 0 = desactivadas, 1 = plenas
|
|
||||||
uniform float uChroma; // 0 = sin aberración, 1 = máxima
|
|
||||||
uniform float uOutputHeight; // altura del viewport en pixels de pantalla
|
|
||||||
|
|
||||||
// Nuevos uniforms
|
|
||||||
uniform float uMask; // 0 = sin máscara de fósforo, 1 = máxima
|
|
||||||
uniform float uGamma; // 0 = sin corrección gamma, 1 = gamma 2.4/2.2 plena
|
|
||||||
uniform float uCurvature; // 0 = plana, 1 = curvatura barrel máxima
|
|
||||||
uniform float uBleeding; // 0 = sin sangrado NTSC, 1 = máximo
|
|
||||||
|
|
||||||
// Conversores YCbCr para efecto NTSC
|
|
||||||
vec3 rgb_to_ycc(vec3 rgb) {
|
|
||||||
return vec3(
|
|
||||||
0.299*rgb.r + 0.587*rgb.g + 0.114*rgb.b,
|
|
||||||
-0.169*rgb.r - 0.331*rgb.g + 0.500*rgb.b + 0.5,
|
|
||||||
0.500*rgb.r - 0.419*rgb.g - 0.081*rgb.b + 0.5
|
|
||||||
);
|
|
||||||
}
|
|
||||||
vec3 ycc_to_rgb(vec3 ycc) {
|
|
||||||
float y = ycc.x;
|
|
||||||
float cb = ycc.y - 0.5;
|
|
||||||
float cr = ycc.z - 0.5;
|
|
||||||
return clamp(vec3(
|
|
||||||
y + 1.402*cr,
|
|
||||||
y - 0.344*cb - 0.714*cr,
|
|
||||||
y + 1.772*cb
|
|
||||||
), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float CalcScanLineWeight(float dist)
|
|
||||||
{
|
|
||||||
return max(1.0 - dist * dist * SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 texcoord = vTexCoord;
|
|
||||||
|
|
||||||
// Curvatura barrel CRT (distorsión en UV antes de muestrear)
|
|
||||||
if (uCurvature > 0.0) {
|
|
||||||
vec2 c = texcoord - 0.5;
|
|
||||||
float rsq = dot(c, c);
|
|
||||||
vec2 dist = vec2(0.05, 0.1) * uCurvature;
|
|
||||||
vec2 barrelScale = 1.0 - 0.23 * dist;
|
|
||||||
c += c * (dist * rsq);
|
|
||||||
c *= barrelScale;
|
|
||||||
if (abs(c.x) >= 0.5 || abs(c.y) >= 0.5) {
|
|
||||||
FragColor = vec4(0.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
texcoord = c + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
|
||||||
|
|
||||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
|
||||||
float yCoord = tempY / TextureSize.y;
|
|
||||||
|
|
||||||
// Scanline en espacio de pantalla (subpíxel)
|
|
||||||
float scaleY = uOutputHeight / TextureSize.y;
|
|
||||||
float screenY = texcoord.y * uOutputHeight;
|
|
||||||
float posInRow = mod(screenY, scaleY);
|
|
||||||
float scanLineDY = posInRow / scaleY - 0.5;
|
|
||||||
float localFilterWidth = 1.0 / scaleY;
|
|
||||||
float scanLineWeight = CalcScanLineWeight(scanLineDY);
|
|
||||||
scanLineWeight += CalcScanLineWeight(scanLineDY - localFilterWidth);
|
|
||||||
scanLineWeight += CalcScanLineWeight(scanLineDY + localFilterWidth);
|
|
||||||
scanLineWeight *= 0.3333333;
|
|
||||||
|
|
||||||
// Phosphor blur en espacio textura
|
|
||||||
float dy = texcoordInPixels.y - tempY;
|
|
||||||
float signY = sign(dy);
|
|
||||||
dy = dy * dy;
|
|
||||||
dy = dy * dy;
|
|
||||||
dy *= 8.0;
|
|
||||||
dy /= TextureSize.y;
|
|
||||||
dy *= signY;
|
|
||||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
|
||||||
|
|
||||||
// Muestra base en centro
|
|
||||||
vec3 base = texture(Texture, tc).rgb;
|
|
||||||
|
|
||||||
// Sangrado NTSC — difuminado horizontal de crominancia
|
|
||||||
vec3 colour;
|
|
||||||
if (uBleeding > 0.0) {
|
|
||||||
float tw = TextureSize.x;
|
|
||||||
vec3 ycc = rgb_to_ycc(base);
|
|
||||||
vec3 ycc_l2 = rgb_to_ycc(texture(Texture, tc - vec2(2.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_l1 = rgb_to_ycc(texture(Texture, tc - vec2(1.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_r1 = rgb_to_ycc(texture(Texture, tc + vec2(1.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_r2 = rgb_to_ycc(texture(Texture, tc + vec2(2.0/tw, 0.0)).rgb);
|
|
||||||
ycc.yz = (ycc_l2.yz + ycc_l1.yz*2.0 + ycc.yz*2.0 + ycc_r1.yz*2.0 + ycc_r2.yz) / 8.0;
|
|
||||||
colour = mix(base, ycc_to_rgb(ycc), uBleeding);
|
|
||||||
} else {
|
|
||||||
colour = base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aberración cromática
|
|
||||||
float ca = uChroma * 0.005;
|
|
||||||
colour.r = texture(Texture, tc + vec2(ca, 0.0)).r;
|
|
||||||
colour.b = texture(Texture, tc - vec2(ca, 0.0)).b;
|
|
||||||
|
|
||||||
// Corrección gamma (linealizar antes de scanlines, codificar después)
|
|
||||||
if (uGamma > 0.0) {
|
|
||||||
vec3 lin = pow(colour, vec3(2.4));
|
|
||||||
colour = mix(colour, lin, uGamma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanlines
|
|
||||||
scanLineWeight *= BLOOM_FACTOR;
|
|
||||||
colour *= mix(1.0, scanLineWeight, uScanlines);
|
|
||||||
|
|
||||||
if (uGamma > 0.0) {
|
|
||||||
vec3 enc = pow(colour, vec3(1.0 / 2.2));
|
|
||||||
colour = mix(colour, enc, uGamma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Viñeta
|
|
||||||
if (uVignette > 0.0) {
|
|
||||||
vec2 uv = texcoord - vec2(0.5);
|
|
||||||
float vig = 1.0 - dot(uv, uv) * uVignette * 4.0;
|
|
||||||
colour *= clamp(vig, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Máscara de fósforo RGB
|
|
||||||
if (uMask > 0.0) {
|
|
||||||
float whichMask = fract(gl_FragCoord.x * 0.3333333);
|
|
||||||
vec3 mask = vec3(0.80);
|
|
||||||
if (whichMask < 0.3333333)
|
|
||||||
mask.x = 1.0;
|
|
||||||
else if (whichMask < 0.6666666)
|
|
||||||
mask.y = 1.0;
|
|
||||||
else
|
|
||||||
mask.z = 1.0;
|
|
||||||
colour = mix(colour, colour * mask, uMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
FragColor = vec4(colour, 1.0);
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
#version 300 es
|
|
||||||
|
|
||||||
// OpenGL ES 3.0 - Compatible con Raspberry Pi 5
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
// Configuración
|
|
||||||
#define SCANLINES
|
|
||||||
#define MULTISAMPLE
|
|
||||||
|
|
||||||
#define SCANLINE_WEIGHT 6.0
|
|
||||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
|
||||||
#define BLOOM_FACTOR 3.5
|
|
||||||
|
|
||||||
// Inputs desde vertex shader
|
|
||||||
in vec2 vTexCoord;
|
|
||||||
in float vFilterWidth;
|
|
||||||
|
|
||||||
// Output
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
// Uniforms existentes
|
|
||||||
uniform sampler2D Texture;
|
|
||||||
uniform vec2 TextureSize;
|
|
||||||
uniform float uVignette; // 0 = sin viñeta, 1 = máxima
|
|
||||||
uniform float uScanlines; // 0 = desactivadas, 1 = plenas
|
|
||||||
uniform float uChroma; // 0 = sin aberración, 1 = máxima
|
|
||||||
uniform float uOutputHeight; // altura del viewport en pixels de pantalla
|
|
||||||
|
|
||||||
// Nuevos uniforms
|
|
||||||
uniform float uMask; // 0 = sin máscara de fósforo, 1 = máxima
|
|
||||||
uniform float uGamma; // 0 = sin corrección gamma, 1 = gamma 2.4/2.2 plena
|
|
||||||
uniform float uCurvature; // 0 = plana, 1 = curvatura barrel máxima
|
|
||||||
uniform float uBleeding; // 0 = sin sangrado NTSC, 1 = máximo
|
|
||||||
|
|
||||||
// Conversores YCbCr para efecto NTSC
|
|
||||||
vec3 rgb_to_ycc(vec3 rgb) {
|
|
||||||
return vec3(
|
|
||||||
0.299*rgb.r + 0.587*rgb.g + 0.114*rgb.b,
|
|
||||||
-0.169*rgb.r - 0.331*rgb.g + 0.500*rgb.b + 0.5,
|
|
||||||
0.500*rgb.r - 0.419*rgb.g - 0.081*rgb.b + 0.5
|
|
||||||
);
|
|
||||||
}
|
|
||||||
vec3 ycc_to_rgb(vec3 ycc) {
|
|
||||||
float y = ycc.x;
|
|
||||||
float cb = ycc.y - 0.5;
|
|
||||||
float cr = ycc.z - 0.5;
|
|
||||||
return clamp(vec3(
|
|
||||||
y + 1.402*cr,
|
|
||||||
y - 0.344*cb - 0.714*cr,
|
|
||||||
y + 1.772*cb
|
|
||||||
), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float CalcScanLineWeight(float dist)
|
|
||||||
{
|
|
||||||
return max(1.0 - dist * dist * SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 texcoord = vTexCoord;
|
|
||||||
|
|
||||||
// Curvatura barrel CRT (distorsión en UV antes de muestrear)
|
|
||||||
if (uCurvature > 0.0) {
|
|
||||||
vec2 c = texcoord - vec2(0.5);
|
|
||||||
float rsq = dot(c, c);
|
|
||||||
vec2 dist = vec2(0.05, 0.1) * uCurvature;
|
|
||||||
vec2 barrelScale = vec2(1.0) - 0.23 * dist;
|
|
||||||
c += c * (dist * rsq);
|
|
||||||
c *= barrelScale;
|
|
||||||
if (abs(c.x) >= 0.5 || abs(c.y) >= 0.5) {
|
|
||||||
FragColor = vec4(0.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
texcoord = c + vec2(0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
|
||||||
|
|
||||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
|
||||||
float yCoord = tempY / TextureSize.y;
|
|
||||||
|
|
||||||
// Scanline en espacio de pantalla (subpíxel)
|
|
||||||
float scaleY = uOutputHeight / TextureSize.y;
|
|
||||||
float screenY = texcoord.y * uOutputHeight;
|
|
||||||
float posInRow = mod(screenY, scaleY);
|
|
||||||
float scanLineDY = posInRow / scaleY - 0.5;
|
|
||||||
float localFilterWidth = 1.0 / scaleY;
|
|
||||||
float scanLineWeight = CalcScanLineWeight(scanLineDY);
|
|
||||||
scanLineWeight += CalcScanLineWeight(scanLineDY - localFilterWidth);
|
|
||||||
scanLineWeight += CalcScanLineWeight(scanLineDY + localFilterWidth);
|
|
||||||
scanLineWeight *= 0.3333333;
|
|
||||||
|
|
||||||
// Phosphor blur en espacio textura
|
|
||||||
float dy = texcoordInPixels.y - tempY;
|
|
||||||
float signY = sign(dy);
|
|
||||||
dy = dy * dy;
|
|
||||||
dy = dy * dy;
|
|
||||||
dy *= 8.0;
|
|
||||||
dy /= TextureSize.y;
|
|
||||||
dy *= signY;
|
|
||||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
|
||||||
|
|
||||||
// Muestra base en centro
|
|
||||||
vec3 base = texture(Texture, tc).rgb;
|
|
||||||
|
|
||||||
// Sangrado NTSC — difuminado horizontal de crominancia
|
|
||||||
vec3 colour;
|
|
||||||
if (uBleeding > 0.0) {
|
|
||||||
float tw = TextureSize.x;
|
|
||||||
vec3 ycc = rgb_to_ycc(base);
|
|
||||||
vec3 ycc_l2 = rgb_to_ycc(texture(Texture, tc - vec2(2.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_l1 = rgb_to_ycc(texture(Texture, tc - vec2(1.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_r1 = rgb_to_ycc(texture(Texture, tc + vec2(1.0/tw, 0.0)).rgb);
|
|
||||||
vec3 ycc_r2 = rgb_to_ycc(texture(Texture, tc + vec2(2.0/tw, 0.0)).rgb);
|
|
||||||
ycc.yz = (ycc_l2.yz + ycc_l1.yz*2.0 + ycc.yz*2.0 + ycc_r1.yz*2.0 + ycc_r2.yz) / 8.0;
|
|
||||||
colour = mix(base, ycc_to_rgb(ycc), uBleeding);
|
|
||||||
} else {
|
|
||||||
colour = base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aberración cromática
|
|
||||||
float ca = uChroma * 0.005;
|
|
||||||
colour.r = texture(Texture, tc + vec2(ca, 0.0)).r;
|
|
||||||
colour.b = texture(Texture, tc - vec2(ca, 0.0)).b;
|
|
||||||
|
|
||||||
// Corrección gamma (linealizar antes de scanlines, codificar después)
|
|
||||||
if (uGamma > 0.0) {
|
|
||||||
vec3 lin = pow(colour, vec3(2.4));
|
|
||||||
colour = mix(colour, lin, uGamma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanlines
|
|
||||||
scanLineWeight *= BLOOM_FACTOR;
|
|
||||||
colour *= mix(1.0, scanLineWeight, uScanlines);
|
|
||||||
|
|
||||||
if (uGamma > 0.0) {
|
|
||||||
vec3 enc = pow(colour, vec3(1.0 / 2.2));
|
|
||||||
colour = mix(colour, enc, uGamma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Viñeta
|
|
||||||
if (uVignette > 0.0) {
|
|
||||||
vec2 uv = texcoord - vec2(0.5);
|
|
||||||
float vig = 1.0 - dot(uv, uv) * uVignette * 4.0;
|
|
||||||
colour *= clamp(vig, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Máscara de fósforo RGB
|
|
||||||
if (uMask > 0.0) {
|
|
||||||
float whichMask = fract(gl_FragCoord.x * 0.3333333);
|
|
||||||
vec3 mask = vec3(0.80);
|
|
||||||
if (whichMask < 0.3333333)
|
|
||||||
mask.x = 1.0;
|
|
||||||
else if (whichMask < 0.6666666)
|
|
||||||
mask.y = 1.0;
|
|
||||||
else
|
|
||||||
mask.z = 1.0;
|
|
||||||
colour = mix(colour, colour * mask, uMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
FragColor = vec4(colour, 1.0);
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#version 330 core
|
|
||||||
|
|
||||||
// Configuración
|
|
||||||
#define SCANLINES
|
|
||||||
#define MULTISAMPLE
|
|
||||||
#define GAMMA
|
|
||||||
//#define FAKE_GAMMA
|
|
||||||
//#define CURVATURE
|
|
||||||
//#define SHARPER
|
|
||||||
#define MASK_TYPE 2
|
|
||||||
|
|
||||||
#define CURVATURE_X 0.05
|
|
||||||
#define CURVATURE_Y 0.1
|
|
||||||
#define MASK_BRIGHTNESS 0.80
|
|
||||||
#define SCANLINE_WEIGHT 6.0
|
|
||||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
|
||||||
#define BLOOM_FACTOR 3.5
|
|
||||||
#define INPUT_GAMMA 2.4
|
|
||||||
#define OUTPUT_GAMMA 2.2
|
|
||||||
|
|
||||||
// Inputs (desde VAO)
|
|
||||||
layout(location = 0) in vec2 aPosition;
|
|
||||||
layout(location = 1) in vec2 aTexCoord;
|
|
||||||
|
|
||||||
// Outputs al fragment shader
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
out float vFilterWidth;
|
|
||||||
#if defined(CURVATURE)
|
|
||||||
out vec2 vScreenScale;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Uniforms
|
|
||||||
uniform vec2 TextureSize;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
#if defined(CURVATURE)
|
|
||||||
vScreenScale = vec2(1.0, 1.0);
|
|
||||||
#endif
|
|
||||||
// Calcula filterWidth dinámicamente basándose en la altura de la textura
|
|
||||||
vFilterWidth = (768.0 / TextureSize.y) / 3.0;
|
|
||||||
|
|
||||||
// Pasar coordenadas de textura (invertir Y para SDL)
|
|
||||||
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y) * 1.0001;
|
|
||||||
|
|
||||||
// Posición del vértice (ya en espacio de clip [-1, 1])
|
|
||||||
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#version 300 es
|
|
||||||
|
|
||||||
// OpenGL ES 3.0 - Compatible con Raspberry Pi 5
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
// Configuración
|
|
||||||
#define SCANLINES
|
|
||||||
#define MULTISAMPLE
|
|
||||||
#define GAMMA
|
|
||||||
//#define FAKE_GAMMA
|
|
||||||
//#define CURVATURE
|
|
||||||
//#define SHARPER
|
|
||||||
#define MASK_TYPE 2
|
|
||||||
|
|
||||||
#define CURVATURE_X 0.05
|
|
||||||
#define CURVATURE_Y 0.1
|
|
||||||
#define MASK_BRIGHTNESS 0.80
|
|
||||||
#define SCANLINE_WEIGHT 6.0
|
|
||||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
|
||||||
#define BLOOM_FACTOR 3.5
|
|
||||||
#define INPUT_GAMMA 2.4
|
|
||||||
#define OUTPUT_GAMMA 2.2
|
|
||||||
|
|
||||||
// Inputs (desde VAO)
|
|
||||||
layout(location = 0) in vec2 aPosition;
|
|
||||||
layout(location = 1) in vec2 aTexCoord;
|
|
||||||
|
|
||||||
// Outputs al fragment shader
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
out float vFilterWidth;
|
|
||||||
#if defined(CURVATURE)
|
|
||||||
out vec2 vScreenScale;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Uniforms
|
|
||||||
uniform vec2 TextureSize;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
#if defined(CURVATURE)
|
|
||||||
vScreenScale = vec2(1.0, 1.0);
|
|
||||||
#endif
|
|
||||||
// Calcula filterWidth dinámicamente basándose en la altura de la textura
|
|
||||||
vFilterWidth = (768.0 / TextureSize.y) / 3.0;
|
|
||||||
|
|
||||||
// Pasar coordenadas de textura (invertir Y para SDL)
|
|
||||||
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y) * 1.0001;
|
|
||||||
|
|
||||||
// Posición del vértice (ya en espacio de clip [-1, 1])
|
|
||||||
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
@@ -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_, ¤t_width, ¤t_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
|
|
||||||
@@ -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
|
|
||||||
@@ -10,9 +10,6 @@
|
|||||||
#include <string> // Para char_traits, string, operator+, operator==
|
#include <string> // Para char_traits, string, operator+, operator==
|
||||||
|
|
||||||
#include "core/input/mouse.hpp" // Para updateCursorVisibility
|
#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/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
|
||||||
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
|
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
|
||||||
#include "core/rendering/text.hpp" // Para Text
|
#include "core/rendering/text.hpp" // Para Text
|
||||||
@@ -223,8 +220,6 @@ void Screen::togglePostFX() {
|
|||||||
// Recarga el shader del preset actual sin toggle
|
// Recarga el shader del preset actual sin toggle
|
||||||
void Screen::reloadPostFX() {
|
void Screen::reloadPostFX() {
|
||||||
if (Options::video.postfx) {
|
if (Options::video.postfx) {
|
||||||
vertex_shader_source_.clear();
|
|
||||||
fragment_shader_source_.clear();
|
|
||||||
initShaders();
|
initShaders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,38 +441,6 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
|
|||||||
return Resource::Helper::loadFile(filepath);
|
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
|
// Aplica los parámetros del preset actual al backend de shaders
|
||||||
void Screen::applyCurrentPostFXPreset() {
|
void Screen::applyCurrentPostFXPreset() {
|
||||||
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
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_;
|
SDL_Texture* tex = Options::video.border.enabled ? border_texture_ : game_texture_;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// macOS: usar SDL3 GPU API (Metal) via SDL3GPUShader
|
|
||||||
if (!shader_backend_) {
|
if (!shader_backend_) {
|
||||||
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
||||||
}
|
}
|
||||||
shader_backend_->init(window_, tex, "", "");
|
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();
|
applyCurrentPostFXPreset();
|
||||||
}
|
}
|
||||||
@@ -576,38 +529,12 @@ auto Screen::initSDLVideo() -> bool {
|
|||||||
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal")) {
|
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal")) {
|
||||||
std::cout << "WARNING: Failed to set Metal hint!\n";
|
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
|
#endif
|
||||||
|
|
||||||
// Crear ventana
|
// Crear ventana
|
||||||
const auto WINDOW_WIDTH = Options::video.border.enabled ? Options::game.width + (Options::video.border.width * 2) : Options::game.width;
|
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;
|
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;
|
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) {
|
if (Options::video.fullscreen) {
|
||||||
window_flags |= SDL_WINDOW_FULLSCREEN;
|
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||||
}
|
}
|
||||||
@@ -621,11 +548,6 @@ auto Screen::initSDLVideo() -> bool {
|
|||||||
|
|
||||||
// Crear renderer
|
// Crear renderer
|
||||||
renderer_ = SDL_CreateRenderer(window_, nullptr);
|
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) {
|
if (renderer_ == nullptr) {
|
||||||
std::cerr << "FATAL: Failed to create renderer! SDL Error: " << SDL_GetError() << '\n';
|
std::cerr << "FATAL: Failed to create renderer! SDL Error: " << SDL_GetError() << '\n';
|
||||||
SDL_DestroyWindow(window_);
|
SDL_DestroyWindow(window_);
|
||||||
@@ -633,10 +555,6 @@ auto Screen::initSDLVideo() -> bool {
|
|||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Sin OpenGL garantizado, deshabilitar shaders
|
|
||||||
Options::video.postfx = false;
|
|
||||||
std::cout << "WARNING: PostFX disabled (OpenGL not available)\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configurar renderer
|
// Configurar renderer
|
||||||
const int EXTRA_WIDTH = Options::video.border.enabled ? Options::video.border.width * 2 : 0;
|
const int EXTRA_WIDTH = Options::video.border.enabled ? Options::video.border.width * 2 : 0;
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ class Screen {
|
|||||||
void renderOverlays(); // Renderiza todos los overlays
|
void renderOverlays(); // Renderiza todos los overlays
|
||||||
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
|
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
|
||||||
void initShaders(); // Inicializa los shaders
|
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 applyCurrentPostFXPreset(); // Aplica los parámetros del preset actual al backend
|
||||||
void renderInfo(); // Muestra información por pantalla
|
void renderInfo(); // Muestra información por pantalla
|
||||||
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
||||||
@@ -157,8 +156,6 @@ class Screen {
|
|||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
std::string info_resolution_; // Texto con la información de la pantalla
|
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::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|||||||
Reference in New Issue
Block a user