diff --git a/Makefile.am b/Makefile.am index 4c8566b..5625cb9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign subdir-objects -Wall bin_PROGRAMS = forge -forge_SOURCES = src/main.c src/args.c src/forge.c src/file.c src/window.c src/shaders.c src/timer.c $(top_srcdir)/include/glad/gl.h +forge_SOURCES = src/main.c src/args.c src/forge.c src/file.c src/window.c src/shaders.c src/timer.c src/strings.c $(top_srcdir)/include/glad/gl.h forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE forge_LDADD = -lm -lGL -lglfw -include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h src/constants.h src/window.h src/shaders.h src/logs.h src/timer.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/linmath.h \ No newline at end of file +include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h src/constants.h src/window.h src/shaders.h src/logs.h src/timer.h src/strings.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/linmath.h \ No newline at end of file diff --git a/Makefile.dev b/Makefile.dev index 5c92869..7862151 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -1,6 +1,6 @@ TARGET ?= forge INSTALL_DIR ?= $(HOME)/.local/bin -TEST_ARGS ?= +TEST_ARGS ?= --hot-reload --frag=./shaders SHELL := /bin/bash .PHONY: build @@ -18,7 +18,7 @@ build: -o build/$(TARGET) run: build - ./build/forge --hot-reload --frag=./shaders + ./build/$(TARGET) $(TEST_ARGS) .PHONY: install install: build @@ -26,7 +26,12 @@ install: build .PHONY: valgrind valgrind: build - valgrind --leak-check=full -s ./build/$(TARGET) $(TEST_ARGS) + valgrind \ + --leak-check=full \ + --track-fds=all \ + --show-realloc-size-zero=no \ + --undef-value-errors=no \ + ./build/$(TARGET) $(TEST_ARGS) .PHONY: release release: clean diff --git a/README.md b/README.md index 48aef30..7f4510a 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ make -f Makefile.dev release-arch - [ ] Multi-stage shaders - [x] Test 2 stages with render to texture - [x] 2 in 2 fx 1 mix 1 fx layout - - [ ] Include fragments with special directive + - [x] Include common code - [ ] 16 input + 16 fx definition and selection (with param) - [x] Feedback texture - [ ] Free opengl memory diff --git a/shaders/frag0.glsl b/shaders/frag0.glsl new file mode 100644 index 0000000..5f21221 --- /dev/null +++ b/shaders/frag0.glsl @@ -0,0 +1,19 @@ +#version 460 + +// COMMON DEFINITIONS AND FUNCTIONS + +uniform float iTime; +uniform vec2 iResolution; + +uniform sampler2D frame0; +uniform sampler2D frame1; +uniform sampler2D frame2; +uniform sampler2D frame3; +uniform sampler2D frame4; +uniform sampler2D frame5; +uniform sampler2D frame6; +uniform sampler2D frame7; + +in vec2 vUV; + +// TODO things \ No newline at end of file diff --git a/shaders/frag1.glsl b/shaders/frag1.glsl index 8a7b979..7c2af2a 100644 --- a/shaders/frag1.glsl +++ b/shaders/frag1.glsl @@ -1,20 +1,12 @@ #version 460 -uniform float iTime; -uniform vec2 iResolution; - -uniform sampler2D frame0; -uniform sampler2D frame1; - -in vec2 vUV; -layout(location = 3) out vec3 fragColor; - - // SRC A // --------- // IN: 0 / 1 // OUT: 3 +layout(location = 3) out vec3 fragColor; + void main() { vec2 uv0 = vUV.st; float ratio = iResolution.x / iResolution.y; diff --git a/shaders/frag2.glsl b/shaders/frag2.glsl index abfe8f7..1bcefb0 100644 --- a/shaders/frag2.glsl +++ b/shaders/frag2.glsl @@ -1,19 +1,12 @@ #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 +layout(location = 4) out vec3 fragColor; + 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 index 1234a95..bdaee33 100644 --- a/shaders/frag3.glsl +++ b/shaders/frag3.glsl @@ -1,19 +1,12 @@ #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 +layout(location = 5) out vec3 fragColor; + void main() { fragColor = texture(frame3, vUV).xyz; } \ No newline at end of file diff --git a/shaders/frag4.glsl b/shaders/frag4.glsl index a92774c..8d31466 100644 --- a/shaders/frag4.glsl +++ b/shaders/frag4.glsl @@ -1,19 +1,12 @@ #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 +layout(location = 6) out vec3 fragColor; + void main() { fragColor = texture(frame4, vUV).xyz; } \ No newline at end of file diff --git a/shaders/frag5.glsl b/shaders/frag5.glsl index 4a37d53..11270e1 100644 --- a/shaders/frag5.glsl +++ b/shaders/frag5.glsl @@ -1,19 +1,12 @@ #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 +layout(location = 7) out vec3 fragColor; + 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 index 7f89091..f2a039d 100644 --- a/shaders/frag6.glsl +++ b/shaders/frag6.glsl @@ -1,19 +1,12 @@ #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 +layout(location = 0) out vec3 fragColor; + void main() { fragColor = texture(frame7, vUV).xyz; } \ No newline at end of file diff --git a/src/file.c b/src/file.c index 16b9d06..9cf0542 100644 --- a/src/file.c +++ b/src/file.c @@ -5,6 +5,7 @@ #include #include "logs.h" +#include "strings.h" #include "types.h" time_t get_file_time(File file) { @@ -64,4 +65,13 @@ File read_file(char *path) { return file; } -void free_file(File *file) { free(file->content); } \ No newline at end of file +void prepend_file(File *src, File extra) { + char *old_src_content = src->content; + src->content = concat(extra.content, src->content); + free(old_src_content); +} + +void free_file(File *file) { + free(file->content); + free(file->path); +} \ No newline at end of file diff --git a/src/file.h b/src/file.h index 3f43eae..be5170b 100644 --- a/src/file.h +++ b/src/file.h @@ -11,4 +11,6 @@ void update_file(File *file); void free_file(File *file); +void prepend_file(File *src, File extra); + #endif \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 2aae68f..fa704e3 100644 --- a/src/forge.c +++ b/src/forge.c @@ -36,21 +36,33 @@ void compute_fps(Window *window, Timer *timer) { } } -void loop(Window *window, ShaderProgram program, bool hot_reload, - File *fragment_shaders, Timer *timer) { - Context context; +void hot_reload(ShaderProgram program, File *common_shader_code, + File *fragment_shaders) { int i; + bool force_update = false; + + if (should_update_file(*common_shader_code)) { + update_file(common_shader_code); + force_update = true; + } + + for (i = 0; i < FRAG_COUNT; i++) { + if (force_update || should_update_file(fragment_shaders[i])) { + update_file(&fragment_shaders[i]); + prepend_file(&fragment_shaders[i], *common_shader_code); + update_program(program, fragment_shaders, i); + } + } +} + +void loop(Window *window, ShaderProgram program, bool hr, + File *common_shader_code, File *fragment_shaders, Timer *timer) { + Context context; compute_fps(window, timer); - 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); - } - } + if (hr) { + hot_reload(program, common_shader_code, fragment_shaders); } context = get_window_context(window); @@ -60,23 +72,53 @@ void loop(Window *window, ShaderProgram program, bool hot_reload, refresh_window(window); } +File read_fragment_shader_file(char *frag_path, int i) { + File fragment_shader; + char *file_path = malloc(sizeof(char) * 1024); + + sprintf(file_path, "%s/frag%d.glsl", frag_path, i); + fragment_shader = read_file(file_path); + if (fragment_shader.error) { + exit(EXIT_FAILURE); + } + + return fragment_shader; +} + +void init_files(char *frag_path, File *common_shader_code, + File *fragment_shaders) { + int i; + + for (i = 0; i < FRAG_COUNT + 1; i++) { + if (i == 0) { + (*common_shader_code) = read_fragment_shader_file(frag_path, i); + } else { + fragment_shaders[i - 1] = read_fragment_shader_file(frag_path, i); + + prepend_file(&fragment_shaders[i - 1], *common_shader_code); + } + } +} + +void free_files(File *common_shader_code, File *fragment_shaders) { + int i; + + for (i = 0; i < FRAG_COUNT; i++) { + free_file(&fragment_shaders[i]); + } + + free_file(common_shader_code); +} + void forge_run(Parameters params) { File fragment_shaders[FRAG_COUNT]; + File common_shader_code; ShaderProgram program; Window *window; Timer timer; Context context; - int i; - char file_path[FRAG_COUNT][1024]; - // 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); - } - } + init_files(params.frag_path, &common_shader_code, fragment_shaders); window = init_window(PACKAGE " " VERSION, params.screen, error_callback, key_callback); @@ -93,13 +135,11 @@ void forge_run(Parameters params) { timer = create_timer(60); while (!window_should_close(window)) { - loop(window, program, params.hot_reload, fragment_shaders, &timer); + loop(window, program, params.hot_reload, &common_shader_code, + fragment_shaders, &timer); } close_window(window, true); - // TODO extract to function - for (i = 0; i < FRAG_COUNT; i++) { - free_file(&fragment_shaders[i]); - } + free_files(&common_shader_code, fragment_shaders); } \ No newline at end of file diff --git a/src/shaders.c b/src/shaders.c index 447bb60..159c414 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -256,6 +256,4 @@ void apply_program(ShaderProgram program, Context context) { // draw output glDrawArrays(GL_TRIANGLES, 0, 6); } -} - -// TODO clean buffers from opengl memories \ No newline at end of file +} \ No newline at end of file diff --git a/src/strings.c b/src/strings.c new file mode 100644 index 0000000..6f7dd49 --- /dev/null +++ b/src/strings.c @@ -0,0 +1,11 @@ +#include +#include + +char *concat(const char *s1, const char *s2) { + char *result = + malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator + // in real code you would check for errors in malloc here + strcpy(result, s1); + strcat(result, s2); + return result; +} \ No newline at end of file diff --git a/src/strings.h b/src/strings.h new file mode 100644 index 0000000..c7e907a --- /dev/null +++ b/src/strings.h @@ -0,0 +1,6 @@ +#ifndef STRINGS_H +#define STRINGS_H + +char *concat(const char *s1, const char *s2); + +#endif \ No newline at end of file