diff --git a/Makefile.dev b/Makefile.dev index 758fd88..f98987e 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 --monitor --internal-size=480 +TEST_ARGS ?= --frag=./shaders --frag-config=./config/shaders.cfg --tempo=30 --internal-size=480 SHELL := /bin/bash .PHONY: build diff --git a/src/args.c b/src/args.c index 6d6a545..accfb1a 100644 --- a/src/args.c +++ b/src/args.c @@ -18,11 +18,11 @@ static void print_help(int status_code) { "[-v] " "[-hr] " "[-s=SCREEN] " + "[-m=SCREEN] " "[-f=DIR_PATH] " "[-fc=CFG_PATH] " "[-is=SIZE] " "[-t=TEMPO] " - "[-m] " "[--demo] " "[-w] " "\n\n" @@ -32,11 +32,11 @@ static void print_help(int status_code) { " -v, --version print version\n" " -hr, --hot-reload hot reload of shaders scripts\n" " -s, --screen output screen number (default: primary)\n" + " -m, --monitor monitor screen number (default: none)\n" " -f, --frag fragment shaders directory (default: TODO)\n" " -fc, --frag-config fragment shaders config file (default: TODO)\n" " -is, --internal-size internal texture height (default: 720)\n" " -t, --tempo base tempo (default: 60)\n" - " -m, --monitor output monitor\n" " --demo demonstration mode\n" " -w, --windowed not fullscreen\n"); exit(status_code); @@ -78,11 +78,12 @@ Parameters args_parse(int argc, char **argv) { params.hot_reload = false; params.screen = 0; + params.monitor_screen = 0; + params.monitor = false; params.frag_path = 0; params.frag_config_path = 0; params.internal_size = 720; params.base_tempo = 60.0f; - params.monitor = false; params.demo = false; params.windowed = false; @@ -105,9 +106,10 @@ Parameters args_parse(int argc, char **argv) { } else if (is_arg(arg, "-t") || is_arg(arg, "--tempo")) { params.base_tempo = (float)parse_uint(arg, value); } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { - params.internal_size = (float)parse_uint(arg, value); - } else if (is_arg(arg, "--monitor")) { + params.internal_size = parse_uint(arg, value); + } else if (is_arg(arg, "-m") || is_arg(arg, "--monitor")) { params.monitor = true; + params.monitor_screen = parse_uint(arg, value); } else if (is_arg(arg, "--demo")) { params.demo = true; } else if (is_arg(arg, "-w") || is_arg(arg, "--windowed")) { @@ -122,6 +124,12 @@ Parameters args_parse(int argc, char **argv) { exit(EXIT_FAILURE); } + if (params.monitor && params.monitor_screen == params.screen && + !params.windowed) { + log_error("monitor screen cannot be the same as output screen"); + exit(EXIT_FAILURE); + } + if (params.frag_path == 0) { log_error("required argument -fc/--frag-config"); exit(EXIT_FAILURE); diff --git a/src/forge.c b/src/forge.c index 1027946..83ca505 100644 --- a/src/forge.c +++ b/src/forge.c @@ -16,15 +16,22 @@ static Context context; static ShaderProgram program; +static ShaderProgram program_monitor; -static unsigned int compute_fps(Window *window, Timer *timer) { +static unsigned int compute_fps(Window *window_out, Window *window_monitor, + Timer *timer) { static double fps; char title[100]; if (timer_inc(timer)) { fps = timer_reset(timer); sprintf(title, PACKAGE " " VERSION " - %.0ffps", fps); - window_update_title(window, title); + window_update_title(window_out, title); + + if (window_monitor != NULL) { + sprintf(title, PACKAGE " " VERSION " (monitor) - %.0ffps", fps); + window_update_title(window_monitor, title); + } } return (unsigned int)round(fps); @@ -88,20 +95,35 @@ static void hot_reload(File *common_shader_code, File *fragment_shaders) { } } -static void loop(Window *window, bool hr, File *common_shader_code, - File *fragment_shaders, Timer *timer) { +static void loop(Window *window_out, Window *window_monitor, bool hr, + File *common_shader_code, File *fragment_shaders, + Timer *timer) { if (hr) { hot_reload(common_shader_code, fragment_shaders); } - window_get_context(window, &context); + context.fps = compute_fps(window_out, window_monitor, timer); - context.fps = compute_fps(window, timer); + window_get_context(window_out, &context, true); - shaders_apply(program, context); + window_use(window_out); - window_refresh(window); + shaders_compute(program, context, false); + + window_refresh(window_out); + + if (window_monitor != NULL) { + window_get_context(window_monitor, &context, false); + + window_use(window_monitor); + + shaders_compute(program_monitor, context, true); + + window_refresh(window_monitor); + } + + window_events(); } File read_fragment_shader_file(char *frag_path, unsigned int i) { @@ -170,7 +192,8 @@ void forge_run(Parameters params) { unsigned int frag_count; File *fragment_shaders; File common_shader_code; - Window *window; + Window *window_out; + Window *window_monitor; Timer timer; ConfigFile shader_config; @@ -183,19 +206,36 @@ void forge_run(Parameters params) { init_files(params.frag_path, &common_shader_code, fragment_shaders, frag_count); - window = window_init(PACKAGE " " VERSION, params.screen, params.windowed, - error_callback, key_callback); + window_startup(error_callback); - window_get_context(window, &context); + window_out = window_init(PACKAGE " " VERSION, params.screen, params.windowed, + NULL, key_callback); + + window_get_context(window_out, &context, true); context.internal_size = params.internal_size; program = shaders_init(fragment_shaders, shader_config, context); + if (params.monitor) { + window_monitor = + window_init(PACKAGE " " VERSION " (monitor)", params.monitor_screen, + params.windowed, window_out, key_callback); + + window_get_context(window_monitor, &context, false); + + program_monitor = shaders_init(fragment_shaders, shader_config, context); + } else { + window_monitor = NULL; + } + init_context(params); if (program.error) { - window_close(window, true); + window_close(window_out, true); + if (window_monitor != NULL) { + window_close(window_monitor, true); + } exit(EXIT_FAILURE); } @@ -203,16 +243,20 @@ void forge_run(Parameters params) { log_success("Initialized"); - while (!window_should_close(window)) { - loop(window, params.hot_reload, &common_shader_code, fragment_shaders, - &timer); + while (!window_should_close(window_out) && + (window_monitor == NULL || !window_should_close(window_monitor))) { + loop(window_out, window_monitor, params.hot_reload, &common_shader_code, + fragment_shaders, &timer); } free_files(&common_shader_code, fragment_shaders, frag_count); config_file_free(shader_config); - window_close(window, true); + window_close(window_out, true); + if (window_monitor != NULL) { + window_close(window_monitor, true); + } free_context(); } \ No newline at end of file diff --git a/src/shaders.c b/src/shaders.c index fdeff69..c453e8a 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -46,6 +46,9 @@ static void init_textures(ShaderProgram *program, Context context) { // selects which texture unit subsequent texture state calls will affect glActiveTexture(GL_TEXTURE0 + i); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, program->textures[i]); // define texture image as empty @@ -381,7 +384,7 @@ static void use_program(ShaderProgram program, int i, bool output, glDrawArrays(GL_TRIANGLES, 0, 6); } -void shaders_apply(ShaderProgram program, Context context) { +void shaders_compute(ShaderProgram program, Context context, bool monitor) { unsigned int i; update_viewport(program, context); @@ -393,7 +396,6 @@ void shaders_apply(ShaderProgram program, Context context) { } use_program(program, - context.monitor ? program.frag_monitor_index - : program.frag_output_index, + monitor ? program.frag_monitor_index : program.frag_output_index, true, context); -} +} \ No newline at end of file diff --git a/src/shaders.h b/src/shaders.h index 12fca2b..92308c6 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -9,6 +9,6 @@ ShaderProgram shaders_init(File *fragment_shaders, ConfigFile shader_config, void shaders_update(ShaderProgram program, File *fragment_shaders, unsigned int i); -void shaders_apply(ShaderProgram program, Context context); +void shaders_compute(ShaderProgram program, Context context, bool monitor); #endif /* SHADERS_H */ \ No newline at end of file diff --git a/src/types.h b/src/types.h index 7cae450..cc3271f 100644 --- a/src/types.h +++ b/src/types.h @@ -12,11 +12,12 @@ typedef struct Parameters { bool hot_reload; unsigned char screen; + unsigned char monitor_screen; + bool monitor; char *frag_path; char *frag_config_path; unsigned int internal_size; float base_tempo; - bool monitor; bool demo; bool windowed; } Parameters; diff --git a/src/window.c b/src/window.c index a5789a1..615e811 100644 --- a/src/window.c +++ b/src/window.c @@ -25,11 +25,6 @@ static void init_glfw(void (*error_callback)(int, const char *)) { exit(EXIT_FAILURE); } - // Context related hints - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - log_success("[GLFS] Initialized..."); } @@ -51,9 +46,9 @@ static GLFWmonitor *get_monitor(unsigned char monitor_index) { return monitors[monitor_index]; } -static GLFWwindow *create_window(GLFWmonitor *monitor, char *title, - void (*key_callback)(Window *, int, int, int, - int)) { +static GLFWwindow * +create_window(GLFWmonitor *monitor, char *title, Window *shared_context, + void (*key_callback)(Window *, int, int, int, int)) { GLFWwindow *window; log_info("[GLFW] Creating window..."); @@ -64,8 +59,13 @@ static GLFWwindow *create_window(GLFWmonitor *monitor, char *title, glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_FALSE); glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); + // Context related hints + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + // create fullscreen window in selected monitor - window = glfwCreateWindow(1, 1, title, monitor, NULL); + window = glfwCreateWindow(1, 1, title, monitor, shared_context); // handle window creation fail if (window == NULL) { @@ -93,17 +93,19 @@ static void use_window(GLFWwindow *window) { glfwSwapInterval(1); } +void window_startup(void (*error_callback)(int, const char *)) { + init_glfw(error_callback); +} + Window *window_init(char *title, unsigned char monitor_index, bool windowed, - void (*error_callback)(int, const char *), + Window *shared_context, void (*key_callback)(Window *, int, int, int, int)) { GLFWwindow *window; GLFWmonitor *monitor; - init_glfw(error_callback); - monitor = windowed ? NULL : get_monitor(monitor_index); - window = create_window(monitor, title, key_callback); + window = create_window(monitor, title, shared_context, key_callback); use_window(window); @@ -114,17 +116,24 @@ void window_update_title(Window *window, char *title) { glfwSetWindowTitle(window, title); } +void window_use(Window *window) { + glfwMakeContextCurrent(window); + gladLoadGL(glfwGetProcAddress); +} + void window_refresh(Window *window) { // swap front and back buffers glfwSwapBuffers(window); - // listen to mouse and keyboard events - glfwPollEvents(); } -void window_get_context(Window *window, Context *context) { +void window_events() { glfwPollEvents(); } + +void window_get_context(Window *window, Context *context, bool with_time) { glfwGetFramebufferSize(window, &context->width, &context->height); - context->time = glfwGetTime(); + if (with_time) { + context->time = glfwGetTime(); + } } void window_close(Window *window, bool hard) { diff --git a/src/window.h b/src/window.h index 4ccc139..26351e4 100644 --- a/src/window.h +++ b/src/window.h @@ -3,15 +3,21 @@ #ifndef WINDOW_H #define WINDOW_H +void window_startup(void (*error_callback)(int, const char *)); + Window *window_init(char *title, unsigned char monitor_index, bool windowed, - void (*error_callback)(int, const char *), + Window *shared_context, void (*key_callback)(Window *, int, int, int, int)); void window_update_title(Window *window, char *title); +void window_use(Window *window); + void window_refresh(Window *window); -void window_get_context(Window *window, Context *context); +void window_events(); + +void window_get_context(Window *window, Context *context, bool with_time); void window_close(Window *window, bool hard);