afegits altres shaders

pantalla completa
tecla esc
readme.md
This commit is contained in:
2025-10-21 18:38:43 +02:00
parent bcaa64d22c
commit 4a339c09d1
7 changed files with 592 additions and 105 deletions

79
README.md Normal file
View 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.

View 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;
}

View 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;
}

View 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
View 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
View 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;
}

View File

@@ -1,11 +1,42 @@
// 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]
static const char *vertexShaderSrc = R"glsl(
// 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;
out vec2 vUV;
@@ -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"));
}
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; }
}
// Pedir contexto OpenGL 3.3 Core
// 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;
@@ -164,7 +279,7 @@ int main(int argc, char **argv)
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
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);
glBindVertexArray(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;
}