diff --git a/Makefile.dev b/Makefile.dev index a67a2e9..2908b31 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -1,6 +1,6 @@ TARGET ?= forge INSTALL_DIR ?= $(HOME)/.local/bin -TEST_ARGS ?= --frag=./shaders --frag-config=./config/shaders.cfg --tempo=30 +TEST_ARGS ?= --frag=./shaders --monitor=1 --frag-config=./config/shaders.cfg --tempo=30 SHELL := /bin/bash .PHONY: build @@ -20,7 +20,7 @@ build: .PHONY: run run: build - ./build/$(TARGET) $(TEST_ARGS) --monitor-only --hot-reload + ./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=240 --hot-reload .PHONY: demo demo: build diff --git a/README.md b/README.md index 218c431..23d786e 100644 --- a/README.md +++ b/README.md @@ -140,5 +140,6 @@ make -f Makefile.dev release-arch - [x] 2nd window - [x] Use buffers as panels (INA A FXA / DEBUG A+B FXA+B / INB B FXB) - [x] Clean code and fix things + - [x] Share openGL state between monitor and screen - [ ] Packaging & install - [ ] Clone "shaders" and config in system path at setup \ No newline at end of file diff --git a/src/args.c b/src/args.c index a118928..37e9b81 100644 --- a/src/args.c +++ b/src/args.c @@ -24,7 +24,6 @@ static void print_help(int status_code) { "[-f=DIR_PATH] " "[-fc=CFG_PATH] " "[-is=SIZE] " - "[-mf=FACTOR] " "[-t=TEMPO] " "[--demo] " "[-w] " @@ -41,7 +40,6 @@ static void print_help(int status_code) { " -fc, --frag-config fragment shaders config file (default: " "TODO)\n" " -is, --internal-size internal texture height (default: 720)\n" - " -mf, --monitor-factor monitor internal texture downscale factor " "(default: " "3)\n" " -t, --tempo base tempo (default: 60)\n" @@ -92,7 +90,6 @@ Parameters args_parse(int argc, char **argv) { params.frag_path = 0; params.frag_config_path = 0; params.internal_size = 720; - params.monitor_factor = 3; params.base_tempo = 60.0f; params.demo = false; params.windowed = false; @@ -117,8 +114,6 @@ Parameters args_parse(int argc, char **argv) { params.base_tempo = (float)parse_uint(arg, value); } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { params.internal_size = parse_uint(arg, value); - } else if (is_arg(arg, "-mf") || is_arg(arg, "--monitor-factor")) { - params.monitor_factor = parse_uint(arg, value); } else if (is_arg(arg, "-m") || is_arg(arg, "--monitor")) { params.monitor = true; params.monitor_screen = parse_uint(arg, value); diff --git a/src/forge.c b/src/forge.c index d77bb36..6f37a7e 100644 --- a/src/forge.c +++ b/src/forge.c @@ -16,7 +16,6 @@ static Context context; static ShaderProgram program; -static ShaderProgram program_monitor; static Window *window_output; static Window *window_monitor; @@ -43,34 +42,22 @@ static unsigned int compute_fps(Timer *timer) { static void randomize_context_state() { unsigned int i; - unsigned int size; - unsigned int variants; - size = window_output != NULL - ? program.frag_count * program.sub_type_count - : program_monitor.frag_count * program_monitor.sub_type_count; - - variants = window_output != NULL ? program.sub_variant_count - : program_monitor.sub_variant_count; - - for (i = 0; i < size; i++) { - context.sub_state[i] = rand_uint(variants); + for (i = 0; i < program.frag_count * program.sub_type_count; i++) { + context.sub_state[i] = rand_uint(program.sub_variant_count); } } static void init_context(Parameters params) { - unsigned int size; unsigned int i; context.tempo = params.base_tempo; context.demo = params.demo; context.monitor = params.monitor; - size = window_output != NULL - ? program.frag_count * program.sub_type_count - : program_monitor.frag_count * program_monitor.sub_type_count; - context.sub_state = malloc(size * sizeof(unsigned int)); + context.sub_state = malloc(program.frag_count * program.sub_type_count * + sizeof(unsigned int)); - for (i = 0; i < size; i++) { + for (i = 0; i < program.frag_count * program.sub_type_count; i++) { context.sub_state[i] = 0; } @@ -78,10 +65,8 @@ static void init_context(Parameters params) { randomize_context_state(); } - size = - window_output != NULL ? program.frag_count : program_monitor.frag_count; - context.seeds = malloc(size * sizeof(unsigned int)); - for (i = 0; i < size; i++) { + context.seeds = malloc(program.frag_count * sizeof(unsigned int)); + for (i = 0; i < program.frag_count; i++) { context.seeds[i] = rand_uint(1000); } } @@ -93,37 +78,27 @@ static void free_context() { static void hot_reload(File *common_shader_code, File *fragment_shaders) { unsigned int i; - unsigned int frag_count; bool force_update; force_update = false; - frag_count = - window_output != NULL ? program.frag_count : program_monitor.frag_count; - if (file_should_update(*common_shader_code)) { file_update(common_shader_code); force_update = true; } - for (i = 0; i < frag_count; i++) { + for (i = 0; i < program.frag_count; i++) { if (force_update || file_should_update(fragment_shaders[i])) { file_update(&fragment_shaders[i]); file_prepend(&fragment_shaders[i], *common_shader_code); - if (window_output != NULL) { - shaders_update(program, fragment_shaders, i); - } - - if (window_monitor != NULL) { - shaders_update(program_monitor, fragment_shaders, i); - } + shaders_update(program, fragment_shaders, i); } } } static void loop(bool hr, File *common_shader_code, File *fragment_shaders, - unsigned int monitor_factor, Timer *timer) { + Timer *timer) { if (hr) { hot_reload(common_shader_code, fragment_shaders); } @@ -135,7 +110,7 @@ static void loop(bool hr, File *common_shader_code, File *fragment_shaders, if (window_output != NULL) { window_use(window_output, &context); - shaders_compute(program, context, false, 1); + shaders_compute(program, context, false, false); window_refresh(window_output); } @@ -143,7 +118,7 @@ static void loop(bool hr, File *common_shader_code, File *fragment_shaders, if (window_monitor != NULL) { window_use(window_monitor, &context); - shaders_compute(program_monitor, context, true, monitor_factor); + shaders_compute(program, context, true, window_output != NULL); window_refresh(window_monitor); } @@ -239,7 +214,7 @@ void forge_run(Parameters params) { window_use(window_output, &context); - program = shaders_init(fragment_shaders, shader_config, context, 1); + program = shaders_init(fragment_shaders, shader_config, context, NULL); } else { window_output = NULL; } @@ -251,16 +226,15 @@ void forge_run(Parameters params) { window_use(window_monitor, &context); - program_monitor = shaders_init(fragment_shaders, shader_config, context, - params.monitor_factor); + program = shaders_init(fragment_shaders, shader_config, context, + window_output != NULL ? &program : NULL); } else { window_monitor = NULL; } init_context(params); - if ((window_output != NULL && program.error) || - (window_monitor != NULL && program_monitor.error)) { + if (program.error) { if (window_output != NULL) { window_close(window_output, true); } @@ -276,8 +250,7 @@ void forge_run(Parameters params) { while ((window_output == NULL || !window_should_close(window_output)) && (window_monitor == NULL || !window_should_close(window_monitor))) { - loop(params.hot_reload, &common_shader_code, fragment_shaders, - params.monitor_factor, &timer); + loop(params.hot_reload, &common_shader_code, fragment_shaders, &timer); } free_files(&common_shader_code, fragment_shaders, frag_count); diff --git a/src/shaders.c b/src/shaders.c index 9fa43fd..1c893d3 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -35,8 +35,7 @@ static bool compile_shader(GLuint shader_id, char *name, char *source_code) { return status_params == GL_TRUE; } -static void init_textures(ShaderProgram *program, Context context, - unsigned int downscaling) { +static void init_textures(ShaderProgram *program, Context context) { unsigned int i; program->textures = malloc(program->tex_count * sizeof(GLuint)); @@ -47,23 +46,30 @@ static void init_textures(ShaderProgram *program, Context context, // selects which texture unit subsequent texture state calls will affect glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, program->textures[i]); + + glEnable(GL_TEXTURE_2D); + glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, program->textures[i]); - // define texture image as empty - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - (int)((context.internal_size / downscaling) * - (float)context.width / (context.height)), - context.internal_size / downscaling, 0, GL_RGB, - GL_UNSIGNED_BYTE, 0); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGB, + (int)(context.internal_size * (float)context.width / (context.height)), + context.internal_size, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); // setup mipmap context glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } +} - log_success("Texture %d initialized", i); +static void rebind_textures(ShaderProgram *program) { + unsigned int i; + for (i = 0; i < program->tex_count; i++) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, program->textures[i]); } } @@ -105,15 +111,33 @@ static void init_framebuffers(ShaderProgram *program, return; } -static void init_vertices(ShaderProgram *program) { +static void init_vertices(ShaderProgram *program, bool rebind) { + unsigned int i; + // create vertex buffer and setup vertices - glGenBuffers(1, &program->vertex_buffer); + if (!rebind) { + glGenBuffers(1, &program->vertex_buffer); + } glBindBuffer(GL_ARRAY_BUFFER, program->vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // create vertex array - glGenVertexArrays(1, &program->vertex_array); - glBindVertexArray(program->vertex_array); + if (!rebind) { + glGenVertexArrays(1, &program->vertex_array[0]); + glBindVertexArray(program->vertex_array[0]); + } else { + glGenVertexArrays(1, &program->vertex_array[1]); + glBindVertexArray(program->vertex_array[1]); + } + + for (i = 0; i < program->frag_count; i++) { + // enable attribute pointer + glEnableVertexAttribArray(program->vpos_locations[i]); + // specify the location and data format of the array of generic vertex + // attributes to use when rendering + glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void *)offsetof(Vertex, pos)); + } } static void init_shaders(ShaderProgram *program, File *fragment_shaders) { @@ -147,7 +171,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i, char *sub_prefix; char *seed_prefix; char *state_prefix; - program->programs[i] = glCreateProgram(); glAttachShader(program->programs[i], program->vertex_shader); @@ -214,12 +237,6 @@ static void init_single_program(ShaderProgram *program, unsigned int i, // create attribute pointer program->vpos_locations[i] = glGetAttribLocation(program->programs[i], "vPos"); - // enable attribute pointer - glEnableVertexAttribArray(program->vpos_locations[i]); - // specify the location and data format of the array of generic vertex - // attributes to use when rendering - glVertexAttribPointer(program->vpos_locations[i], 2, GL_FLOAT, GL_FALSE, - sizeof(Vertex), (void *)offsetof(Vertex, pos)); log_success("Program %d initialized", i + 1); } @@ -250,36 +267,41 @@ static void init_programs(ShaderProgram *program, ConfigFile shader_config) { } ShaderProgram shaders_init(File *fragment_shaders, ConfigFile shader_config, - Context context, unsigned int downscaling) { + Context context, ShaderProgram *previous) { ShaderProgram program; - program.error = false; - program.last_width = context.width; - program.last_height = context.height; - program.tex_count = config_file_get_int(shader_config, "TEX_COUNT", 9); - program.frag_count = config_file_get_int(shader_config, "FRAG_COUNT", 6); - program.frag_output_index = - config_file_get_int(shader_config, "FRAG_OUTPUT", 1) - 1; - program.frag_monitor_index = - config_file_get_int(shader_config, "FRAG_MONITOR", 1) - 1; - program.sub_type_count = - config_file_get_int(shader_config, "SUB_TYPE_COUNT", 0); - program.sub_variant_count = - config_file_get_int(shader_config, "SUB_VARIANT_COUNT", 1); + if (previous == NULL) { + program.error = false; + program.last_width = context.width; + program.last_height = context.height; + program.tex_count = config_file_get_int(shader_config, "TEX_COUNT", 9); + program.frag_count = config_file_get_int(shader_config, "FRAG_COUNT", 6); + program.frag_output_index = + config_file_get_int(shader_config, "FRAG_OUTPUT", 1) - 1; + program.frag_monitor_index = + config_file_get_int(shader_config, "FRAG_MONITOR", 1) - 1; + program.sub_type_count = + config_file_get_int(shader_config, "SUB_TYPE_COUNT", 0); + program.sub_variant_count = + config_file_get_int(shader_config, "SUB_VARIANT_COUNT", 1); - init_textures(&program, context, downscaling); + init_shaders(&program, fragment_shaders); - init_framebuffers(&program, shader_config); + if (program.error) { + return program; + } - init_shaders(&program, fragment_shaders); + init_textures(&program, context); - if (program.error) { - return program; + init_framebuffers(&program, shader_config); + + init_programs(&program, shader_config); + + } else { + program = *previous; } - init_vertices(&program); - - init_programs(&program, shader_config); + init_vertices(&program, previous != NULL); return program; } @@ -298,8 +320,7 @@ void shaders_update(ShaderProgram program, File *fragment_shaders, } } -static void update_viewport(ShaderProgram program, Context context, - unsigned int downscaling) { +static void update_viewport(ShaderProgram program, Context context) { unsigned int i; // viewport changed @@ -309,16 +330,15 @@ static void update_viewport(ShaderProgram program, Context context, for (i = 0; i < program.tex_count; i++) { glActiveTexture(GL_TEXTURE0 + i); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - (int)((context.internal_size / downscaling) * - (float)context.width / (context.height)), - (int)(float)context.internal_size / downscaling, 0, GL_RGB, - GL_UNSIGNED_BYTE, 0); + (int)(context.internal_size * (float)context.width / + (context.height)), + context.internal_size, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); } } } static void use_program(ShaderProgram program, int i, bool output, - Context context, unsigned int downscaling) { + Context context) { unsigned int j, k; GLuint *subroutines; vec2 resolution; @@ -339,10 +359,10 @@ static void use_program(ShaderProgram program, int i, bool output, // clear buffer glClear(GL_COLOR_BUFFER_BIT); } else { - glViewport(0, 0, - (int)((context.internal_size / downscaling) * - (float)context.width / (context.height)), - (int)(float)context.internal_size / downscaling); + glViewport( + 0, 0, + (int)(context.internal_size * (float)context.width / (context.height)), + context.internal_size); // use memory framebuffer glBindFramebuffer(GL_FRAMEBUFFER, program.frame_buffers[i]); @@ -389,18 +409,26 @@ static void use_program(ShaderProgram program, int i, bool output, } void shaders_compute(ShaderProgram program, Context context, bool monitor, - unsigned int downscaling) { + bool output_only) { unsigned int i; - update_viewport(program, context, downscaling); + if (!output_only) { + glBindVertexArray(program.vertex_array[0]); - for (i = 0; i < program.frag_count; i++) { - if (i != program.frag_output_index && i != program.frag_monitor_index) { - use_program(program, i, false, context, downscaling); + update_viewport(program, context); + + for (i = 0; i < program.frag_count; i++) { + if (i != program.frag_output_index && i != program.frag_monitor_index) { + use_program(program, i, false, context); + } } + } else { + glBindVertexArray(program.vertex_array[1]); + + rebind_textures(&program); } use_program(program, monitor ? program.frag_monitor_index : program.frag_output_index, - true, context, downscaling); + true, context); } \ No newline at end of file diff --git a/src/shaders.h b/src/shaders.h index fc4963a..4dd3992 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -4,12 +4,12 @@ #define SHADERS_H ShaderProgram shaders_init(File *fragment_shaders, ConfigFile shader_config, - Context context, unsigned int downscaling); + Context context, ShaderProgram *shared_program); void shaders_update(ShaderProgram program, File *fragment_shaders, unsigned int i); void shaders_compute(ShaderProgram program, Context context, bool monitor, - unsigned int downscaling); + bool output_only); #endif /* SHADERS_H */ \ No newline at end of file diff --git a/src/types.h b/src/types.h index 16fce5c..9726cc7 100644 --- a/src/types.h +++ b/src/types.h @@ -18,7 +18,6 @@ typedef struct Parameters { char *frag_path; char *frag_config_path; unsigned int internal_size; - unsigned int monitor_factor; float base_tempo; bool demo; bool windowed; @@ -44,7 +43,7 @@ typedef struct ShaderProgram { GLuint vertex_shader; GLuint vertex_buffer; - GLuint vertex_array; + GLuint vertex_array[2]; unsigned int tex_count; GLuint *textures;