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;
|
||||
}
|
||||
324
src/main.cpp
324
src/main.cpp
@@ -1,10 +1,41 @@
|
||||
// src/main.cpp
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <filesystem>
|
||||
#include <SDL3/SDL.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
|
||||
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
|
||||
layout(location = 0) in vec2 aPos;
|
||||
@@ -15,146 +46,230 @@ void main() {
|
||||
}
|
||||
)glsl";
|
||||
|
||||
// Fragment shader: adapta tu shader de Shadertoy
|
||||
static const char *fragmentShaderSrc = R"glsl(
|
||||
#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) );
|
||||
// Helpers de carga
|
||||
static bool loadFileToString(const std::filesystem::path& path, std::string& out) {
|
||||
std::ifstream ifs(path, std::ios::in | std::ios::binary);
|
||||
if (!ifs) return false;
|
||||
std::ostringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
out = ss.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
)glsl";
|
||||
|
||||
// helpers
|
||||
static GLuint compileShader(GLenum type, const char *src)
|
||||
{
|
||||
static GLuint compileShader(GLenum type, const char* src) {
|
||||
GLuint s = glCreateShader(type);
|
||||
glShaderSource(s, 1, &src, nullptr);
|
||||
glCompileShader(s);
|
||||
GLint ok = 0;
|
||||
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!ok) {
|
||||
GLint len = 0;
|
||||
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
|
||||
std::string log(len, ' ');
|
||||
std::string log(len > 0 ? len : 1, ' ');
|
||||
glGetShaderInfoLog(s, len, nullptr, &log[0]);
|
||||
std::cerr << "Shader compile error: " << log << '\n';
|
||||
Logger::error("Shader compile error: " + log);
|
||||
glDeleteShader(s);
|
||||
return 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static GLuint linkProgram(GLuint vs, GLuint fs)
|
||||
{
|
||||
static GLuint linkProgram(GLuint vs, GLuint fs) {
|
||||
GLuint p = glCreateProgram();
|
||||
glAttachShader(p, vs);
|
||||
glAttachShader(p, fs);
|
||||
glLinkProgram(p);
|
||||
GLint ok = 0;
|
||||
glGetProgramiv(p, GL_LINK_STATUS, &ok);
|
||||
if (!ok)
|
||||
{
|
||||
if (!ok) {
|
||||
GLint len = 0;
|
||||
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &len);
|
||||
std::string log(len, ' ');
|
||||
std::string log(len > 0 ? len : 1, ' ');
|
||||
glGetProgramInfoLog(p, len, nullptr, &log[0]);
|
||||
std::cerr << "Program link error: " << log << '\n';
|
||||
Logger::error("Program link error: " + log);
|
||||
glDeleteProgram(p);
|
||||
return 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (!SDL_Init(SDL_INIT_VIDEO))
|
||||
{
|
||||
std::cerr << "SDL_Init error: " << SDL_GetError() << '\n';
|
||||
return -1;
|
||||
// --- Funciones basadas en tu código ---
|
||||
void getDisplayInfo() {
|
||||
int num_displays = 0;
|
||||
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||
if (displays != nullptr && num_displays > 0) {
|
||||
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_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
// Crear ventana
|
||||
int winW = 800, winH = 800;
|
||||
// SDL3: SDL_CreateWindow signature es (title, w, h, flags)
|
||||
SDL_Window *window = SDL_CreateWindow("Shadertoy SDL3 + OpenGL",
|
||||
winW, winH,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
if (!window)
|
||||
{
|
||||
std::cerr << "SDL_CreateWindow error: " << SDL_GetError() << '\n';
|
||||
window_ = SDL_CreateWindow("Shadertoy SDL3 + OpenGL", winW, winH, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
if (!window_) { Logger::error(std::string("SDL_CreateWindow error: ") + SDL_GetError()); SDL_Quit(); return -1; }
|
||||
|
||||
// Aplicar fullscreen si el flag estaba activado
|
||||
setFullscreenMode();
|
||||
|
||||
// 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();
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_GLContext glContext = SDL_GL_CreateContext(window);
|
||||
if (!glContext)
|
||||
{
|
||||
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";
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
Logger::error("Failed to initialize GL loader");
|
||||
SDL_GL_DestroyContext(glContext);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_DestroyWindow(window_);
|
||||
SDL_Quit();
|
||||
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 fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
|
||||
if (!vs || !fs)
|
||||
return -1;
|
||||
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragSrc.c_str());
|
||||
if (!vs || !fs) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
||||
GLuint program = linkProgram(vs, fs);
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
if (!program)
|
||||
return -1;
|
||||
if (!program) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
||||
|
||||
// Quad setup
|
||||
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;
|
||||
@@ -174,28 +289,30 @@ int main(int argc, char **argv)
|
||||
bool running = true;
|
||||
Uint32 startTicks = SDL_GetTicks();
|
||||
|
||||
while (running)
|
||||
{
|
||||
while (running) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e))
|
||||
{
|
||||
if (e.type == SDL_EVENT_QUIT)
|
||||
running = false;
|
||||
if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
|
||||
running = false;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_EVENT_QUIT) running = false;
|
||||
else if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) running = false;
|
||||
else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||
// Escape cierra la app
|
||||
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;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
SDL_GetWindowSize(window_, &w, &h);
|
||||
glViewport(0, 0, w, h);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glUseProgram(program);
|
||||
if (locRes >= 0)
|
||||
glUniform2f(locRes, float(w), float(h));
|
||||
if (locTime >= 0)
|
||||
{
|
||||
if (locRes >= 0) glUniform2f(locRes, float(w), float(h));
|
||||
if (locTime >= 0) {
|
||||
float t = (SDL_GetTicks() - startTicks) / 1000.0f;
|
||||
glUniform1f(locTime, t);
|
||||
}
|
||||
@@ -204,16 +321,17 @@ int main(int argc, char **argv)
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
|
||||
SDL_GL_SwapWindow(window);
|
||||
SDL_GL_SwapWindow(window_);
|
||||
SDL_Delay(1);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteProgram(program);
|
||||
|
||||
SDL_GL_DestroyContext(glContext);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_DestroyWindow(window_);
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user