working 6-stage fragments

This commit is contained in:
2025-09-15 11:39:29 +02:00
parent bfd1abcac7
commit 858d504528
14 changed files with 204 additions and 76 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ build:
-o build/$(TARGET) -o build/$(TARGET)
run: build run: build
./build/forge --hot-reload --frag=./shaders/frag.glsl ./build/forge --hot-reload --frag=./shaders
.PHONY: install .PHONY: install
install: build install: build
+1 -1
View File
@@ -101,7 +101,7 @@ make -f Makefile.dev release-arch
- [x] Clean code - [x] Clean code
- [ ] Multi-stage shaders - [ ] Multi-stage shaders
- [x] Test 2 stages with render to texture - [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 - [ ] Include fragments with special directive
- [ ] 16 input + 16 fx definition and selection (with param) - [ ] 16 input + 16 fx definition and selection (with param)
- [x] Feedback texture - [x] Feedback texture
+11 -2
View File
@@ -2,9 +2,18 @@
uniform float iTime; uniform float iTime;
uniform vec2 iResolution; uniform vec2 iResolution;
in vec2 vUV;
layout(location = 0) out vec3 fragColor;
uniform sampler2D frame0; uniform sampler2D frame0;
uniform sampler2D frame1;
in vec2 vUV;
layout(location = 3) out vec3 fragColor;
// SRC A
// ---------
// IN: 0 / 1
// OUT: 3
void main() { void main() {
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
+19
View File
@@ -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);
}
+19
View File
@@ -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;
}
+19
View File
@@ -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;
}
+19
View File
@@ -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;
}
+19
View File
@@ -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;
}
+4 -3
View File
@@ -8,13 +8,14 @@
#include "logs.h" #include "logs.h"
void print_help(int status_code) { void print_help(int status_code) {
puts(PACKAGE " " VERSION "\n\n" puts(PACKAGE
" " VERSION "\n\n"
"usage: " PACKAGE " " "usage: " PACKAGE " "
"[-h] " "[-h] "
"[-v] " "[-v] "
"[-hr] " "[-hr] "
"[-s=SCREEN] " "[-s=SCREEN] "
"[-f=FRAG_PATH] " "[-f=DIR_PATH] "
"\n\n" "\n\n"
"Fusion Of Real-time Generative Effects.\n\n" "Fusion Of Real-time Generative Effects.\n\n"
"options:\n" "options:\n"
@@ -22,7 +23,7 @@ void print_help(int status_code) {
" -v, --version print version\n" " -v, --version print version\n"
" -hr, --hot-reload hot reload of shaders scripts\n" " -hr, --hot-reload hot reload of shaders scripts\n"
" -s, --screen output screen number (default: primary)\n" " -s, --screen output screen number (default: primary)\n"
" -f, --frag fragment shader path (default: TODO)\n"); " -f, --frag fragment shaders directory (default: TODO)\n");
exit(status_code); exit(status_code);
} }
+4 -4
View File
@@ -9,12 +9,12 @@
#define VERSION "(dev)" #define VERSION "(dev)"
#endif #endif
#ifndef FRAMEBUFFER_COUNT #ifndef FRAG_COUNT
#define FRAMEBUFFER_COUNT 7 #define FRAG_COUNT 6
#endif #endif
#ifndef TEXTURE_COUNT #ifndef TEX_COUNT
#define TEXTURE_COUNT 8 #define TEX_COUNT 8
#endif #endif
#endif #endif
+25 -11
View File
@@ -37,14 +37,20 @@ void compute_fps(Window *window, Timer *timer) {
} }
void loop(Window *window, ShaderProgram program, bool hot_reload, void loop(Window *window, ShaderProgram program, bool hot_reload,
File *fragment_shader, Timer *timer) { File *fragment_shaders, Timer *timer) {
Context context; Context context;
int i;
compute_fps(window, timer); compute_fps(window, timer);
if (hot_reload && should_update_file(*fragment_shader)) { if (hot_reload) {
update_file(fragment_shader); // TODO extract to function
update_program(program, *fragment_shader); 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); context = get_window_context(window);
@@ -55,24 +61,29 @@ void loop(Window *window, ShaderProgram program, bool hot_reload,
} }
void forge_run(Parameters params) { void forge_run(Parameters params) {
File fragment_shader; File fragment_shaders[FRAG_COUNT];
ShaderProgram program; ShaderProgram program;
Window *window; Window *window;
Timer timer; Timer timer;
Context context; Context context;
int i;
char file_path[FRAG_COUNT][1024];
fragment_shader = read_file(params.frag_path); // TODO extract to function
for (i = 0; i < FRAG_COUNT; i++) {
if (fragment_shader.error) { 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); exit(EXIT_FAILURE);
} }
}
window = init_window(PACKAGE " " VERSION, params.screen, error_callback, window = init_window(PACKAGE " " VERSION, params.screen, error_callback,
key_callback); key_callback);
context = get_window_context(window); context = get_window_context(window);
program = init_program(fragment_shader, context); program = init_program(fragment_shaders, context);
if (program.error) { if (program.error) {
close_window(window, true); close_window(window, true);
@@ -82,10 +93,13 @@ void forge_run(Parameters params) {
timer = create_timer(60); timer = create_timer(60);
while (!window_should_close(window)) { 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); close_window(window, true);
free_file(&fragment_shader); // TODO extract to function
for (i = 0; i < FRAG_COUNT; i++) {
free_file(&fragment_shaders[i]);
}
} }
+37 -30
View File
@@ -35,9 +35,9 @@ bool compile_shader(GLuint shader_id, char *name, char *source_code) {
void init_textures(ShaderProgram *program, Context context) { void init_textures(ShaderProgram *program, Context context) {
int i; 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 // selects which texture unit subsequent texture state calls will affect
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
@@ -58,12 +58,12 @@ void init_textures(ShaderProgram *program, Context context) {
void init_framebuffers(ShaderProgram *program) { void init_framebuffers(ShaderProgram *program) {
int i, j; 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]); 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 // attaches a selected mipmap level or image of a texture object as one of
// the logical buffers of the framebuffer object // the logical buffers of the framebuffer object
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + j, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + j,
@@ -97,7 +97,9 @@ void init_vertices(ShaderProgram *program) {
glBindVertexArray(program->vertex_array); 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 // compile vertex shader
program->vertex_shader = glCreateShader(GL_VERTEX_SHADER); program->vertex_shader = glCreateShader(GL_VERTEX_SHADER);
program->error |= !compile_shader( program->error |= !compile_shader(
@@ -109,10 +111,13 @@ void init_shaders(ShaderProgram *program, File fragment_shader) {
!compile_shader(program->output_fragment_shader, !compile_shader(program->output_fragment_shader,
"internal fragment shader", output_fragment_shader_text); "internal fragment shader", output_fragment_shader_text);
// compile fragment shader // compile fragment shaders
program->fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); for (i = 0; i < FRAG_COUNT; i++) {
program->error |= !compile_shader( program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
program->fragment_shader, fragment_shader.path, fragment_shader.content); 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) { 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) { if (output) {
glAttachShader(program->programs[i], program->output_fragment_shader); glAttachShader(program->programs[i], program->output_fragment_shader);
} else { } else {
// TODO add others glAttachShader(program->programs[i], program->fragment_shaders[i]);
glAttachShader(program->programs[i], program->fragment_shader);
} }
glLinkProgram(program->programs[i]); glLinkProgram(program->programs[i]);
@@ -141,7 +145,7 @@ void init_single_program(ShaderProgram *program, int i, bool output) {
} }
// create frameX uniforms pointer // create frameX uniforms pointer
for (j = 0; j < TEXTURE_COUNT; j++) { for (j = 0; j < TEX_COUNT; j++) {
sprintf(uniform_name, "frame%d", j); sprintf(uniform_name, "frame%d", j);
program->frames_locations[i][j] = program->frames_locations[i][j] =
glGetUniformLocation(program->programs[i], uniform_name); 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, glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (void *)offsetof(Vertex, pos)); 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; int i;
ShaderProgram program = {.error = false, ShaderProgram program = {.error = false,
.last_width = context.width, .last_width = context.width,
@@ -170,7 +174,7 @@ ShaderProgram init_program(File fragment_shader, Context context) {
init_framebuffers(&program); init_framebuffers(&program);
init_shaders(&program, fragment_shader); init_shaders(&program, fragment_shaders);
if (program.error) { if (program.error) {
return program; return program;
@@ -179,27 +183,28 @@ ShaderProgram init_program(File fragment_shader, Context context) {
init_vertices(&program); init_vertices(&program);
// create and link full shader programs // create and link full shader programs
for (i = 0; i < FRAMEBUFFER_COUNT + 1; i++) { for (i = 0; i < FRAG_COUNT + 1; i++) {
init_single_program(&program, i, i == FRAMEBUFFER_COUNT); 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; return program;
} }
void update_program(ShaderProgram program, File fragment_shader) { void update_program(ShaderProgram program, File *fragment_shaders, int i) {
bool result; bool result;
int i;
result = compile_shader(program.fragment_shader, fragment_shader.path, result = compile_shader(program.fragment_shaders[i], fragment_shaders[i].path,
fragment_shader.content); fragment_shaders[i].content);
if (result) { 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); glViewport(0, 0, context.width, context.height);
// clean and resize all textures // clean and resize all textures
for (i = 0; i < TEXTURE_COUNT; i++) { for (i = 0; i < TEX_COUNT; i++) {
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0,
GL_RGB, GL_UNSIGNED_BYTE, 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}; 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 // use specific shader program
glUseProgram(program.programs[i]); glUseProgram(program.programs[i]);
if (i == FRAMEBUFFER_COUNT) { if (i == FRAG_COUNT) {
// use default framebuffer (output) // use default framebuffer (output)
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -242,10 +247,12 @@ void apply_program(ShaderProgram program, Context context) {
} }
// set GL_TEXTURE(X) to uniform sampler2D frameX // 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); glUniform1i(program.frames_locations[i][j], j);
} }
glDrawBuffers(TEX_COUNT, program.draw_buffers);
// draw output // draw output
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
} }
+2 -2
View File
@@ -3,9 +3,9 @@
#ifndef SHADERS_H #ifndef SHADERS_H
#define 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); void apply_program(ShaderProgram program, Context context);
+10 -8
View File
@@ -33,23 +33,25 @@ typedef struct ShaderProgram {
int last_width; int last_width;
int last_height; int last_height;
GLuint programs[FRAMEBUFFER_COUNT + 1]; GLuint programs[FRAG_COUNT + 1];
GLuint vertex_shader; GLuint vertex_shader;
GLuint output_fragment_shader; GLuint output_fragment_shader;
GLuint fragment_shader; // TODO multiple GLuint fragment_shaders[FRAG_COUNT];
GLuint itime_locations[FRAMEBUFFER_COUNT]; GLuint itime_locations[FRAG_COUNT];
GLuint ires_locations[FRAMEBUFFER_COUNT]; GLuint ires_locations[FRAG_COUNT];
GLuint frames_locations[FRAMEBUFFER_COUNT + 1][FRAMEBUFFER_COUNT]; GLuint frames_locations[FRAG_COUNT + 1][TEX_COUNT];
GLuint vpos_locations[FRAMEBUFFER_COUNT + 1]; GLuint vpos_locations[FRAG_COUNT + 1];
GLuint vertex_buffer; GLuint vertex_buffer;
GLuint vertex_array; GLuint vertex_array;
GLuint frame_buffers[FRAMEBUFFER_COUNT]; GLuint frame_buffers[FRAG_COUNT];
GLuint textures[FRAMEBUFFER_COUNT]; GLuint textures[TEX_COUNT];
GLenum draw_buffers[TEX_COUNT];
} ShaderProgram; } ShaderProgram;
typedef GLFWwindow Window; typedef GLFWwindow Window;