From 858d5045289eb030562b8ddd54af2ece483361ab Mon Sep 17 00:00:00 2001 From: klemek Date: Mon, 15 Sep 2025 11:39:29 +0200 Subject: [PATCH] working 6-stage fragments --- Makefile.dev | 2 +- README.md | 2 +- shaders/{frag.glsl => frag1.glsl} | 13 +++++- shaders/frag2.glsl | 19 +++++++++ shaders/frag3.glsl | 19 +++++++++ shaders/frag4.glsl | 19 +++++++++ shaders/frag5.glsl | 19 +++++++++ shaders/frag6.glsl | 19 +++++++++ src/args.c | 31 +++++++------- src/config.h | 8 ++-- src/forge.c | 38 +++++++++++------ src/shaders.c | 69 +++++++++++++++++-------------- src/shaders.h | 4 +- src/types.h | 18 ++++---- 14 files changed, 204 insertions(+), 76 deletions(-) rename shaders/{frag.glsl => frag1.glsl} (78%) create mode 100644 shaders/frag2.glsl create mode 100644 shaders/frag3.glsl create mode 100644 shaders/frag4.glsl create mode 100644 shaders/frag5.glsl create mode 100644 shaders/frag6.glsl diff --git a/Makefile.dev b/Makefile.dev index 0e16266..5c92869 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -18,7 +18,7 @@ build: -o build/$(TARGET) run: build - ./build/forge --hot-reload --frag=./shaders/frag.glsl + ./build/forge --hot-reload --frag=./shaders .PHONY: install install: build diff --git a/README.md b/README.md index cb02a8e..48aef30 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ make -f Makefile.dev release-arch - [x] Clean code - [ ] Multi-stage shaders - [x] Test 2 stages with render to texture - - [ ] 2 in 2 fx 1 mix 1 fx layout + - [x] 2 in 2 fx 1 mix 1 fx layout - [ ] Include fragments with special directive - [ ] 16 input + 16 fx definition and selection (with param) - [x] Feedback texture diff --git a/shaders/frag.glsl b/shaders/frag1.glsl similarity index 78% rename from shaders/frag.glsl rename to shaders/frag1.glsl index 9ae5d6b..8a7b979 100644 --- a/shaders/frag.glsl +++ b/shaders/frag1.glsl @@ -2,9 +2,18 @@ uniform float iTime; uniform vec2 iResolution; -in vec2 vUV; -layout(location = 0) out vec3 fragColor; + uniform sampler2D frame0; +uniform sampler2D frame1; + +in vec2 vUV; +layout(location = 3) out vec3 fragColor; + + +// SRC A +// --------- +// IN: 0 / 1 +// OUT: 3 void main() { vec2 uv0 = vUV.st; diff --git a/shaders/frag2.glsl b/shaders/frag2.glsl new file mode 100644 index 0000000..abfe8f7 --- /dev/null +++ b/shaders/frag2.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame0; +uniform sampler2D frame2; + +in vec2 vUV; +layout(location = 4) out vec3 fragColor; + +// SRC B +// --------- +// IN: 0 / 2 +// OUT: 4 + +void main() { + fragColor = vec3(vUV, 0.0) * step(0.3, vUV.x) * step(-0.4, -vUV.x); +} \ No newline at end of file diff --git a/shaders/frag3.glsl b/shaders/frag3.glsl new file mode 100644 index 0000000..1234a95 --- /dev/null +++ b/shaders/frag3.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame3; +uniform sampler2D frame5; + +in vec2 vUV; +layout(location = 5) out vec3 fragColor; + +// FX A +// --------- +// IN: 3 / 5 +// OUT: 5 + +void main() { + fragColor = texture(frame3, vUV).xyz; +} \ No newline at end of file diff --git a/shaders/frag4.glsl b/shaders/frag4.glsl new file mode 100644 index 0000000..a92774c --- /dev/null +++ b/shaders/frag4.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame4; +uniform sampler2D frame6; + +in vec2 vUV; +layout(location = 6) out vec3 fragColor; + +// FX B +// --------- +// IN: 4 / 6 +// OUT: 6 + +void main() { + fragColor = texture(frame4, vUV).xyz; +} \ No newline at end of file diff --git a/shaders/frag5.glsl b/shaders/frag5.glsl new file mode 100644 index 0000000..4a37d53 --- /dev/null +++ b/shaders/frag5.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame5; +uniform sampler2D frame6; + +in vec2 vUV; +layout(location = 7) out vec3 fragColor; + +// A+B +// --------- +// IN: 5 / 6 +// OUT: 7 + +void main() { + fragColor = texture(frame5, vUV).xyz + texture(frame6, vUV).xyz; +} \ No newline at end of file diff --git a/shaders/frag6.glsl b/shaders/frag6.glsl new file mode 100644 index 0000000..7f89091 --- /dev/null +++ b/shaders/frag6.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame7; +uniform sampler2D frame0; + +in vec2 vUV; +layout(location = 0) out vec3 fragColor; + +// MFX +// --------- +// IN: 7 / 0 +// OUT: 0 + +void main() { + fragColor = texture(frame7, vUV).xyz; +} \ No newline at end of file diff --git a/src/args.c b/src/args.c index 17708c2..d20cc56 100644 --- a/src/args.c +++ b/src/args.c @@ -8,21 +8,22 @@ #include "logs.h" void print_help(int status_code) { - puts(PACKAGE " " VERSION "\n\n" - "usage: " PACKAGE " " - "[-h] " - "[-v] " - "[-hr] " - "[-s=SCREEN] " - "[-f=FRAG_PATH] " - "\n\n" - "Fusion Of Real-time Generative Effects.\n\n" - "options:\n" - " -h, --help show this help message and exit\n" - " -v, --version print version\n" - " -hr, --hot-reload hot reload of shaders scripts\n" - " -s, --screen output screen number (default: primary)\n" - " -f, --frag fragment shader path (default: TODO)\n"); + puts(PACKAGE + " " VERSION "\n\n" + "usage: " PACKAGE " " + "[-h] " + "[-v] " + "[-hr] " + "[-s=SCREEN] " + "[-f=DIR_PATH] " + "\n\n" + "Fusion Of Real-time Generative Effects.\n\n" + "options:\n" + " -h, --help show this help message and exit\n" + " -v, --version print version\n" + " -hr, --hot-reload hot reload of shaders scripts\n" + " -s, --screen output screen number (default: primary)\n" + " -f, --frag fragment shaders directory (default: TODO)\n"); exit(status_code); } diff --git a/src/config.h b/src/config.h index 0d1990b..e81abb5 100644 --- a/src/config.h +++ b/src/config.h @@ -9,12 +9,12 @@ #define VERSION "(dev)" #endif -#ifndef FRAMEBUFFER_COUNT -#define FRAMEBUFFER_COUNT 7 +#ifndef FRAG_COUNT +#define FRAG_COUNT 6 #endif -#ifndef TEXTURE_COUNT -#define TEXTURE_COUNT 8 +#ifndef TEX_COUNT +#define TEX_COUNT 8 #endif #endif \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 0636823..2aae68f 100644 --- a/src/forge.c +++ b/src/forge.c @@ -37,14 +37,20 @@ void compute_fps(Window *window, Timer *timer) { } void loop(Window *window, ShaderProgram program, bool hot_reload, - File *fragment_shader, Timer *timer) { + File *fragment_shaders, Timer *timer) { Context context; + int i; compute_fps(window, timer); - if (hot_reload && should_update_file(*fragment_shader)) { - update_file(fragment_shader); - update_program(program, *fragment_shader); + if (hot_reload) { + // TODO extract to function + for (i = 0; i < FRAG_COUNT; i++) { + if (should_update_file(fragment_shaders[i])) { + update_file(&fragment_shaders[i]); + update_program(program, fragment_shaders, i); + } + } } context = get_window_context(window); @@ -55,16 +61,21 @@ void loop(Window *window, ShaderProgram program, bool hot_reload, } void forge_run(Parameters params) { - File fragment_shader; + File fragment_shaders[FRAG_COUNT]; ShaderProgram program; Window *window; Timer timer; Context context; + int i; + char file_path[FRAG_COUNT][1024]; - fragment_shader = read_file(params.frag_path); - - if (fragment_shader.error) { - exit(EXIT_FAILURE); + // TODO extract to function + for (i = 0; i < FRAG_COUNT; i++) { + sprintf(file_path[i], "%s/frag%d.glsl", params.frag_path, i + 1); + fragment_shaders[i] = read_file(file_path[i]); + if (fragment_shaders[i].error) { + exit(EXIT_FAILURE); + } } window = init_window(PACKAGE " " VERSION, params.screen, error_callback, @@ -72,7 +83,7 @@ void forge_run(Parameters params) { context = get_window_context(window); - program = init_program(fragment_shader, context); + program = init_program(fragment_shaders, context); if (program.error) { close_window(window, true); @@ -82,10 +93,13 @@ void forge_run(Parameters params) { timer = create_timer(60); while (!window_should_close(window)) { - loop(window, program, params.hot_reload, &fragment_shader, &timer); + loop(window, program, params.hot_reload, fragment_shaders, &timer); } close_window(window, true); - free_file(&fragment_shader); + // TODO extract to function + for (i = 0; i < FRAG_COUNT; i++) { + free_file(&fragment_shaders[i]); + } } \ No newline at end of file diff --git a/src/shaders.c b/src/shaders.c index f4935a4..447bb60 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -35,9 +35,9 @@ bool compile_shader(GLuint shader_id, char *name, char *source_code) { void init_textures(ShaderProgram *program, Context context) { int i; - glGenTextures(TEXTURE_COUNT, program->textures); + glGenTextures(TEX_COUNT, program->textures); - for (i = 0; i < TEXTURE_COUNT; i++) { + for (i = 0; i < TEX_COUNT; i++) { // selects which texture unit subsequent texture state calls will affect glActiveTexture(GL_TEXTURE0 + i); @@ -58,12 +58,12 @@ void init_textures(ShaderProgram *program, Context context) { void init_framebuffers(ShaderProgram *program) { int i, j; - glGenFramebuffers(FRAMEBUFFER_COUNT, program->frame_buffers); + glGenFramebuffers(FRAG_COUNT, program->frame_buffers); - for (i = 0; i < FRAMEBUFFER_COUNT; i++) { + for (i = 0; i < FRAG_COUNT; i++) { glBindFramebuffer(GL_FRAMEBUFFER, program->frame_buffers[i]); - for (j = 0; j < TEXTURE_COUNT; j++) { + for (j = 0; j < TEX_COUNT; j++) { // attaches a selected mipmap level or image of a texture object as one of // the logical buffers of the framebuffer object glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + j, @@ -97,7 +97,9 @@ void init_vertices(ShaderProgram *program) { glBindVertexArray(program->vertex_array); } -void init_shaders(ShaderProgram *program, File fragment_shader) { +void init_shaders(ShaderProgram *program, File *fragment_shaders) { + int i; + // compile vertex shader program->vertex_shader = glCreateShader(GL_VERTEX_SHADER); program->error |= !compile_shader( @@ -109,10 +111,13 @@ void init_shaders(ShaderProgram *program, File fragment_shader) { !compile_shader(program->output_fragment_shader, "internal fragment shader", output_fragment_shader_text); - // compile fragment shader - program->fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - program->error |= !compile_shader( - program->fragment_shader, fragment_shader.path, fragment_shader.content); + // compile fragment shaders + for (i = 0; i < FRAG_COUNT; i++) { + program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER); + program->error |= + !compile_shader(program->fragment_shaders[i], fragment_shaders[i].path, + fragment_shaders[i].content); + } } void init_single_program(ShaderProgram *program, int i, bool output) { @@ -126,8 +131,7 @@ void init_single_program(ShaderProgram *program, int i, bool output) { if (output) { glAttachShader(program->programs[i], program->output_fragment_shader); } else { - // TODO add others - glAttachShader(program->programs[i], program->fragment_shader); + glAttachShader(program->programs[i], program->fragment_shaders[i]); } glLinkProgram(program->programs[i]); @@ -141,7 +145,7 @@ void init_single_program(ShaderProgram *program, int i, bool output) { } // create frameX uniforms pointer - for (j = 0; j < TEXTURE_COUNT; j++) { + for (j = 0; j < TEX_COUNT; j++) { sprintf(uniform_name, "frame%d", j); program->frames_locations[i][j] = glGetUniformLocation(program->programs[i], uniform_name); @@ -157,10 +161,10 @@ void init_single_program(ShaderProgram *program, int i, bool output) { glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, pos)); - log_success("Program %d initialized", i); + log_success("Program %d initialized", i + 1); } -ShaderProgram init_program(File fragment_shader, Context context) { +ShaderProgram init_program(File *fragment_shaders, Context context) { int i; ShaderProgram program = {.error = false, .last_width = context.width, @@ -170,7 +174,7 @@ ShaderProgram init_program(File fragment_shader, Context context) { init_framebuffers(&program); - init_shaders(&program, fragment_shader); + init_shaders(&program, fragment_shaders); if (program.error) { return program; @@ -179,27 +183,28 @@ ShaderProgram init_program(File fragment_shader, Context context) { init_vertices(&program); // create and link full shader programs - for (i = 0; i < FRAMEBUFFER_COUNT + 1; i++) { - init_single_program(&program, i, i == FRAMEBUFFER_COUNT); + for (i = 0; i < FRAG_COUNT + 1; i++) { + init_single_program(&program, i, i == FRAG_COUNT); + } + + // TODO functions + for (i = 0; i < TEX_COUNT; i++) { + program.draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; } return program; } -void update_program(ShaderProgram program, File fragment_shader) { +void update_program(ShaderProgram program, File *fragment_shaders, int i) { bool result; - int i; - result = compile_shader(program.fragment_shader, fragment_shader.path, - fragment_shader.content); + result = compile_shader(program.fragment_shaders[i], fragment_shaders[i].path, + fragment_shaders[i].content); if (result) { - // re-link all programs - for (i = 0; i < FRAMEBUFFER_COUNT; i++) { - glLinkProgram(program.programs[i]); - } + glLinkProgram(program.programs[i]); - log_success("Programs updated"); + log_success("Program %d updated", i + 1); } } @@ -213,7 +218,7 @@ void apply_program(ShaderProgram program, Context context) { glViewport(0, 0, context.width, context.height); // clean and resize all textures - for (i = 0; i < TEXTURE_COUNT; i++) { + for (i = 0; i < TEX_COUNT; i++) { glActiveTexture(GL_TEXTURE0 + i); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -222,11 +227,11 @@ void apply_program(ShaderProgram program, Context context) { vec2 resolution = {(float)context.width, (float)context.height}; - for (i = 0; i < FRAMEBUFFER_COUNT + 1; i++) { + for (i = 0; i < FRAG_COUNT + 1; i++) { // use specific shader program glUseProgram(program.programs[i]); - if (i == FRAMEBUFFER_COUNT) { + if (i == FRAG_COUNT) { // use default framebuffer (output) glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -242,10 +247,12 @@ void apply_program(ShaderProgram program, Context context) { } // set GL_TEXTURE(X) to uniform sampler2D frameX - for (j = 0; j < FRAMEBUFFER_COUNT; j++) { + for (j = 0; j < TEX_COUNT; j++) { glUniform1i(program.frames_locations[i][j], j); } + glDrawBuffers(TEX_COUNT, program.draw_buffers); + // draw output glDrawArrays(GL_TRIANGLES, 0, 6); } diff --git a/src/shaders.h b/src/shaders.h index 3c75a09..71fd996 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -3,9 +3,9 @@ #ifndef SHADERS_H #define SHADERS_H -ShaderProgram init_program(File fragment_shader, Context context); +ShaderProgram init_program(File *fragment_shader, Context context); -void update_program(ShaderProgram program, File fragment_shader); +void update_program(ShaderProgram program, File *fragment_shaders, int i); void apply_program(ShaderProgram program, Context context); diff --git a/src/types.h b/src/types.h index bb5f859..db49c28 100644 --- a/src/types.h +++ b/src/types.h @@ -33,23 +33,25 @@ typedef struct ShaderProgram { int last_width; int last_height; - GLuint programs[FRAMEBUFFER_COUNT + 1]; + GLuint programs[FRAG_COUNT + 1]; GLuint vertex_shader; GLuint output_fragment_shader; - GLuint fragment_shader; // TODO multiple + GLuint fragment_shaders[FRAG_COUNT]; - GLuint itime_locations[FRAMEBUFFER_COUNT]; - GLuint ires_locations[FRAMEBUFFER_COUNT]; - GLuint frames_locations[FRAMEBUFFER_COUNT + 1][FRAMEBUFFER_COUNT]; - GLuint vpos_locations[FRAMEBUFFER_COUNT + 1]; + GLuint itime_locations[FRAG_COUNT]; + GLuint ires_locations[FRAG_COUNT]; + GLuint frames_locations[FRAG_COUNT + 1][TEX_COUNT]; + GLuint vpos_locations[FRAG_COUNT + 1]; GLuint vertex_buffer; GLuint vertex_array; - GLuint frame_buffers[FRAMEBUFFER_COUNT]; - GLuint textures[FRAMEBUFFER_COUNT]; + GLuint frame_buffers[FRAG_COUNT]; + GLuint textures[TEX_COUNT]; + + GLenum draw_buffers[TEX_COUNT]; } ShaderProgram; typedef GLFWwindow Window;