canvis de shaders al vol amb els cursors
This commit is contained in:
12
src/defines.hpp
Normal file
12
src/defines.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Nombre de la aplicación
|
||||||
|
constexpr const char* APP_NAME = "Shadertoy";
|
||||||
|
|
||||||
|
// Tamaño de ventana por defecto
|
||||||
|
constexpr int WINDOW_WIDTH = 800;
|
||||||
|
constexpr int WINDOW_HEIGHT = 800;
|
||||||
|
|
||||||
|
// Rutas
|
||||||
|
constexpr const char* SHADERS_FOLDER = "shaders";
|
||||||
|
constexpr const char* DEFAULT_SHADER = "shaders/test.frag.glsl";
|
||||||
226
src/main.cpp
226
src/main.cpp
@@ -4,11 +4,14 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#include "defines.hpp"
|
||||||
|
|
||||||
// Simple logger compatible con el estilo que usas
|
// Simple logger compatible con el estilo que usas
|
||||||
struct Logger {
|
struct Logger {
|
||||||
static void info(const std::string& s) { std::cout << "[INFO] " << s << '\n'; }
|
static void info(const std::string& s) { std::cout << "[INFO] " << s << '\n'; }
|
||||||
@@ -32,12 +35,12 @@ struct DisplayMonitor {
|
|||||||
static DisplayMonitor display_monitor_;
|
static DisplayMonitor display_monitor_;
|
||||||
static SDL_Window* window_ = nullptr;
|
static SDL_Window* window_ = nullptr;
|
||||||
|
|
||||||
// Constante por defecto del fragment shader
|
// Sistema de shaders
|
||||||
static constexpr const char* DEFAULT_FRAG = "shaders/test.frag.glsl";
|
static std::vector<std::filesystem::path> shader_list_;
|
||||||
|
static size_t current_shader_index_ = 0;
|
||||||
// Tamaño de ventana por defecto
|
static std::filesystem::path shaders_directory_;
|
||||||
static constexpr int WINDOW_WIDTH = 800;
|
static GLuint current_program_ = 0;
|
||||||
static constexpr int WINDOW_HEIGHT = 800;
|
static Uint32 shader_start_ticks_ = 0;
|
||||||
|
|
||||||
// Vertex shader embebido
|
// Vertex shader embebido
|
||||||
static const char* vertexShaderSrc = R"glsl(
|
static const char* vertexShaderSrc = R"glsl(
|
||||||
@@ -60,6 +63,38 @@ static bool loadFileToString(const std::filesystem::path& path, std::string& out
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::filesystem::path> scanShaderDirectory(const std::filesystem::path& directory) {
|
||||||
|
std::vector<std::filesystem::path> shaders;
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(directory) || !std::filesystem::is_directory(directory)) {
|
||||||
|
Logger::error("Shader directory does not exist: " + directory.string());
|
||||||
|
return shaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
|
||||||
|
if (entry.is_regular_file()) {
|
||||||
|
auto ext = entry.path().extension().string();
|
||||||
|
if (ext == ".glsl") {
|
||||||
|
shaders.push_back(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordenar alfabéticamente
|
||||||
|
std::sort(shaders.begin(), shaders.end());
|
||||||
|
|
||||||
|
Logger::info("Found " + std::to_string(shaders.size()) + " shader(s) in " + directory.string());
|
||||||
|
return shaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateWindowTitle() {
|
||||||
|
if (!window_ || shader_list_.empty()) return;
|
||||||
|
|
||||||
|
std::string filename = shader_list_[current_shader_index_].filename().string();
|
||||||
|
std::string title = std::string(APP_NAME) + " (" + filename + ")";
|
||||||
|
SDL_SetWindowTitle(window_, title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
static GLuint compileShader(GLenum type, const char* src) {
|
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);
|
||||||
@@ -97,6 +132,44 @@ static GLuint linkProgram(GLuint vs, GLuint fs) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GLuint loadAndCompileShader(size_t index) {
|
||||||
|
if (index >= shader_list_.size()) {
|
||||||
|
Logger::error("Invalid shader index: " + std::to_string(index));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& shaderPath = shader_list_[index];
|
||||||
|
Logger::info("Loading shader: " + shaderPath.string());
|
||||||
|
|
||||||
|
std::string fragSrc;
|
||||||
|
if (!loadFileToString(shaderPath, fragSrc)) {
|
||||||
|
Logger::error("Failed to load shader file: " + shaderPath.string());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
||||||
|
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragSrc.c_str());
|
||||||
|
|
||||||
|
if (!vs || !fs) {
|
||||||
|
if (vs) glDeleteShader(vs);
|
||||||
|
if (fs) glDeleteShader(fs);
|
||||||
|
Logger::error("Shader compilation failed for: " + shaderPath.string());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint program = linkProgram(vs, fs);
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
|
||||||
|
if (!program) {
|
||||||
|
Logger::error("Program linking failed for: " + shaderPath.string());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::info("Shader loaded successfully: " + shaderPath.filename().string());
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
// --- Funciones basadas en tu código ---
|
// --- Funciones basadas en tu código ---
|
||||||
void getDisplayInfo() {
|
void getDisplayInfo() {
|
||||||
int num_displays = 0;
|
int num_displays = 0;
|
||||||
@@ -148,6 +221,36 @@ void toggleFullscreen() {
|
|||||||
setFullscreenMode();
|
setFullscreenMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void switchShader(int direction) {
|
||||||
|
if (shader_list_.empty()) return;
|
||||||
|
|
||||||
|
// Calcular nuevo índice con wrap-around cíclico
|
||||||
|
size_t new_index = current_shader_index_;
|
||||||
|
if (direction > 0) {
|
||||||
|
new_index = (current_shader_index_ + 1) % shader_list_.size();
|
||||||
|
} else if (direction < 0) {
|
||||||
|
new_index = (current_shader_index_ == 0) ? shader_list_.size() - 1 : current_shader_index_ - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentar cargar el nuevo shader
|
||||||
|
GLuint new_program = loadAndCompileShader(new_index);
|
||||||
|
if (new_program == 0) {
|
||||||
|
Logger::error("Failed to switch shader, keeping current one");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Éxito: eliminar programa anterior y actualizar
|
||||||
|
if (current_program_ != 0) {
|
||||||
|
glDeleteProgram(current_program_);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_program_ = new_program;
|
||||||
|
current_shader_index_ = new_index;
|
||||||
|
shader_start_ticks_ = SDL_GetTicks();
|
||||||
|
|
||||||
|
updateWindowTitle();
|
||||||
|
}
|
||||||
|
|
||||||
// Manejo de teclas
|
// Manejo de teclas
|
||||||
void handleDebugEvents(const SDL_Event& event) {
|
void handleDebugEvents(const SDL_Event& event) {
|
||||||
// evitar repetición de teclas: event.key.repeat disponible en SDL3
|
// evitar repetición de teclas: event.key.repeat disponible en SDL3
|
||||||
@@ -157,6 +260,14 @@ void handleDebugEvents(const SDL_Event& event) {
|
|||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SDLK_LEFT: {
|
||||||
|
switchShader(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDLK_RIGHT: {
|
||||||
|
switchShader(+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -172,7 +283,7 @@ int main(int argc, char** argv) {
|
|||||||
if (a == "-F" || a == "--fullscreen") { fullscreenFlag = true; continue; }
|
if (a == "-F" || a == "--fullscreen") { fullscreenFlag = true; continue; }
|
||||||
if (shaderPath.empty()) shaderPath = a;
|
if (shaderPath.empty()) shaderPath = a;
|
||||||
}
|
}
|
||||||
if (shaderPath.empty()) shaderPath = DEFAULT_FRAG;
|
if (shaderPath.empty()) shaderPath = DEFAULT_SHADER;
|
||||||
Options_video.fullscreen = fullscreenFlag;
|
Options_video.fullscreen = fullscreenFlag;
|
||||||
|
|
||||||
// Inicializar SDL3
|
// Inicializar SDL3
|
||||||
@@ -192,7 +303,7 @@ int main(int argc, char** argv) {
|
|||||||
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
|
// Crear ventana
|
||||||
window_ = SDL_CreateWindow("Shadertoy SDL3 + OpenGL", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
window_ = SDL_CreateWindow(APP_NAME, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||||
if (!window_) { Logger::error(std::string("SDL_CreateWindow error: ") + SDL_GetError()); SDL_Quit(); return -1; }
|
if (!window_) { Logger::error(std::string("SDL_CreateWindow error: ") + SDL_GetError()); SDL_Quit(); return -1; }
|
||||||
|
|
||||||
// Aplicar fullscreen si el flag estaba activado
|
// Aplicar fullscreen si el flag estaba activado
|
||||||
@@ -215,41 +326,69 @@ int main(int argc, char** argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localizar y cargar el fragment shader (intenta rutas comunes)
|
// Determinar carpeta de shaders
|
||||||
std::vector<std::filesystem::path> candidates;
|
std::filesystem::path shaderFile(shaderPath);
|
||||||
candidates.emplace_back(shaderPath);
|
if (shaderFile.has_parent_path()) {
|
||||||
candidates.emplace_back(std::filesystem::path("..") / shaderPath);
|
shaders_directory_ = shaderFile.parent_path();
|
||||||
candidates.emplace_back(std::filesystem::path(".") / shaderPath);
|
} else {
|
||||||
if (argc > 0 && argv[0]) {
|
shaders_directory_ = SHADERS_FOLDER;
|
||||||
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;
|
// Escanear carpeta de shaders
|
||||||
std::filesystem::path found;
|
shader_list_ = scanShaderDirectory(shaders_directory_);
|
||||||
for (auto &p : candidates) {
|
if (shader_list_.empty()) {
|
||||||
if (loadFileToString(p, fragSrc)) { found = p; break; }
|
Logger::error("No shaders found in directory: " + shaders_directory_.string());
|
||||||
}
|
|
||||||
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_GL_DestroyContext(glContext);
|
||||||
SDL_DestroyWindow(window_);
|
SDL_DestroyWindow(window_);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Logger::info("Loaded fragment shader from: " + found.string());
|
|
||||||
|
|
||||||
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc);
|
// Determinar shader inicial
|
||||||
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragSrc.c_str());
|
size_t initial_index = 0;
|
||||||
if (!vs || !fs) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
bool found_shader = false;
|
||||||
GLuint program = linkProgram(vs, fs);
|
|
||||||
glDeleteShader(vs);
|
// Intentar encontrar el shader especificado
|
||||||
glDeleteShader(fs);
|
std::filesystem::path target_shader = shaderFile.has_parent_path() ? shaderFile : (shaders_directory_ / shaderFile.filename());
|
||||||
if (!program) { SDL_GL_DestroyContext(glContext); SDL_DestroyWindow(window_); SDL_Quit(); return -1; }
|
for (size_t i = 0; i < shader_list_.size(); ++i) {
|
||||||
|
if (shader_list_[i] == target_shader) {
|
||||||
|
initial_index = i;
|
||||||
|
found_shader = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no se encuentra, intentar con DEFAULT_SHADER
|
||||||
|
if (!found_shader) {
|
||||||
|
std::filesystem::path default_path(DEFAULT_SHADER);
|
||||||
|
for (size_t i = 0; i < shader_list_.size(); ++i) {
|
||||||
|
if (shader_list_[i] == default_path) {
|
||||||
|
initial_index = i;
|
||||||
|
found_shader = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si aún no se encuentra, usar el primer shader de la lista
|
||||||
|
if (!found_shader) {
|
||||||
|
Logger::info("Specified shader not found, using first shader in directory");
|
||||||
|
initial_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cargar shader inicial
|
||||||
|
current_shader_index_ = initial_index;
|
||||||
|
current_program_ = loadAndCompileShader(current_shader_index_);
|
||||||
|
if (current_program_ == 0) {
|
||||||
|
Logger::error("Failed to load initial shader");
|
||||||
|
SDL_GL_DestroyContext(glContext);
|
||||||
|
SDL_DestroyWindow(window_);
|
||||||
|
SDL_Quit();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_start_ticks_ = SDL_GetTicks();
|
||||||
|
updateWindowTitle();
|
||||||
|
|
||||||
// Quad setup
|
// Quad setup
|
||||||
float quadVertices[] = {
|
float quadVertices[] = {
|
||||||
@@ -270,11 +409,7 @@ int main(int argc, char** argv) {
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
GLint locRes = glGetUniformLocation(program, "iResolution");
|
|
||||||
GLint locTime = glGetUniformLocation(program, "iTime");
|
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
Uint32 startTicks = SDL_GetTicks();
|
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
@@ -297,10 +432,15 @@ int main(int argc, char** argv) {
|
|||||||
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(current_program_);
|
||||||
|
|
||||||
|
// Obtener uniform locations (se recalculan porque el shader puede cambiar)
|
||||||
|
GLint locRes = glGetUniformLocation(current_program_, "iResolution");
|
||||||
|
GLint locTime = glGetUniformLocation(current_program_, "iTime");
|
||||||
|
|
||||||
if (locRes >= 0) glUniform2f(locRes, float(w), float(h));
|
if (locRes >= 0) glUniform2f(locRes, float(w), float(h));
|
||||||
if (locTime >= 0) {
|
if (locTime >= 0) {
|
||||||
float t = (SDL_GetTicks() - startTicks) / 1000.0f;
|
float t = (SDL_GetTicks() - shader_start_ticks_) / 1000.0f;
|
||||||
glUniform1f(locTime, t);
|
glUniform1f(locTime, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +455,9 @@ int main(int argc, char** argv) {
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
glDeleteBuffers(1, &vbo);
|
glDeleteBuffers(1, &vbo);
|
||||||
glDeleteVertexArrays(1, &vao);
|
glDeleteVertexArrays(1, &vao);
|
||||||
glDeleteProgram(program);
|
if (current_program_ != 0) {
|
||||||
|
glDeleteProgram(current_program_);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GL_DestroyContext(glContext);
|
SDL_GL_DestroyContext(glContext);
|
||||||
SDL_DestroyWindow(window_);
|
SDL_DestroyWindow(window_);
|
||||||
|
|||||||
Reference in New Issue
Block a user