afegits altres shaders
pantalla completa tecla esc readme.md
This commit is contained in:
79
README.md
Normal file
79
README.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Shadertoy SDL3 + OpenGL
|
||||||
|
|
||||||
|
Proyecto minimal para ejecutar fragment shaders tipo Shadertoy usando SDL3 + GLAD + OpenGL 3.3.
|
||||||
|
|
||||||
|
## Estructura
|
||||||
|
- src/ — código fuente C++ (incluye main.cpp).
|
||||||
|
- shaders/ — shaders fragment (.frag.glsl) que se cargan en runtime.
|
||||||
|
- third_party/glad/ — glad.c + headers.
|
||||||
|
- CMakeLists.txt — configuración de build.
|
||||||
|
- .gitignore — recomendado.
|
||||||
|
|
||||||
|
## Requisitos
|
||||||
|
- CMake >= 3.16
|
||||||
|
- Compilador con soporte C++17
|
||||||
|
- SDL3 development headers and library
|
||||||
|
- GL loader (GLAD) incluido en third_party/glad o disponible en el sistema
|
||||||
|
|
||||||
|
Instalación típica:
|
||||||
|
- Debian/Ubuntu:
|
||||||
|
sudo apt install build-essential cmake libsdl3-dev
|
||||||
|
- macOS (Homebrew):
|
||||||
|
brew install cmake sdl3
|
||||||
|
|
||||||
|
## Build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build . --config Release
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
Por defecto el ejecutable carga shaders/test.frag.glsl.
|
||||||
|
|
||||||
|
Ejecutar en ventana:
|
||||||
|
./shadertoy_sdl3 ../shaders/test.frag.glsl
|
||||||
|
|
||||||
|
Ejecutar en fullscreen nativo:
|
||||||
|
./shadertoy_sdl3 -F ../shaders/test.frag.glsl
|
||||||
|
|
||||||
|
Si ejecutas desde la raíz del repo:
|
||||||
|
./build/shadertoy_sdl3 shaders/frag_tile_iter.frag.glsl
|
||||||
|
|
||||||
|
Atajos en ejecución
|
||||||
|
- Escape — salir.
|
||||||
|
- F11 — alternar fullscreen desktop.
|
||||||
|
|
||||||
|
## Formato de shader esperado
|
||||||
|
- #version 330 core
|
||||||
|
- Debe declarar:
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
in vec2 vUV;
|
||||||
|
out vec4 FragColor;
|
||||||
|
- Función de entrada esperada (opcional, el main llama a mainImage):
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord);
|
||||||
|
- main() debe convertir vUV a fragCoord y llamar a mainImage.
|
||||||
|
|
||||||
|
## Rutas y ejecución
|
||||||
|
El ejecutable intenta varias rutas relativas para localizar el shader:
|
||||||
|
- ruta tal cual pasada en argv
|
||||||
|
- ./<ruta>
|
||||||
|
- ../<ruta>
|
||||||
|
- relativo al directorio del ejecutable
|
||||||
|
|
||||||
|
Si obtienes "Failed to load fragment shader file", ejecuta desde la carpeta build o pasa la ruta correcta a tu shader.
|
||||||
|
|
||||||
|
## Multi-pass / Buffers (nota)
|
||||||
|
Ejemplo actual es single-pass. Para portar Shadertoy con BufferA/B/C necesitas:
|
||||||
|
- crear FBOs y textures por buffer
|
||||||
|
- renderizar buffers en orden y pasar las texturas como iChannelN a pases posteriores
|
||||||
|
- evitar leer y escribir la misma textura (usar ping-pong si hace falta)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
- SDL_Init devuelve error vacío: asegúrate que SDL3.dll (Windows) está en el mismo directorio que el ejecutable o en PATH.
|
||||||
|
- Errores de compilación/constantes: verifica que usas SDL3 headers (#include <SDL3/SDL.h>) y no SDL2.
|
||||||
|
- Shaders que fallan a compilar: revisa glGetShaderInfoLog en la salida; versiones GLSL y funciones incompatibles son la causa habitual.
|
||||||
|
|
||||||
|
## Licencia y créditos
|
||||||
|
- Código de ejemplo: libre para uso personal y adaptación.
|
||||||
|
- Respeta créditos de shaders copiados de Shadertoy/otros autores cuando los reutilices.
|
||||||
42
shaders/creation.frac.glsl
Normal file
42
shaders/creation.frac.glsl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
#define t iTime
|
||||||
|
#define r iResolution.xy
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec3 c = vec3(0.0);
|
||||||
|
float l;
|
||||||
|
float z = t;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
vec2 uv, p = fragCoord.xy / r;
|
||||||
|
uv = p;
|
||||||
|
p -= 0.5;
|
||||||
|
p.x *= r.x / r.y;
|
||||||
|
z += 0.07;
|
||||||
|
l = length(p);
|
||||||
|
// evitar división por cero
|
||||||
|
float invl = (l > 0.0) ? (1.0 / l) : 0.0;
|
||||||
|
uv += p * invl * (sin(z) + 1.0) * abs(sin(l * 9.0 - z - z));
|
||||||
|
vec2 m = mod(uv, 1.0) - 0.5;
|
||||||
|
float denom = length(m);
|
||||||
|
// evitar división por cero en el denominador
|
||||||
|
if (denom < 1e-6) denom = 1e-6;
|
||||||
|
c[i] = 0.01 / denom;
|
||||||
|
}
|
||||||
|
// si l es cero, usar 1.0 para evitar NaN
|
||||||
|
float L = (l > 0.0) ? l : 1.0;
|
||||||
|
fragColor = vec4(c / L, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
65
shaders/fractal_pyramid.frag.glsl
Normal file
65
shaders/fractal_pyramid.frag.glsl
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
vec3 palette(float d){
|
||||||
|
return mix(vec3(0.2,0.7,0.9), vec3(1.0,0.0,1.0), d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 rotate(vec2 p, float a){
|
||||||
|
float c = cos(a);
|
||||||
|
float s = sin(a);
|
||||||
|
return p * mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 p){
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float t = iTime * 0.2;
|
||||||
|
p.xz = rotate(p.xz, t);
|
||||||
|
p.xy = rotate(p.xy, t * 1.89);
|
||||||
|
p.xz = abs(p.xz);
|
||||||
|
p.xz -= 0.5;
|
||||||
|
}
|
||||||
|
return dot(sign(p), p) / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 rm(vec3 ro, vec3 rd){
|
||||||
|
float t = 0.0;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float d = 1.0;
|
||||||
|
for (int i = 0; i < 64; ++i){
|
||||||
|
vec3 p = ro + rd * t;
|
||||||
|
d = mapScene(p) * 0.5;
|
||||||
|
if (d < 0.02) break;
|
||||||
|
if (d > 100.0) break;
|
||||||
|
col += palette(length(p) * 0.1) / (400.0 * d);
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
return vec4(col, 1.0 / (d * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord){
|
||||||
|
vec2 uv = (fragCoord - (iResolution.xy * 0.5)) / iResolution.x;
|
||||||
|
vec3 ro = vec3(0.0, 0.0, -50.0);
|
||||||
|
ro.xz = rotate(ro.xz, iTime);
|
||||||
|
vec3 cf = normalize(-ro);
|
||||||
|
vec3 cs = normalize(cross(cf, vec3(0.0, 1.0, 0.0)));
|
||||||
|
vec3 cu = normalize(cross(cf, cs));
|
||||||
|
|
||||||
|
vec3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu;
|
||||||
|
vec3 rd = normalize(uuv - ro);
|
||||||
|
|
||||||
|
vec4 col = rm(ro, rd);
|
||||||
|
fragColor = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
47
shaders/kishimisu.frag.glsl
Normal file
47
shaders/kishimisu.frag.glsl
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
vec3 palette( float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos( 6.28318 * (c * t * d) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
|
||||||
|
vec2 uv0 = uv;
|
||||||
|
vec3 finalColor = vec3(0.0);
|
||||||
|
|
||||||
|
for (float i = 0.0; i < 4.0; i++) {
|
||||||
|
uv = fract(uv * 1.5) - 0.5;
|
||||||
|
|
||||||
|
float d = length(uv) * exp(-length(uv0));
|
||||||
|
|
||||||
|
vec3 col = palette(length(uv0) + i * 0.4 + iTime * 0.4);
|
||||||
|
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
|
||||||
|
d = abs(d);
|
||||||
|
|
||||||
|
d = pow(0.01 / d, 1.2);
|
||||||
|
|
||||||
|
finalColor += col * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = vec4(finalColor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
104
shaders/octograms.frag.glsl
Normal file
104
shaders/octograms.frag.glsl
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#version 330 core
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
float gTime = 0.0;
|
||||||
|
const float REPEAT = 5.0;
|
||||||
|
|
||||||
|
// rotación 2D
|
||||||
|
mat2 rot(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdBox(vec3 p, vec3 b) {
|
||||||
|
vec3 q = abs(p) - b;
|
||||||
|
return length(max(q, vec3(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxGeom(vec3 pos, float scale) {
|
||||||
|
pos *= scale;
|
||||||
|
float base = sdBox(pos, vec3(.4, .4, .1)) / 1.5;
|
||||||
|
pos.xy *= 5.0;
|
||||||
|
pos.y -= 3.5;
|
||||||
|
pos.xy *= rot(.75);
|
||||||
|
float result = -base;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float box_set(vec3 pos, float iTimeLocal) {
|
||||||
|
vec3 pos_origin = pos;
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box1 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box2 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box3 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box4 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box5 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
float box6 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
float result = max(max(max(max(max(box1, box2), box3), box4), box5), box6);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 pos, float iTimeLocal) {
|
||||||
|
return box_set(pos, iTimeLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 p = (fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
|
||||||
|
vec3 ro = vec3(0.0, -0.2, iTime * 4.0);
|
||||||
|
vec3 ray = normalize(vec3(p, 1.5));
|
||||||
|
ray.xy = ray.xy * rot(sin(iTime * .03) * 5.0);
|
||||||
|
ray.yz = ray.yz * rot(sin(iTime * .05) * .2);
|
||||||
|
float t = 0.1;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float ac = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 99; i++) {
|
||||||
|
vec3 pos = ro + ray * t;
|
||||||
|
pos = mod(pos - 2.0, 4.0) - 2.0;
|
||||||
|
gTime = iTime - float(i) * 0.01;
|
||||||
|
|
||||||
|
float d = mapScene(pos, iTime);
|
||||||
|
|
||||||
|
d = max(abs(d), 0.01);
|
||||||
|
ac += exp(-d * 23.0);
|
||||||
|
|
||||||
|
t += d * 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
col = vec3(ac * 0.02);
|
||||||
|
col += vec3(0.0, 0.2 * abs(sin(iTime)), 0.5 + sin(iTime) * 0.2);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0 - t * (0.02 + 0.02 * sin(iTime)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
32
shaders/test.frag.glsl
Normal file
32
shaders/test.frag.glsl
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 vUV;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
|
||||||
|
vec3 palette( float t) {
|
||||||
|
vec3 a = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos( 6.28318 * (c * t * d) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
|
||||||
|
float d = length(uv);
|
||||||
|
vec3 col = palette(d);
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = 0.02 / d;
|
||||||
|
col *= d;
|
||||||
|
fragColor = vec4(col, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
328
src/main.cpp
328
src/main.cpp
@@ -1,11 +1,42 @@
|
|||||||
// src/main.cpp
|
// src/main.cpp
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <filesystem>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
// Vertex shader: genera posiciones de pantalla y una coordenada uv en [0,1]
|
// Simple logger compatible con el estilo que usas
|
||||||
static const char *vertexShaderSrc = R"glsl(
|
struct Logger {
|
||||||
|
static void info(const std::string& s) { std::cout << "[INFO] " << s << '\n'; }
|
||||||
|
static void error(const std::string& s) { std::cerr << "[ERROR] " << s << '\n'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Opciones mínimas parecidas a las tuyas
|
||||||
|
struct VideoOptions {
|
||||||
|
bool fullscreen = false;
|
||||||
|
} Options_video;
|
||||||
|
|
||||||
|
// Estructura para guardar info del display
|
||||||
|
struct DisplayMonitor {
|
||||||
|
std::string name;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int refresh_rate = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Globales simplificados (tu proyecto puede integrarlo en clases)
|
||||||
|
static DisplayMonitor display_monitor_;
|
||||||
|
static SDL_Window* window_ = nullptr;
|
||||||
|
|
||||||
|
// Constante por defecto del fragment shader
|
||||||
|
static constexpr const char* DEFAULT_FRAG = "shaders/test.frag.glsl";
|
||||||
|
|
||||||
|
// Vertex shader embebido
|
||||||
|
static const char* vertexShaderSrc = R"glsl(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
layout(location = 0) in vec2 aPos;
|
layout(location = 0) in vec2 aPos;
|
||||||
out vec2 vUV;
|
out vec2 vUV;
|
||||||
@@ -15,146 +46,230 @@ void main() {
|
|||||||
}
|
}
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
||||||
// Fragment shader: adapta tu shader de Shadertoy
|
// Helpers de carga
|
||||||
static const char *fragmentShaderSrc = R"glsl(
|
static bool loadFileToString(const std::filesystem::path& path, std::string& out) {
|
||||||
#version 330 core
|
std::ifstream ifs(path, std::ios::in | std::ios::binary);
|
||||||
out vec4 FragColor;
|
if (!ifs) return false;
|
||||||
in vec2 vUV;
|
std::ostringstream ss;
|
||||||
uniform vec2 iResolution;
|
ss << ifs.rdbuf();
|
||||||
uniform float iTime;
|
out = ss.str();
|
||||||
|
return true;
|
||||||
vec3 palette( float t) {
|
|
||||||
vec3 a = vec3(1.0, 0.5, 0.5);
|
|
||||||
vec3 b = vec3(1.0, 0.5, 0.5);
|
|
||||||
vec3 c = vec3(1.0, 1.0, 1.0);
|
|
||||||
vec3 d = vec3(0.263, 0.416, 0.557);
|
|
||||||
return a + b * cos( 6.28318 * (c * t * d) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
static GLuint compileShader(GLenum type, const char* src) {
|
||||||
{
|
|
||||||
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
|
|
||||||
float d = length(uv);
|
|
||||||
vec3 col = palette(d);
|
|
||||||
d = sin(d * 8.0 + iTime) / 8.0;
|
|
||||||
d = abs(d);
|
|
||||||
d = 0.02 / d;
|
|
||||||
col *= d;
|
|
||||||
fragColor = vec4(col, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 fragCoordPixels = vUV * iResolution;
|
|
||||||
vec4 outColor;
|
|
||||||
mainImage(outColor, fragCoordPixels);
|
|
||||||
FragColor = outColor;
|
|
||||||
}
|
|
||||||
)glsl";
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
static GLuint compileShader(GLenum type, const char *src)
|
|
||||||
{
|
|
||||||
GLuint s = glCreateShader(type);
|
GLuint s = glCreateShader(type);
|
||||||
glShaderSource(s, 1, &src, nullptr);
|
glShaderSource(s, 1, &src, nullptr);
|
||||||
glCompileShader(s);
|
glCompileShader(s);
|
||||||
GLint ok = 0;
|
GLint ok = 0;
|
||||||
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
|
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
|
||||||
if (!ok)
|
if (!ok) {
|
||||||
{
|
|
||||||
GLint len = 0;
|
GLint len = 0;
|
||||||
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
|
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
|
||||||
std::string log(len, ' ');
|
std::string log(len > 0 ? len : 1, ' ');
|
||||||
glGetShaderInfoLog(s, len, nullptr, &log[0]);
|
glGetShaderInfoLog(s, len, nullptr, &log[0]);
|
||||||
std::cerr << "Shader compile error: " << log << '\n';
|
Logger::error("Shader compile error: " + log);
|
||||||
glDeleteShader(s);
|
glDeleteShader(s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLuint linkProgram(GLuint vs, GLuint fs)
|
static GLuint linkProgram(GLuint vs, GLuint fs) {
|
||||||
{
|
|
||||||
GLuint p = glCreateProgram();
|
GLuint p = glCreateProgram();
|
||||||
glAttachShader(p, vs);
|
glAttachShader(p, vs);
|
||||||
glAttachShader(p, fs);
|
glAttachShader(p, fs);
|
||||||
glLinkProgram(p);
|
glLinkProgram(p);
|
||||||
GLint ok = 0;
|
GLint ok = 0;
|
||||||
glGetProgramiv(p, GL_LINK_STATUS, &ok);
|
glGetProgramiv(p, GL_LINK_STATUS, &ok);
|
||||||
if (!ok)
|
if (!ok) {
|
||||||
{
|
|
||||||
GLint len = 0;
|
GLint len = 0;
|
||||||
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &len);
|
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &len);
|
||||||
std::string log(len, ' ');
|
std::string log(len > 0 ? len : 1, ' ');
|
||||||
glGetProgramInfoLog(p, len, nullptr, &log[0]);
|
glGetProgramInfoLog(p, len, nullptr, &log[0]);
|
||||||
std::cerr << "Program link error: " << log << '\n';
|
Logger::error("Program link error: " + log);
|
||||||
glDeleteProgram(p);
|
glDeleteProgram(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
// --- Funciones basadas en tu código ---
|
||||||
{
|
void getDisplayInfo() {
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO))
|
int num_displays = 0;
|
||||||
{
|
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||||
std::cerr << "SDL_Init error: " << SDL_GetError() << '\n';
|
if (displays != nullptr && num_displays > 0) {
|
||||||
return -1;
|
for (int i = 0; i < num_displays; ++i) {
|
||||||
|
SDL_DisplayID instance_id = displays[i];
|
||||||
|
const char* name = SDL_GetDisplayName(instance_id);
|
||||||
|
Logger::info(std::string("Display ") + std::to_string(instance_id) + ": " + (name != nullptr ? name : "Unknown"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pedir contexto OpenGL 3.3 Core
|
const SDL_DisplayMode* dm = SDL_GetCurrentDisplayMode(displays[0]);
|
||||||
|
const char* first_display_name = SDL_GetDisplayName(displays[0]);
|
||||||
|
display_monitor_.name = (first_display_name != nullptr) ? first_display_name : "Unknown";
|
||||||
|
if (dm) {
|
||||||
|
display_monitor_.width = static_cast<int>(dm->w);
|
||||||
|
display_monitor_.height = static_cast<int>(dm->h);
|
||||||
|
display_monitor_.refresh_rate = static_cast<int>(dm->refresh_rate);
|
||||||
|
} else {
|
||||||
|
Logger::info("SDL_GetCurrentDisplayMode returned null");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger::info("No displays found or SDL_GetDisplays failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFullscreenMode() {
|
||||||
|
// SDL3: la API acepta un bool para fullscreen (true = fullscreen desktop / exclusive depending on param)
|
||||||
|
// En tu repos tienes Options::video.fullscreen (bool), así lo usamos:
|
||||||
|
if (!window_) return;
|
||||||
|
|
||||||
|
// Si se pide fullscreen = true, preferimos fullscreen exclusivo si se puede ajustar tamaño
|
||||||
|
if (Options_video.fullscreen) {
|
||||||
|
// Si conocemos la resolución nativa, forzamos tamaño de ventana y pedimos fullscreen exclusivo
|
||||||
|
if (display_monitor_.width > 0 && display_monitor_.height > 0) {
|
||||||
|
SDL_SetWindowSize(window_, display_monitor_.width, display_monitor_.height);
|
||||||
|
// SDL3 acepta SDL_SetWindowFullscreen(window, true) para fullscreen; algunos drivers pueden ofrecer exclusive/fullscreen desktop.
|
||||||
|
if (SDL_SetWindowFullscreen(window_, true) != 0) {
|
||||||
|
// fallback: intentar fullscreen desktop (true funciona como desktop fullscreen en muchas implementaciones)
|
||||||
|
Logger::info("SDL_SetWindowFullscreen(exclusive) failed, fallback to fullscreen desktop");
|
||||||
|
SDL_SetWindowFullscreen(window_, true); // ya es el mismo en SDL3; dejamos registro
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// desconocemos resolución, pedimos fullscreen desktop
|
||||||
|
SDL_SetWindowFullscreen(window_, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// volver a ventana
|
||||||
|
SDL_SetWindowFullscreen(window_, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleFullscreen() {
|
||||||
|
Options_video.fullscreen = !Options_video.fullscreen;
|
||||||
|
setFullscreenMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manejo de teclas de debug (adaptado a tu estilo)
|
||||||
|
void handleDebugEvents(const SDL_Event& event) {
|
||||||
|
// evitar repetición de teclas: event.key.repeat disponible en SDL3
|
||||||
|
if (event.type == SDL_EVENT_KEY_DOWN && static_cast<int>(event.key.repeat) == 0) {
|
||||||
|
switch (event.key.key) {
|
||||||
|
case SDLK_1: {
|
||||||
|
Logger::info("Key 1 pressed (action placeholder)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_2: {
|
||||||
|
static bool deploy_balloons_ = true;
|
||||||
|
deploy_balloons_ = !deploy_balloons_;
|
||||||
|
Logger::info(std::string("Toggle balloons: ") + (deploy_balloons_ ? "on" : "off"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_F11: {
|
||||||
|
toggleFullscreen();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- main (integra todo y soporta -F y argv[1] para shader path) ---
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
std::string shaderPath;
|
||||||
|
bool fullscreenFlag = false;
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
std::string a = argv[i];
|
||||||
|
if (a == "-F" || a == "--fullscreen") { fullscreenFlag = true; continue; }
|
||||||
|
if (shaderPath.empty()) shaderPath = a;
|
||||||
|
}
|
||||||
|
if (shaderPath.empty()) shaderPath = DEFAULT_FRAG;
|
||||||
|
Options_video.fullscreen = fullscreenFlag;
|
||||||
|
|
||||||
|
// Inicializar SDL3
|
||||||
|
auto initResult = SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
if constexpr (std::is_same_v<decltype(initResult), bool>) {
|
||||||
|
if (!initResult) { Logger::error(SDL_GetError()); return -1; }
|
||||||
|
} else {
|
||||||
|
if (initResult != 0) { Logger::error(SDL_GetError()); return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener información del display antes de crear ventana
|
||||||
|
getDisplayInfo();
|
||||||
|
|
||||||
|
// Atributos GL
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
|
||||||
|
// Crear ventana
|
||||||
int winW = 800, winH = 800;
|
int winW = 800, winH = 800;
|
||||||
// SDL3: SDL_CreateWindow signature es (title, w, h, flags)
|
window_ = SDL_CreateWindow("Shadertoy SDL3 + OpenGL", winW, winH, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||||
SDL_Window *window = SDL_CreateWindow("Shadertoy SDL3 + OpenGL",
|
if (!window_) { Logger::error(std::string("SDL_CreateWindow error: ") + SDL_GetError()); SDL_Quit(); return -1; }
|
||||||
winW, winH,
|
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
// Aplicar fullscreen si el flag estaba activado
|
||||||
if (!window)
|
setFullscreenMode();
|
||||||
{
|
|
||||||
std::cerr << "SDL_CreateWindow error: " << SDL_GetError() << '\n';
|
// Crear contexto GL
|
||||||
|
SDL_GLContext glContext = SDL_GL_CreateContext(window_);
|
||||||
|
if (!glContext) {
|
||||||
|
Logger::error(std::string("SDL_GL_CreateContext error: ") + SDL_GetError());
|
||||||
|
SDL_DestroyWindow(window_);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GLContext glContext = SDL_GL_CreateContext(window);
|
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||||
if (!glContext)
|
Logger::error("Failed to initialize GL loader");
|
||||||
{
|
|
||||||
std::cerr << "SDL_GL_CreateContext error: " << SDL_GetError() << '\n';
|
|
||||||
SDL_DestroyWindow(window);
|
|
||||||
SDL_Quit();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to initialize GL loader\n";
|
|
||||||
SDL_GL_DestroyContext(glContext);
|
SDL_GL_DestroyContext(glContext);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window_);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Localizar y cargar el fragment shader (intenta rutas comunes)
|
||||||
|
std::vector<std::filesystem::path> candidates;
|
||||||
|
candidates.emplace_back(shaderPath);
|
||||||
|
candidates.emplace_back(std::filesystem::path("..") / shaderPath);
|
||||||
|
candidates.emplace_back(std::filesystem::path(".") / shaderPath);
|
||||||
|
if (argc > 0 && argv[0]) {
|
||||||
|
std::filesystem::path exe = argv[0];
|
||||||
|
if (exe.has_parent_path()) {
|
||||||
|
candidates.emplace_back(exe.parent_path() / shaderPath);
|
||||||
|
candidates.emplace_back(exe.parent_path() / ".." / shaderPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fragSrc;
|
||||||
|
std::filesystem::path found;
|
||||||
|
for (auto &p : candidates) {
|
||||||
|
if (loadFileToString(p, fragSrc)) { found = p; break; }
|
||||||
|
}
|
||||||
|
if (found.empty()) {
|
||||||
|
Logger::error("Failed to load fragment shader file. Tried paths:");
|
||||||
|
for (auto &p : candidates) Logger::error(" " + p.string());
|
||||||
|
SDL_GL_DestroyContext(glContext);
|
||||||
|
SDL_DestroyWindow(window_);
|
||||||
|
SDL_Quit();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Logger::info("Loaded fragment shader from: " + found.string());
|
||||||
|
|
||||||
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
||||||
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
|
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragSrc.c_str());
|
||||||
if (!vs || !fs)
|
if (!vs || !fs) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
||||||
return -1;
|
|
||||||
GLuint program = linkProgram(vs, fs);
|
GLuint program = linkProgram(vs, fs);
|
||||||
glDeleteShader(vs);
|
glDeleteShader(vs);
|
||||||
glDeleteShader(fs);
|
glDeleteShader(fs);
|
||||||
if (!program)
|
if (!program) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
||||||
return -1;
|
|
||||||
|
|
||||||
|
// Quad setup
|
||||||
float quadVertices[] = {
|
float quadVertices[] = {
|
||||||
-1.0f,
|
-1.0f, -1.0f,
|
||||||
-1.0f,
|
1.0f, -1.0f,
|
||||||
1.0f,
|
-1.0f, 1.0f,
|
||||||
-1.0f,
|
1.0f, 1.0f,
|
||||||
-1.0f,
|
|
||||||
1.0f,
|
|
||||||
1.0f,
|
|
||||||
1.0f,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GLuint vao = 0, vbo = 0;
|
GLuint vao = 0, vbo = 0;
|
||||||
@@ -164,7 +279,7 @@ int main(int argc, char **argv)
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
@@ -174,28 +289,30 @@ int main(int argc, char **argv)
|
|||||||
bool running = true;
|
bool running = true;
|
||||||
Uint32 startTicks = SDL_GetTicks();
|
Uint32 startTicks = SDL_GetTicks();
|
||||||
|
|
||||||
while (running)
|
while (running) {
|
||||||
{
|
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
while (SDL_PollEvent(&e))
|
while (SDL_PollEvent(&e)) {
|
||||||
{
|
if (e.type == SDL_EVENT_QUIT) running = false;
|
||||||
if (e.type == SDL_EVENT_QUIT)
|
else if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) running = false;
|
||||||
running = false;
|
else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||||
if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
|
// Escape cierra la app
|
||||||
running = false;
|
if (e.key.key == SDLK_ESCAPE) running = false;
|
||||||
|
// handle your debug keys
|
||||||
|
handleDebugEvents(e);
|
||||||
|
} else if (e.type == SDL_EVENT_WINDOW_RESIZED) {
|
||||||
|
// opcional: podrías actualizar algo con new size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
SDL_GetWindowSize(window, &w, &h);
|
SDL_GetWindowSize(window_, &w, &h);
|
||||||
glViewport(0, 0, w, h);
|
glViewport(0, 0, w, h);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
if (locRes >= 0)
|
if (locRes >= 0) glUniform2f(locRes, float(w), float(h));
|
||||||
glUniform2f(locRes, float(w), float(h));
|
if (locTime >= 0) {
|
||||||
if (locTime >= 0)
|
|
||||||
{
|
|
||||||
float t = (SDL_GetTicks() - startTicks) / 1000.0f;
|
float t = (SDL_GetTicks() - startTicks) / 1000.0f;
|
||||||
glUniform1f(locTime, t);
|
glUniform1f(locTime, t);
|
||||||
}
|
}
|
||||||
@@ -204,16 +321,17 @@ int main(int argc, char **argv)
|
|||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window_);
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
glDeleteBuffers(1, &vbo);
|
glDeleteBuffers(1, &vbo);
|
||||||
glDeleteVertexArrays(1, &vao);
|
glDeleteVertexArrays(1, &vao);
|
||||||
glDeleteProgram(program);
|
glDeleteProgram(program);
|
||||||
|
|
||||||
SDL_GL_DestroyContext(glContext);
|
SDL_GL_DestroyContext(glContext);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window_);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user