feat: working include directive
This commit is contained in:
@@ -16,7 +16,7 @@ jobs:
|
|||||||
- name: install libs
|
- name: install libs
|
||||||
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev
|
run: sudo apt install -y libglfw3-dev libgl-dev libv4l-dev libasound2-dev
|
||||||
- name: gcc
|
- name: gcc
|
||||||
run: mkdir -p build && gcc -v -Wall -Wextra -Werror src/*.c src/*.h -lglfw -lGL -lm -lasound -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE
|
run: mkdir -p build && gcc -v -Wall -Wextra -Werror -Wno-format-truncation src/*.c src/*.h -lglfw -lGL -lm -lasound -Iinclude hashmap.c/hashmap.c log.c/src/log.c -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE
|
||||||
|
|
||||||
build-release:
|
build-release:
|
||||||
needs: lint
|
needs: lint
|
||||||
|
|||||||
+4
-1
@@ -85,6 +85,7 @@ make -f Makefile.dev release-arch
|
|||||||
- [x] Clean code and fix things
|
- [x] Clean code and fix things
|
||||||
- [x] Share openGL state between monitor and screen
|
- [x] Share openGL state between monitor and screen
|
||||||
- [ ] Default project
|
- [ ] Default project
|
||||||
|
- [ ] split with includes
|
||||||
- [ ] src 9: game of life
|
- [ ] src 9: game of life
|
||||||
- [ ] src 10 : ?
|
- [ ] src 10 : ?
|
||||||
- [ ] src 11 : ?
|
- [ ] src 11 : ?
|
||||||
@@ -97,7 +98,9 @@ make -f Makefile.dev release-arch
|
|||||||
- [ ] Other
|
- [ ] Other
|
||||||
- [x] `forge_project.cfg`
|
- [x] `forge_project.cfg`
|
||||||
- [x] Define frag prefix in config
|
- [x] Define frag prefix in config
|
||||||
- [ ] Use custom `#include xxx.glsl` preprocessor
|
- [x] Use custom `#include xxx.glsl` preprocessor
|
||||||
|
- [ ] Use snprintf isntead of sprintf (and strlcpy instand of strncpy)
|
||||||
|
- [ ] Pass "heavy" struct as pointer to avoid stack overload
|
||||||
- [x] Clean and sort args
|
- [x] Clean and sort args
|
||||||
- [x] `--auto-random` / `--no-auto-random`
|
- [x] `--auto-random` / `--no-auto-random`
|
||||||
- [ ] Update readme with usage documentation
|
- [ ] Update readme with usage documentation
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ build:
|
|||||||
log.c/src/log.c \
|
log.c/src/log.c \
|
||||||
-lm -lGL -lglfw -lasound \
|
-lm -lGL -lglfw -lasound \
|
||||||
-Wall -Wextra \
|
-Wall -Wextra \
|
||||||
|
-Wno-format-truncation \
|
||||||
-DGLFW_INCLUDE_NONE \
|
-DGLFW_INCLUDE_NONE \
|
||||||
-DGLFW_EXPOSE_NATIVE_EGL \
|
-DGLFW_EXPOSE_NATIVE_EGL \
|
||||||
-DGLFW_NATIVE_INCLUDE_NONE \
|
-DGLFW_NATIVE_INCLUDE_NONE \
|
||||||
@@ -31,6 +32,10 @@ run: build
|
|||||||
demo: build
|
demo: build
|
||||||
./build/$(TARGET) $(TEST_ARGS) --demo
|
./build/$(TARGET) $(TEST_ARGS) --demo
|
||||||
|
|
||||||
|
.PHONY: sample
|
||||||
|
sample: build
|
||||||
|
./build/$(TARGET) --project=sample
|
||||||
|
|
||||||
.PHONY: valgrind
|
.PHONY: valgrind
|
||||||
valgrind: build
|
valgrind: build
|
||||||
valgrind \
|
valgrind \
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ b
|
|||||||
- [NanoKontrol2 Controller mapping](#nanokontrol2-controller-mapping)
|
- [NanoKontrol2 Controller mapping](#nanokontrol2-controller-mapping)
|
||||||
- [Making your own FORGE project](#making-your-own-forge-project)
|
- [Making your own FORGE project](#making-your-own-forge-project)
|
||||||
- [`forge_project.cfg`](#forge_projectcfg)
|
- [`forge_project.cfg`](#forge_projectcfg)
|
||||||
- [Working with `frag0.glsl`](#working-with-frag0glsl)
|
- [Writing your fragment shaders](#writing-your-fragment-shaders)
|
||||||
|
- [Working with `#include`](#working-with-include)
|
||||||
- [Frequently Asked Questions](#frequently-asked-questions)
|
- [Frequently Asked Questions](#frequently-asked-questions)
|
||||||
- [Why "steel"?](#why-steel)
|
- [Why "steel"?](#why-steel)
|
||||||
- [How do I report a bug?](#how-do-i-report-a-bug)
|
- [How do I report a bug?](#how-do-i-report-a-bug)
|
||||||
@@ -178,7 +179,11 @@ TODO
|
|||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
### Working with `frag0.glsl`
|
### Writing your fragment shaders
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Working with `#include`
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// VIDEO 1
|
// VIDEO 1
|
||||||
// -----------
|
// -----------
|
||||||
// IN: 1 (RAW IN A)
|
// IN: 1 (RAW IN A)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// MONITOR
|
// MONITOR
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// VIDEO 2
|
// VIDEO 2
|
||||||
// -----------
|
// -----------
|
||||||
// IN: 2 (RAW IN B)
|
// IN: 2 (RAW IN B)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// SRC A
|
// SRC A
|
||||||
// -----------
|
// -----------
|
||||||
// OUT: 5 (FX A)
|
// OUT: 5 (FX A)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// SRC B
|
// SRC B
|
||||||
// -----------
|
// -----------
|
||||||
// OUT: 6 (FX B)
|
// OUT: 6 (FX B)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// FX A
|
// FX A
|
||||||
// -------------
|
// -------------
|
||||||
// IN: 5 (SRC A)
|
// IN: 5 (SRC A)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// FX B
|
// FX B
|
||||||
// -------------
|
// -------------
|
||||||
// IN: 6 (SRC B)
|
// IN: 6 (SRC B)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// A+B
|
// A+B
|
||||||
// ------------
|
// ------------
|
||||||
// IN: 7 (FX A)
|
// IN: 7 (FX A)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// MFX
|
// MFX
|
||||||
// ------------
|
// ------------
|
||||||
// IN: 9 (A+B)
|
// IN: 9 (A+B)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include frag0.glsl
|
||||||
|
|
||||||
// OUT
|
// OUT
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -31,6 +31,10 @@
|
|||||||
#define MAX_FRAG 64
|
#define MAX_FRAG 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_SUB_FILE
|
||||||
|
#define MAX_SUB_FILE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
/* MIDI */
|
/* MIDI */
|
||||||
|
|
||||||
#ifndef UNSET_MIDI_CODE
|
#ifndef UNSET_MIDI_CODE
|
||||||
@@ -44,7 +48,7 @@
|
|||||||
/* ARRAY */
|
/* ARRAY */
|
||||||
|
|
||||||
#ifndef ARRAY_SIZE
|
#ifndef ARRAY_SIZE
|
||||||
#define ARRAY_SIZE 1024
|
#define ARRAY_SIZE 512
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ARRAY_NOT_FOUND
|
#ifndef ARRAY_NOT_FOUND
|
||||||
|
|||||||
+20
-12
@@ -2,6 +2,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ bool file_should_update(File file) {
|
|||||||
return file.last_write != get_file_time(file);
|
return file.last_write != get_file_time(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_update(File *file) {
|
bool file_update(File *file) {
|
||||||
long length;
|
long length;
|
||||||
FILE *file_pointer;
|
FILE *file_pointer;
|
||||||
|
|
||||||
@@ -40,19 +41,19 @@ void file_update(File *file) {
|
|||||||
if (file_pointer == NULL) {
|
if (file_pointer == NULL) {
|
||||||
file->error = true;
|
file->error = true;
|
||||||
log_error("Cannot open file '%s'", file->path);
|
log_error("Cannot open file '%s'", file->path);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// read file length
|
// read file length
|
||||||
fseek(file_pointer, 0, SEEK_END);
|
fseek(file_pointer, 0, SEEK_END);
|
||||||
length = ftell(file_pointer);
|
length = ftell(file_pointer);
|
||||||
// init buffer
|
// init buffer
|
||||||
fseek(file_pointer, 0, SEEK_SET);
|
fseek(file_pointer, 0, SEEK_SET);
|
||||||
file->content = (char *)malloc((length + 1) * sizeof(char));
|
file->content = malloc(length + 1);
|
||||||
if (file->content == NULL) {
|
if (file->content == NULL) {
|
||||||
file->error = true;
|
file->error = true;
|
||||||
fclose(file_pointer);
|
fclose(file_pointer);
|
||||||
log_error("Cannot read file '%s'", file->path);
|
log_error("Cannot read file '%s'", file->path);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// read file
|
// read file
|
||||||
fread(file->content, sizeof(char), length, file_pointer);
|
fread(file->content, sizeof(char), length, file_pointer);
|
||||||
@@ -62,12 +63,14 @@ void file_update(File *file) {
|
|||||||
file->content[length] = '\0';
|
file->content[length] = '\0';
|
||||||
// read last update time
|
// read last update time
|
||||||
file->last_write = get_file_time(*file);
|
file->last_write = get_file_time(*file);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
File file_read(char *path) {
|
File file_read(char *path) {
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
sprintf(file.path, path, STR_LEN);
|
strncpy(file.path, path, STR_LEN);
|
||||||
file.content = NULL;
|
file.content = NULL;
|
||||||
file.error = false;
|
file.error = false;
|
||||||
file.last_write = 0;
|
file.last_write = 0;
|
||||||
@@ -98,12 +101,17 @@ void file_write(char *path, StringArray lines) {
|
|||||||
fclose(file_pointer);
|
fclose(file_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_prepend(File *src, File extra) {
|
void file_free(File *file) {
|
||||||
char *old_src_content;
|
if (!file->error) {
|
||||||
|
free(file->content);
|
||||||
old_src_content = src->content;
|
file->error = true;
|
||||||
src->content = string_concat(extra.content, src->content);
|
}
|
||||||
free(old_src_content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_free(File *file) { free(file->content); }
|
void file_free_array(FileArray *files) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < files->length; i++) {
|
||||||
|
file_free(&files->values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -7,12 +7,12 @@ File file_read(char *path);
|
|||||||
|
|
||||||
bool file_should_update(File file);
|
bool file_should_update(File file);
|
||||||
|
|
||||||
void file_update(File *file);
|
bool file_update(File *file);
|
||||||
|
|
||||||
void file_prepend(File *src, File extra);
|
|
||||||
|
|
||||||
void file_write(char *path, StringArray lines);
|
void file_write(char *path, StringArray lines);
|
||||||
|
|
||||||
void file_free(File *file);
|
void file_free(File *file);
|
||||||
|
|
||||||
|
void file_free_array(FileArray *files);
|
||||||
|
|
||||||
#endif /* FILE_H */
|
#endif /* FILE_H */
|
||||||
+9
-6
@@ -81,7 +81,7 @@ static void init_context(Parameters params, unsigned int in_count) {
|
|||||||
static void free_context() { shared_close_context(context); }
|
static void free_context() { shared_close_context(context); }
|
||||||
|
|
||||||
static void reload_shader(unsigned int i) {
|
static void reload_shader(unsigned int i) {
|
||||||
shaders_update(program, project.fragment_shaders, i);
|
shaders_update(program, project.fragment_shaders[i][0], i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_inputs(StringArray video_in, unsigned int video_size) {
|
static void init_inputs(StringArray video_in, unsigned int video_size) {
|
||||||
@@ -186,7 +186,11 @@ void forge_run(Parameters params) {
|
|||||||
|
|
||||||
context->stop = false;
|
context->stop = false;
|
||||||
|
|
||||||
project = project_init(params.project_path, params.config_file);
|
project_init(&project, params.project_path, params.config_file);
|
||||||
|
|
||||||
|
if (project.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
init_inputs(params.video_in, params.video_size);
|
init_inputs(params.video_in, params.video_size);
|
||||||
|
|
||||||
@@ -222,7 +226,7 @@ void forge_run(Parameters params) {
|
|||||||
|
|
||||||
window_use(window_output, context);
|
window_use(window_output, context);
|
||||||
|
|
||||||
program = shaders_init(project, context, inputs, NULL);
|
shaders_init(&program, &project, context, inputs, false);
|
||||||
} else {
|
} else {
|
||||||
window_output = NULL;
|
window_output = NULL;
|
||||||
}
|
}
|
||||||
@@ -234,8 +238,7 @@ void forge_run(Parameters params) {
|
|||||||
|
|
||||||
window_use(window_monitor, context);
|
window_use(window_monitor, context);
|
||||||
|
|
||||||
program = shaders_init(project, context, inputs,
|
shaders_init(&program, &project, context, inputs, window_output != NULL);
|
||||||
window_output != NULL ? &program : NULL);
|
|
||||||
} else {
|
} else {
|
||||||
window_monitor = NULL;
|
window_monitor = NULL;
|
||||||
}
|
}
|
||||||
@@ -279,7 +282,7 @@ void forge_run(Parameters params) {
|
|||||||
|
|
||||||
free_context();
|
free_context();
|
||||||
|
|
||||||
project_free(project);
|
project_free(&project);
|
||||||
|
|
||||||
window_terminate();
|
window_terminate();
|
||||||
}
|
}
|
||||||
+107
-60
@@ -1,95 +1,142 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "config_file.h"
|
#include "config_file.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "log.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
static File read_fragment_shader_file(char *frag_path, char *frag_prefix,
|
static bool parse_fragment_shader_file(Project *project, unsigned int i) {
|
||||||
unsigned int i) {
|
File tmp_file, fragment_shader;
|
||||||
File fragment_shader;
|
|
||||||
char file_path[STR_LEN];
|
char file_path[STR_LEN];
|
||||||
|
char *include_pos, *include_end;
|
||||||
|
char included_file[STR_LEN];
|
||||||
|
char *new_content;
|
||||||
|
|
||||||
snprintf(file_path, STR_LEN, "%s/%s%d.glsl", frag_path, frag_prefix, i);
|
fragment_shader = project->fragment_shaders[i][0];
|
||||||
fragment_shader = file_read(file_path);
|
|
||||||
if (fragment_shader.error) {
|
project->sub_counts.values[i] = 0;
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
include_pos = strstr(fragment_shader.content, "#include ");
|
||||||
|
|
||||||
|
while (include_pos != NULL && project->sub_counts.values[i] < MAX_SUB_FILE) {
|
||||||
|
include_end = strstr(include_pos, "\n");
|
||||||
|
if (include_end == NULL) {
|
||||||
|
log_error("Invalid '#include' directive in '%s'", fragment_shader.path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(included_file, include_pos + 9, include_end - include_pos - 8);
|
||||||
|
|
||||||
|
snprintf(file_path, STR_LEN, "%s/%s", project->path, included_file);
|
||||||
|
|
||||||
|
tmp_file = file_read(file_path);
|
||||||
|
|
||||||
|
if (tmp_file.error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
project->fragment_shaders[i][++project->sub_counts.values[i]] = tmp_file;
|
||||||
|
|
||||||
|
new_content = string_replace_at(
|
||||||
|
fragment_shader.content, include_pos - fragment_shader.content,
|
||||||
|
include_end - fragment_shader.content, tmp_file.content);
|
||||||
|
|
||||||
|
project->fragment_shaders[i][0].content = new_content;
|
||||||
|
|
||||||
|
file_free(&tmp_file);
|
||||||
|
|
||||||
|
include_pos = strstr(fragment_shader.content, "#include ");
|
||||||
}
|
}
|
||||||
|
|
||||||
return fragment_shader;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_files(Project *output, char *frag_path, char *frag_prefix,
|
static bool read_fragment_shader_file(Project *project, char *frag_prefix,
|
||||||
unsigned int frag_count) {
|
unsigned int i) {
|
||||||
|
char file_path[STR_LEN];
|
||||||
|
|
||||||
|
snprintf(file_path, STR_LEN, "%s/%s%d.glsl", project->path, frag_prefix,
|
||||||
|
i + 1);
|
||||||
|
|
||||||
|
project->fragment_shaders[i][0] = file_read(file_path);
|
||||||
|
|
||||||
|
if (project->fragment_shaders[i][0].error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_fragment_shader_file(project, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void project_init(Project *project, char *project_path, char *config_file) {
|
||||||
|
char config_path[STR_LEN];
|
||||||
|
char *frag_prefix;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
output->fragment_shaders.length = frag_count;
|
strlcpy(project->path, project_path, STR_LEN);
|
||||||
|
|
||||||
for (i = 0; i < frag_count + 1; i++) {
|
snprintf(config_path, STR_LEN, "%s/%s", project_path, config_file);
|
||||||
if (i == 0) {
|
|
||||||
output->common_shader_code =
|
|
||||||
read_fragment_shader_file(frag_path, frag_prefix, i);
|
|
||||||
} else {
|
|
||||||
output->fragment_shaders.values[i - 1] =
|
|
||||||
read_fragment_shader_file(frag_path, frag_prefix, i);
|
|
||||||
|
|
||||||
file_prepend(&output->fragment_shaders.values[i - 1],
|
project->config = config_file_read(config_path);
|
||||||
output->common_shader_code);
|
|
||||||
|
project->state_config = state_parse_config(project->config);
|
||||||
|
|
||||||
|
project->frag_count = config_file_get_int(project->config, "FRAG_COUNT", 1);
|
||||||
|
project->in_count = config_file_get_int(project->config, "IN_COUNT", 0);
|
||||||
|
frag_prefix =
|
||||||
|
config_file_get_str(project->config, "FRAG_FILE_PREFIX", "frag");
|
||||||
|
|
||||||
|
if (project->frag_count > MAX_FRAG) {
|
||||||
|
log_error("FRAG_COUNT over %d", MAX_FRAG);
|
||||||
|
project->error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
project->sub_counts.length = project->frag_count;
|
||||||
|
|
||||||
|
for (i = 0; i < project->frag_count; i++) {
|
||||||
|
project->sub_counts.values[i] = 0;
|
||||||
|
if (!read_fragment_shader_file(project, frag_prefix, i)) {
|
||||||
|
project_free(project);
|
||||||
|
project->error = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Project project_init(char *project_path, char *config_file) {
|
|
||||||
Project project;
|
|
||||||
char config_path[STR_LEN];
|
|
||||||
char *frag_prefix;
|
|
||||||
|
|
||||||
snprintf(config_path, STR_LEN, "%s/%s", project_path, config_file);
|
|
||||||
|
|
||||||
project.config = config_file_read(config_path);
|
|
||||||
|
|
||||||
project.state_config = state_parse_config(project.config);
|
|
||||||
|
|
||||||
project.frag_count = config_file_get_int(project.config, "FRAG_COUNT", 1);
|
|
||||||
project.in_count = config_file_get_int(project.config, "IN_COUNT", 0);
|
|
||||||
frag_prefix = config_file_get_str(project.config, "FRAG_FILE_PREFIX", "frag");
|
|
||||||
|
|
||||||
init_files(&project, project_path, frag_prefix, project.frag_count);
|
|
||||||
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
void project_reload(Project *project, void (*reload_callback)(unsigned int)) {
|
void project_reload(Project *project, void (*reload_callback)(unsigned int)) {
|
||||||
unsigned int i;
|
unsigned int i, j;
|
||||||
bool force_update;
|
bool should_update;
|
||||||
|
|
||||||
force_update = false;
|
|
||||||
|
|
||||||
if (file_should_update(project->common_shader_code)) {
|
|
||||||
file_update(&project->common_shader_code);
|
|
||||||
force_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < project->frag_count; i++) {
|
for (i = 0; i < project->frag_count; i++) {
|
||||||
if (force_update ||
|
should_update = file_should_update(project->fragment_shaders[i][0]);
|
||||||
file_should_update(project->fragment_shaders.values[i])) {
|
|
||||||
file_update(&project->fragment_shaders.values[i]);
|
|
||||||
file_prepend(&project->fragment_shaders.values[i],
|
|
||||||
project->common_shader_code);
|
|
||||||
|
|
||||||
|
for (j = 0; j < project->sub_counts.values[i]; j++) {
|
||||||
|
should_update = should_update ||
|
||||||
|
file_should_update(project->fragment_shaders[i][j + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
should_update =
|
||||||
|
should_update && file_update(&project->fragment_shaders[i][0]);
|
||||||
|
|
||||||
|
should_update = should_update && parse_fragment_shader_file(project, i);
|
||||||
|
|
||||||
|
if (should_update) {
|
||||||
reload_callback(i);
|
reload_callback(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void project_free(Project project) {
|
void project_free(Project *project) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < project.frag_count; i++) {
|
for (i = 0; i < project->frag_count; i++) {
|
||||||
file_free(&project.fragment_shaders.values[i]);
|
file_free(&project->fragment_shaders[i][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
file_free(&project.common_shader_code);
|
config_file_free(project->config);
|
||||||
|
|
||||||
config_file_free(project.config);
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -3,10 +3,10 @@
|
|||||||
#ifndef PROJECT_H
|
#ifndef PROJECT_H
|
||||||
#define PROJECT_H
|
#define PROJECT_H
|
||||||
|
|
||||||
Project project_init(char *project_path, char *config_file);
|
void project_init(Project *project, char *project_path, char *config_file);
|
||||||
|
|
||||||
void project_reload(Project *project, void (*reload_callback)(unsigned int));
|
void project_reload(Project *project, void (*reload_callback)(unsigned int));
|
||||||
|
|
||||||
void project_free(Project project);
|
void project_free(Project *project);
|
||||||
|
|
||||||
#endif /* PROJECT_H */
|
#endif /* PROJECT_H */
|
||||||
+37
-48
@@ -213,7 +213,7 @@ static bool compile_shader(GLuint shader_id, char *name, char *source_code) {
|
|||||||
return status_params == GL_TRUE;
|
return status_params == GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_shaders(ShaderProgram *program, FileArray fragment_shaders) {
|
static void init_shaders(ShaderProgram *program, Project *project) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
// compile vertex shader
|
// compile vertex shader
|
||||||
@@ -225,8 +225,8 @@ static void init_shaders(ShaderProgram *program, FileArray fragment_shaders) {
|
|||||||
for (i = 0; i < program->frag_count; i++) {
|
for (i = 0; i < program->frag_count; i++) {
|
||||||
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
|
program->fragment_shaders[i] = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
program->error |= !compile_shader(program->fragment_shaders[i],
|
program->error |= !compile_shader(program->fragment_shaders[i],
|
||||||
fragment_shaders.values[i].path,
|
project->fragment_shaders[i][0].path,
|
||||||
fragment_shaders.values[i].content);
|
project->fragment_shaders[i][0].content);
|
||||||
|
|
||||||
if (program->error) {
|
if (program->error) {
|
||||||
return;
|
return;
|
||||||
@@ -377,69 +377,58 @@ static void init_programs(ShaderProgram *program, ConfigFile config,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderProgram shaders_init(Project project, SharedContext *context,
|
void shaders_init(ShaderProgram *program, Project *project,
|
||||||
VideoCaptureArray inputs, ShaderProgram *previous) {
|
SharedContext *context, VideoCaptureArray inputs,
|
||||||
ShaderProgram program;
|
bool rebind) {
|
||||||
|
if (!rebind) {
|
||||||
|
program->error = false;
|
||||||
|
program->last_resolution[0] = context->resolution[0];
|
||||||
|
program->last_resolution[1] = context->resolution[1];
|
||||||
|
program->tex_count = config_file_get_int(project->config, "TEX_COUNT", 9);
|
||||||
|
program->frag_count = project->frag_count;
|
||||||
|
program->frag_output_index =
|
||||||
|
config_file_get_int(project->config, "FRAG_OUTPUT", 1) - 1;
|
||||||
|
program->frag_monitor_index =
|
||||||
|
config_file_get_int(project->config, "FRAG_MONITOR", 1) - 1;
|
||||||
|
program->sub_type_count =
|
||||||
|
config_file_get_int(project->config, "SUB_TYPE_COUNT", 0);
|
||||||
|
program->in_count = config_file_get_int(project->config, "IN_COUNT", 0);
|
||||||
|
program->sub_variant_count = project->state_config.state_max;
|
||||||
|
program->active_count = project->state_config.midi_active_counts.length;
|
||||||
|
program->midi_lengths.length = 0;
|
||||||
|
|
||||||
if (previous == NULL) {
|
init_gl(program);
|
||||||
program.error = false;
|
|
||||||
program.last_resolution[0] = context->resolution[0];
|
|
||||||
program.last_resolution[1] = context->resolution[1];
|
|
||||||
program.tex_count = config_file_get_int(project.config, "TEX_COUNT", 9);
|
|
||||||
program.frag_count = project.frag_count;
|
|
||||||
program.frag_output_index =
|
|
||||||
config_file_get_int(project.config, "FRAG_OUTPUT", 1) - 1;
|
|
||||||
program.frag_monitor_index =
|
|
||||||
config_file_get_int(project.config, "FRAG_MONITOR", 1) - 1;
|
|
||||||
program.sub_type_count =
|
|
||||||
config_file_get_int(project.config, "SUB_TYPE_COUNT", 0);
|
|
||||||
program.in_count = config_file_get_int(project.config, "IN_COUNT", 0);
|
|
||||||
program.sub_variant_count = project.state_config.state_max;
|
|
||||||
program.active_count = project.state_config.midi_active_counts.length;
|
|
||||||
program.midi_lengths.length = 0;
|
|
||||||
|
|
||||||
if (program.frag_count > MAX_FRAG) {
|
init_shaders(program, project);
|
||||||
log_error("FRAG_COUNT over %d", MAX_FRAG);
|
|
||||||
program.error = true;
|
if (program->error) {
|
||||||
return program;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_gl(&program);
|
init_textures(program, context);
|
||||||
|
|
||||||
init_shaders(&program, project.fragment_shaders);
|
init_input(program, project->config, inputs);
|
||||||
|
|
||||||
if (program.error) {
|
init_framebuffers(program, project->config);
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_textures(&program, context);
|
init_programs(program, project->config, project->state_config);
|
||||||
|
|
||||||
init_input(&program, project.config, inputs);
|
init_vertices(program);
|
||||||
|
|
||||||
init_framebuffers(&program, project.config);
|
|
||||||
|
|
||||||
init_programs(&program, project.config, project.state_config);
|
|
||||||
|
|
||||||
init_vertices(&program);
|
|
||||||
|
|
||||||
// log_debug("Error after init: %04x",
|
// log_debug("Error after init: %04x",
|
||||||
// glGetError()); // TODO check error at each step
|
// glGetError()); // TODO check error at each step
|
||||||
} else {
|
|
||||||
program = *previous;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_vertices(&program, previous != NULL ? 1 : 0);
|
bind_vertices(program, rebind ? 1 : 0);
|
||||||
|
;
|
||||||
return program;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void shaders_update(ShaderProgram program, FileArray fragment_shaders,
|
void shaders_update(ShaderProgram program, File fragment_shader,
|
||||||
unsigned int i) {
|
unsigned int i) {
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
result = compile_shader(program.fragment_shaders[i],
|
result = compile_shader(program.fragment_shaders[i], fragment_shader.path,
|
||||||
fragment_shaders.values[i].path,
|
fragment_shader.content);
|
||||||
fragment_shaders.values[i].content);
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
glLinkProgram(program.programs[i]);
|
glLinkProgram(program.programs[i]);
|
||||||
|
|||||||
+4
-3
@@ -3,10 +3,11 @@
|
|||||||
#ifndef SHADERS_H
|
#ifndef SHADERS_H
|
||||||
#define SHADERS_H
|
#define SHADERS_H
|
||||||
|
|
||||||
ShaderProgram shaders_init(Project project, SharedContext *context,
|
void shaders_init(ShaderProgram *program, Project *project,
|
||||||
VideoCaptureArray inputs, ShaderProgram *previous);
|
SharedContext *context, VideoCaptureArray inputs,
|
||||||
|
bool rebind);
|
||||||
|
|
||||||
void shaders_update(ShaderProgram program, FileArray fragment_shaders,
|
void shaders_update(ShaderProgram program, File fragment_shader,
|
||||||
unsigned int i);
|
unsigned int i);
|
||||||
|
|
||||||
void shaders_compute(ShaderProgram program, SharedContext *context,
|
void shaders_compute(ShaderProgram program, SharedContext *context,
|
||||||
|
|||||||
+18
-11
@@ -4,17 +4,6 @@
|
|||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
char *string_concat(const char *s1, const char *s2) {
|
|
||||||
char *result;
|
|
||||||
|
|
||||||
result = malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator
|
|
||||||
|
|
||||||
strcpy(result, s1);
|
|
||||||
strcat(result, s2);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int string_trim(char *str) {
|
unsigned int string_trim(char *str) {
|
||||||
// https://www.delftstack.com/howto/c/trim-string-in-c/
|
// https://www.delftstack.com/howto/c/trim-string-in-c/
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
@@ -61,4 +50,22 @@ bool string_is_number(char *value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_replace_at(char *src, unsigned int from, unsigned int to,
|
||||||
|
char *rpl) {
|
||||||
|
unsigned long src_len, rpl_len;
|
||||||
|
char *dst;
|
||||||
|
|
||||||
|
src_len = strlen(src);
|
||||||
|
rpl_len = strlen(rpl);
|
||||||
|
|
||||||
|
dst =
|
||||||
|
malloc(src_len - (to - from) + rpl_len + 1); // +1 for the null-terminator
|
||||||
|
|
||||||
|
strncpy(dst, src, from);
|
||||||
|
strncpy(dst + from, rpl, rpl_len);
|
||||||
|
strncpy(dst + from + rpl_len, src + to, src_len - to);
|
||||||
|
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
+3
-2
@@ -3,10 +3,11 @@
|
|||||||
#ifndef STRINGS_H
|
#ifndef STRINGS_H
|
||||||
#define STRINGS_H
|
#define STRINGS_H
|
||||||
|
|
||||||
char *string_concat(const char *s1, const char *s2);
|
|
||||||
|
|
||||||
unsigned int string_trim(char *str);
|
unsigned int string_trim(char *str);
|
||||||
|
|
||||||
bool string_is_number(char *value);
|
bool string_is_number(char *value);
|
||||||
|
|
||||||
|
char *string_replace_at(char *src, unsigned int from, unsigned int to,
|
||||||
|
char *rpl);
|
||||||
|
|
||||||
#endif /* STRINGS_H */
|
#endif /* STRINGS_H */
|
||||||
+3
-2
@@ -242,12 +242,13 @@ typedef struct MidiDevice {
|
|||||||
|
|
||||||
typedef struct Project {
|
typedef struct Project {
|
||||||
bool error;
|
bool error;
|
||||||
|
char path[STR_LEN];
|
||||||
ConfigFile config;
|
ConfigFile config;
|
||||||
StateConfig state_config;
|
StateConfig state_config;
|
||||||
FileArray fragment_shaders;
|
|
||||||
File common_shader_code; // TODO change
|
|
||||||
unsigned int frag_count;
|
unsigned int frag_count;
|
||||||
unsigned int in_count;
|
unsigned int in_count;
|
||||||
|
UintArray sub_counts;
|
||||||
|
File fragment_shaders[MAX_FRAG][MAX_SUB_FILE + 1];
|
||||||
} Project;
|
} Project;
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
Reference in New Issue
Block a user