From 809ce7cdc95cd602223333b53761735238b5b48a Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 3 Nov 2022 14:48:51 -0400 Subject: custom bg-shader --- command.c | 3 +++ config.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- main.c | 49 ++++++++++++++++++++++++++++++++++++------------- ted.c | 16 +++++++++++++++- ted.cfg | 16 ++++++++++++++++ ted.h | 6 ++++++ 6 files changed, 138 insertions(+), 15 deletions(-) diff --git a/command.c b/command.c index 51c5c24..ce447ed 100644 --- a/command.c +++ b/command.c @@ -203,6 +203,7 @@ void command_execute(Ted *ted, Command c, i64 argument) { ted_new_file(ted, NULL); break; case CMD_SAVE: + ted->last_save_time = time_get_seconds(); if (buffer) { if (buffer_is_untitled(buffer)) { command_execute(ted, CMD_SAVE_AS, 1); @@ -212,11 +213,13 @@ void command_execute(Ted *ted, Command c, i64 argument) { } break; case CMD_SAVE_AS: + ted->last_save_time = time_get_seconds(); if (buffer && !buffer->is_line_buffer) { menu_open(ted, MENU_SAVE_AS); } break; case CMD_SAVE_ALL: + ted->last_save_time = time_get_seconds(); ted_save_all(ted); break; case CMD_RELOAD_ALL: diff --git a/config.c b/config.c index 17dbf73..612a647 100644 --- a/config.c +++ b/config.c @@ -43,6 +43,12 @@ static bool context_is_parent(const SettingsContext *parent, const SettingsConte static void settings_copy(Settings *dest, const Settings *src) { *dest = *src; + + // we only use this function before generating these + assert(!src->bg_shader); + assert(!src->bg_buffer); + assert(!src->bg_array); + context_copy(&dest->context, &src->context); for (u32 i = 0; i < LANG_COUNT; ++i) { if (src->language_extensions[i]) @@ -59,7 +65,13 @@ static void settings_free(Settings *settings) { context_free(&settings->context); for (u32 i = 0; i < LANG_COUNT; ++i) free(settings->language_extensions[i]); - memset(settings, 0, sizeof *settings); + if (settings->bg_shader) + glDeleteProgram(settings->bg_shader); + if (settings->bg_buffer) + glDeleteBuffers(1, &settings->bg_buffer); + if (settings->bg_array) + glDeleteVertexArrays(1, &settings->bg_array); + memset(settings, 0, sizeof *settings); } static void config_part_free(ConfigPart *part) { @@ -272,6 +284,7 @@ static OptionFloat const options_float[] = { }; static OptionString const options_string[] = { {"build-default-command", options_zero.build_default_command, sizeof options_zero.build_default_command, true}, + {"bg-shader", options_zero.bg_shader_text, sizeof options_zero.bg_shader_text, true}, }; static void option_bool_set(Settings *settings, const OptionBool *opt, bool value) { @@ -861,6 +874,54 @@ void config_parse(Ted *ted, ConfigPart **pparts) { } } + arr_foreach_ptr(ted->all_settings, Settings, s) { + if (*s->bg_shader_text) { + // load bg shader + char vshader[] = "#version 110\n\ + attribute vec2 v_pos;\n\ + varying vec2 t_pos;\n\ + void main() { \n\ + gl_Position = vec4(v_pos * 2.0 - 1.0, 0.0, 1.0);\n\ + t_pos = v_pos;\n\ + }"; + char fshader[8192]; + strbuf_printf(fshader, "#version 110\n\ + varying vec2 t_pos;\n\ + uniform float t_time;\n\ + uniform float t_save_time;\n\ + uniform vec2 t_aspect;\n\ + #line 1\n\ + %s", settings->bg_shader_text); + s->bg_shader = gl_compile_and_link_shaders(ted->error, vshader, fshader); + if (s->bg_shader) { + GLuint bg_buffer = 0, bg_array = 0; + glGenBuffers(1, &bg_buffer); + if (gl_version_major >= 3) { + glGenVertexArrays(1, &bg_array); + glBindVertexArray(bg_array); + } + + s->bg_buffer = bg_buffer; + s->bg_array = bg_array; + + float bg_buffer_data[][2] = { + {0,0}, + {1,0}, + {1,1}, + {0,0}, + {1,1}, + {0,1} + }; + + GLuint v_pos = (GLuint)glGetAttribLocation(s->bg_shader, "v_pos"); + glBindBuffer(GL_ARRAY_BUFFER, bg_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof bg_buffer_data, bg_buffer_data, GL_STATIC_DRAW); + glVertexAttribPointer(v_pos, 2, GL_FLOAT, 0, 2 * sizeof(float), 0); + glEnableVertexAttribArray(v_pos); + } + } + } + arr_foreach_ptr(parts, ConfigPart, part) { config_part_free(part); } diff --git a/main.c b/main.c index 0bd2c85..b61cf9f 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,7 @@ /* FUTURE FEATURES: -- custom shaders - - texture, time, time since last save +- custom shaders texture - config variables -- config multi-line strings - plugins? */ @@ -326,6 +324,7 @@ int main(int argc, char **argv) { if (!ted) { die("Not enough memory available to run ted."); } + ted->last_save_time = -1e50; // make sure signal handler has access to ted. error_signal_handler_ted = ted; @@ -411,13 +410,6 @@ int main(int argc, char **argv) { char config_err[sizeof ted->error] = {0}; PROFILE_TIME(misc_end) - PROFILE_TIME(configs_start) - ted_load_configs(ted, false); - if (ted_haserr(ted)) { - strcpy(config_err, ted->error); - ted_clearerr(ted); // clear the error so later things (e.g. loading font) don't detect an error - } - PROFILE_TIME(configs_end) PROFILE_TIME(window_start) SDL_Window *window = SDL_CreateWindow("ted", SDL_WINDOWPOS_UNDEFINED, @@ -456,11 +448,11 @@ int main(int argc, char **argv) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); #endif glctx = SDL_GL_CreateContext(window); - if (!glctx) { + if (glctx) { + break; + } else { debug_println("Couldn't get GL %d.%d context. Falling back to %d.%d.", gl_versions[i][0], gl_versions[i][1], gl_versions[i+1][0], gl_versions[i+1][1]); - gl_version_major = 3; - gl_version_minor = 0; } } @@ -488,6 +480,14 @@ int main(int argc, char **argv) { PROFILE_TIME(gl_end) + PROFILE_TIME(configs_start) + ted_load_configs(ted, false); + if (ted_haserr(ted)) { + strcpy(config_err, ted->error); + ted_clearerr(ted); // clear the error so later things (e.g. loading font) don't detect an error + } + PROFILE_TIME(configs_end) + PROFILE_TIME(fonts_start) ted_load_fonts(ted); PROFILE_TIME(fonts_end) @@ -571,6 +571,8 @@ int main(int argc, char **argv) { while (SDL_PollEvent(&event)); } + double start_time = time_get_seconds(); + while (!ted->quit) { double frame_start = time_get_seconds(); @@ -786,6 +788,27 @@ int main(int argc, char **argv) { } glClear(GL_COLOR_BUFFER_BIT); + { + // background shader + Settings *s = ted_active_settings(ted); + if (s->bg_shader) { + glUseProgram(s->bg_shader); + if (s->bg_array) + glBindVertexArray(s->bg_array); + double t = time_get_seconds(); + glUniform1f(glGetUniformLocation(s->bg_shader, "t_time"), (float)fmod(t - start_time, 3600)); + glUniform2f(glGetUniformLocation(s->bg_shader, "t_aspect"), (float)window_width / (float)window_height, 1); + glUniform1f(glGetUniformLocation(s->bg_shader, "t_save_time"), (float)(t - ted->last_save_time)); + glBindBuffer(GL_ARRAY_BUFFER, s->bg_buffer); + if (!s->bg_array) { + GLuint v_pos = (GLuint)glGetAttribLocation(s->bg_shader, "v_pos"); + glVertexAttribPointer(v_pos, 2, GL_FLOAT, 0, 2 * sizeof(float), 0); + glEnableVertexAttribArray(v_pos); + } + glDrawArrays(GL_TRIANGLES, 0, 6); + } + } + Font *font = ted->font; // default window title diff --git a/ted.c b/ted.c index 2d19a02..5d82198 100644 --- a/ted.c +++ b/ted.c @@ -49,7 +49,21 @@ static void *ted_realloc(Ted *ted, void *p, size_t new_size) { } Settings *ted_active_settings(Ted *ted) { - return ted->active_buffer ? buffer_settings(ted->active_buffer) : ted->default_settings; + if (ted->active_buffer) + return buffer_settings(ted->active_buffer); + Settings *settings = ted->default_settings; + int settings_score = 0; + arr_foreach_ptr(ted->all_settings, Settings, s) { + const SettingsContext *c = &s->context; + if (c->language != 0) continue; + if (!c->path || !str_has_prefix(ted->cwd, c->path)) continue; + int score = (int)strlen(c->path); + if (score > settings_score) { + settings = s; + settings_score = score; + } + } + return settings; } u32 ted_color(Ted *ted, ColorSetting color) { diff --git a/ted.cfg b/ted.cfg index c7a08a7..0c142b1 100644 --- a/ted.cfg +++ b/ted.cfg @@ -36,6 +36,22 @@ tags-max-depth = 2 # regenerate tags if an identifier is not found (with Ctrl+click)? regenerate-tags-if-not-found = yes +# you can make your own custom background for ted using a shader. +# an example is provided here. you will have access to the following variables: +# t_pos - screen position of fragment (0,0) to (1,1) +# t_aspect - (window_width / window_height, 1) +# t_time - current time in seconds, modulo 3600 +# t_save_time - time since last save, in seconds. +# if you want your shader supported no matter what, only use stuff from GLSL version 110. +# on non-ancient computers, you should be able to use GLSL version 130. +# bg-shader = "void main() { +# vec2 p = t_pos * t_aspect; +# float r = pow(sin(p.x * 100.0 + t_time * 3.0), 60.0); +# float g = pow(sin(p.y * 100.0 + t_time * 6.0), 60.0); +# vec4 color = vec4(r, g, 1.0 - t_save_time, 0.2); +# gl_FragColor = clamp(color, 0.0, 1.0); +# }" + [keyboard] # motion and selection Left = :left diff --git a/ted.h b/ted.h index 5eebced..0271d64 100644 --- a/ted.h +++ b/ted.h @@ -166,6 +166,10 @@ typedef struct { u8 padding; u8 scrolloff; u8 tags_max_depth; + u32 bg_shader; + u32 bg_buffer; + u32 bg_array; + char bg_shader_text[4096]; char build_default_command[256]; // [i] = comma-separated string of file extensions for language i, or NULL for none char *language_extensions[LANG_COUNT]; @@ -407,6 +411,8 @@ typedef struct Ted { float build_output_height; // what % of the screen the build output takes up bool resizing_build_output; + + double last_save_time; // last time a save command was executed. used for bg-shaders. Process build_process; // When we read the stdout from the build process, the tail end of the read could be an -- cgit v1.2.3