diff --git a/README.md b/README.md index a734da8..8ad6061 100644 --- a/README.md +++ b/README.md @@ -50,16 +50,19 @@ make install ## CLI arguments ```txt -usage: forge [-h] [-v] [-hr] [-s=SCREEN] [-f=FRAG_PATH] +usage: forge [-h] [-v] [-hr] [-s=SCREEN] [-f=DIR_PATH] [-fc=CFG_PATH] [-t=TEMPO] [--demo] Fusion Of Real-time Generative Effects. options: - -h, --help show this help message and exit - -v, --version print version - -hr, --hot-reload hot reload of shaders scripts - -s, --screen output screen number (default: primary) - -f, --frag fragment shader path (default: TODO) + -h, --help show this help message and exit + -v, --version print version + -hr, --hot-reload hot reload of shaders scripts + -s, --screen output screen number (default: primary) + -f, --frag fragment shaders directory (default: TODO) + -fc, --frag-config fragment shaders config file (default: TODO) + -t, --tempo base tempo (default: 120) + --demo demonstration mode ``` ## Release guide @@ -99,7 +102,7 @@ make -f Makefile.dev release-arch - [x] Select screen as argument / config - [x] fps in window title - [x] Clean code -- [x] Multi-stage shaders +- [ ] Multi-stage shaders - [x] Test 2 stages with render to texture - [x] 2 in 2 fx 1 mix 1 fx layout - [x] Include common code @@ -109,7 +112,7 @@ make -f Makefile.dev release-arch - [x] uniform config - [x] fragment config - [x] subroutines config - - [x] Clean code + - [ ] Clean code and fix things - [ ] Midi - [ ] Read Midi events - [ ] Read midi mapping config file @@ -117,14 +120,14 @@ make -f Makefile.dev release-arch - [ ] Save midi state - [ ] State machine with A/B switch - [ ] Tap-tempo feature - - [ ] Clean code + - [ ] Clean code and fix things - [ ] Video input - [ ] Fixed camera video - [ ] Video mapping config file - - [ ] Clean code + - [ ] Clean code and fix things - [ ] Monitor screen - [ ] 2nd window - - [ ] Use buffers as panels (INA A FXA / DEBUG A+B FXA+B / INB B FXB) - - [ ] Clean code + - [x] Use buffers as panels (INA A FXA / DEBUG A+B FXA+B / INB B FXB) + - [ ] Clean code and fix things - [ ] Packaging & install - [ ] Clone "shaders" and config in system path at setup \ No newline at end of file diff --git a/config/shaders.cfg b/config/shaders.cfg index 59b4e50..af69651 100644 --- a/config/shaders.cfg +++ b/config/shaders.cfg @@ -1,6 +1,7 @@ UNIFORM_TIME=iTime UNIFORM_TEMPO=iTempo UNIFORM_FPS=iFPS +UNIFORM_DEMO=iDemo UNIFORM_RESOLUTION=iResolution UNIFORM_TEX_PREFIX=tex diff --git a/shaders/frag0.glsl b/shaders/frag0.glsl index b3f57d2..0f0e947 100644 --- a/shaders/frag0.glsl +++ b/shaders/frag0.glsl @@ -10,6 +10,7 @@ uniform float iTime; uniform float iTempo; uniform int iFPS; uniform vec2 iResolution; +uniform int iDemo; // 2. textures // --------------- @@ -166,8 +167,8 @@ float cosTime(float k) vec2 magic_f(vec2 F, vec3 B, float i) { return vec2( - mix(F.x, randTime(i + 1), B.z), - mix(F.y, randTime(i + 2), B.z) + mix(F.x, randTime(i + 1), B.z + iDemo), + mix(F.y, randTime(i + 2), B.z + iDemo) ); } @@ -179,9 +180,9 @@ vec2 magic_f(float i) vec3 magic_b(vec3 B, float i) { return vec3( - mix(B.x, step(0.2, randTime(i + 3)), B.z), - mix(B.y, step(0.5, randTime(i + 4)), B.z), - B.z + mix(B.x, step(0.2, randTime(i + 3)), B.z + iDemo), + mix(B.y, step(0.5, randTime(i + 4)), B.z + iDemo), + min(1, B.z + iDemo) ); } @@ -1250,6 +1251,8 @@ subroutine(src_stage_sub) vec4 src_16(vec2 vUV, const float seed) // controls // logic + + // TODO tmp return vec4(0.0); } diff --git a/src/args.c b/src/args.c index 7c5ccf2..491f552 100644 --- a/src/args.c +++ b/src/args.c @@ -19,6 +19,8 @@ static void print_help(int status_code) { "[-s=SCREEN] " "[-f=DIR_PATH] " "[-fc=CFG_PATH] " + "[-t=TEMPO] " + "[--demo] " "\n\n" "Fusion Of Real-time Generative Effects.\n\n" "options:\n" @@ -27,7 +29,9 @@ static void print_help(int status_code) { " -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" - " -fc, --frag-config fragment shaders config file (default: TODO)\n"); + " -fc, --frag-config fragment shaders config file (default: TODO)\n" + " -t, --tempo base tempo (default: 120)\n" + " --demo demonstration mode\n"); exit(status_code); } @@ -59,6 +63,17 @@ static unsigned char parse_uchar(char *arg, char *value) { return (unsigned char)tmp_value; } +static unsigned short parse_ushort(char *arg, char *value) { + if (!string_is_number(value)) { + invalid_value(arg, value); + } + unsigned long long tmp_value = (unsigned long long)atoll(value); + if (tmp_value >= 65536) { + invalid_value(arg, value); + } + return (unsigned short)tmp_value; +} + Parameters args_parse(int argc, char **argv) { Parameters params; int i; @@ -69,6 +84,8 @@ Parameters args_parse(int argc, char **argv) { params.frag_path = 0; params.frag_config_path = 0; params.hot_reload = false; + params.base_tempo = 120.0f; + params.demo = false; for (i = 1; i < argc; i++) { arg = argv[i]; @@ -86,6 +103,10 @@ Parameters args_parse(int argc, char **argv) { params.frag_path = value; } else if (is_arg(arg, "-fc") || is_arg(arg, "--frag-config")) { params.frag_config_path = value; + } else if (is_arg(arg, "-t") || is_arg(arg, "--tempo")) { + params.base_tempo = (float)parse_ushort(arg, value); + } else if (is_arg(arg, "--demo")) { + params.demo = true; } else { invalid_arg(arg); } diff --git a/src/forge.c b/src/forge.c index 7643219..04bc07a 100644 --- a/src/forge.c +++ b/src/forge.c @@ -41,6 +41,24 @@ static unsigned int compute_fps(Window *window, Timer *timer) { return (unsigned int)round(fps); } +static void init_context(ShaderProgram program, Context *context, + Parameters params) { + int size; + context->tempo = params.base_tempo; + context->demo = params.demo; + + // TODO temporary state + size = program.frag_count * program.sub_type_count * sizeof(unsigned int); + context->sub_state = malloc(size); + memset(context->sub_state, 0, size); + context->sub_state[program.sub_type_count * 0 + 0] = 1; + context->sub_state[program.sub_type_count * 1 + 0] = 1; + context->sub_state[program.sub_type_count * 2 + 1] = 1; + context->sub_state[program.sub_type_count * 3 + 1] = 3; + context->sub_state[program.sub_type_count * 5 + 1] = 6; + // TODO fix here ?? +} + static void hot_reload(ShaderProgram program, File *common_shader_code, File *fragment_shaders) { unsigned int i; @@ -63,35 +81,20 @@ static void hot_reload(ShaderProgram program, File *common_shader_code, } static void loop(Window *window, ShaderProgram program, bool hr, - File *common_shader_code, File *fragment_shaders, - Timer *timer) { - Context context; - int size; + File *common_shader_code, File *fragment_shaders, Timer *timer, + Context *context) { if (hr) { hot_reload(program, common_shader_code, fragment_shaders); } - context = window_get_context(window); + window_get_context(window, context); - context.fps = compute_fps(window, timer); - context.tempo = 120.0f; // TODO need tempo here + context->fps = compute_fps(window, timer); - // TODO temporary state - size = program.frag_count * program.sub_type_count * sizeof(unsigned int); - context.sub_state = malloc(size); - memset(context.sub_state, 0, size); - context.sub_state[program.sub_type_count * 0 + 0] = 1; - context.sub_state[program.sub_type_count * 1 + 0] = 6; - context.sub_state[program.sub_type_count * 2 + 1] = 1; - context.sub_state[program.sub_type_count * 3 + 1] = 3; - context.sub_state[program.sub_type_count * 5 + 1] = 6; - - shaders_apply(program, context); + shaders_apply(program, *context); window_refresh(window); - - free(context.sub_state); } File read_fragment_shader_file(char *frag_path, unsigned int i) { @@ -157,7 +160,9 @@ void forge_run(Parameters params) { window = window_init(PACKAGE " " VERSION, params.screen, error_callback, key_callback); - context = window_get_context(window); + window_get_context(window, &context); + + init_context(program, &context, params); program = shaders_init(fragment_shaders, shader_config, context); @@ -172,7 +177,7 @@ void forge_run(Parameters params) { while (!window_should_close(window)) { loop(window, program, params.hot_reload, &common_shader_code, - fragment_shaders, &timer); + fragment_shaders, &timer, &context); } free_files(&common_shader_code, fragment_shaders, frag_count); @@ -180,4 +185,6 @@ void forge_run(Parameters params) { config_file_free(shader_config); window_close(window, true); + + free(context.sub_state); } \ No newline at end of file diff --git a/src/shaders.c b/src/shaders.c index 0ea5d0b..89f2e3c 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -158,6 +158,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i, program->ires_locations[i] = glGetUniformLocation( program->programs[i], config_file_get_str(shader_config, "UNIFORM_RESOLUTION", "iResolution")); + program->idemo_locations[i] = glGetUniformLocation( + program->programs[i], + config_file_get_str(shader_config, "UNIFORM_DEMO", "iDemo")); for (j = 0; j < program->sub_type_count; j++) { sprintf(name, "SUB_%d_PREFIX", j + 1); @@ -200,6 +203,7 @@ static void init_programs(ShaderProgram *program, ConfigFile shader_config) { program->itempo_locations = malloc(program->frag_count * sizeof(GLuint)); program->ifps_locations = malloc(program->frag_count * sizeof(GLuint)); program->ires_locations = malloc(program->frag_count * sizeof(GLuint)); + program->idemo_locations = malloc(program->frag_count * sizeof(GLuint)); program->vpos_locations = malloc(program->frag_count * sizeof(GLuint)); program->textures_locations = malloc(program->frag_count * program->tex_count * sizeof(GLuint)); @@ -307,6 +311,7 @@ static void use_program(ShaderProgram program, int i, bool output, glUniform1f(program.itime_locations[i], (const GLfloat)context.time); glUniform1f(program.itempo_locations[i], (const GLfloat)context.tempo); glUniform1i(program.ifps_locations[i], (const GLint)context.fps); + glUniform1i(program.idemo_locations[i], (const GLint)(context.demo ? 1 : 0)); glUniform2fv(program.ires_locations[i], 1, (const GLfloat *)&resolution); // set subroutines for fragment @@ -340,5 +345,5 @@ void shaders_apply(ShaderProgram program, Context context) { } } - use_program(program, program.frag_output_index, true, context); + use_program(program, program.frag_monitor_index, true, context); } diff --git a/src/types.h b/src/types.h index 5af57f7..0cd9b66 100644 --- a/src/types.h +++ b/src/types.h @@ -14,6 +14,8 @@ typedef struct Parameters { char *frag_path; char *frag_config_path; bool hot_reload; + float base_tempo; + bool demo; } Parameters; typedef struct Vertex { @@ -54,6 +56,7 @@ typedef struct ShaderProgram { GLuint *itempo_locations; GLuint *ifps_locations; GLuint *ires_locations; + GLuint *idemo_locations; GLuint *vpos_locations; @@ -73,6 +76,7 @@ typedef struct Context { unsigned int fps; float tempo; unsigned int *sub_state; + bool demo; } Context; typedef struct Timer { diff --git a/src/window.c b/src/window.c index d96eb3a..7109857 100644 --- a/src/window.c +++ b/src/window.c @@ -121,14 +121,10 @@ void window_refresh(Window *window) { glfwPollEvents(); } -Context window_get_context(Window *window) { - Context context; +void window_get_context(Window *window, Context *context) { + glfwGetFramebufferSize(window, &context->width, &context->height); - glfwGetFramebufferSize(window, &context.width, &context.height); - - context.time = glfwGetTime(); - - return context; + context->time = glfwGetTime(); } void window_close(Window *window, bool hard) { diff --git a/src/window.h b/src/window.h index fa850e3..d650d4f 100644 --- a/src/window.h +++ b/src/window.h @@ -11,7 +11,7 @@ void window_update_title(Window *window, char *title); void window_refresh(Window *window); -Context window_get_context(Window *window); +void window_get_context(Window *window, Context *context); void window_close(Window *window, bool hard);