vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: 7d1c35b39e63aeb8dfea640aa6724de442955fba
Parent: 1be2e60791c0b00cecfaaf917ce81e5fad3011e3
Author: Randy Palamar
Date:   Tue,  2 Jul 2024 22:58:32 -0600

add post processing shader and scanline nonsense

Diffstat:
Afrag_post.glsl | 22++++++++++++++++++++++
Rfrag.glsl -> frag_render.glsl | 0
Mmain.c | 51+++++++++++++++++++++++++++++++--------------------
Mutil.h | 53+++++++++++++++++++++++++++++++++++------------------
Avert_post.glsl | 28++++++++++++++++++++++++++++
Rvert.glsl -> vert_render.glsl | 0
Mvtgl.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
7 files changed, 186 insertions(+), 77 deletions(-)

diff --git a/frag_post.glsl b/frag_post.glsl @@ -0,0 +1,22 @@ +#version 460 core + +out vec4 colour; + +in VS_OUT { + vec2 tex_coord; +} fs_in; + +uniform sampler2D u_texslot; +uniform float u_param; + +void main() +{ + vec2 tex_coord = fs_in.tex_coord; + + if (mod(tex_coord.y + u_param, 0.005) < 0.0005) { + vec4 tint = vec4(0.1, 0.1, 0.1, 1); + colour = mix(texture(u_texslot, tex_coord), tint, 0.5); + } else { + colour = texture(u_texslot, tex_coord); + } +} diff --git a/frag.glsl b/frag_render.glsl diff --git a/main.c b/main.c @@ -227,29 +227,40 @@ program_from_shader_text(s8 vertex, s8 fragment, Arena a) static void check_shaders(GLCtx *gl, Arena a) { - static char *fs_name = "frag.glsl"; - static char *vs_name = "vert.glsl"; - static os_file_stats fs_stats, vs_stats; - os_file_stats fs_test = os_get_file_stats(fs_name); - os_file_stats vs_test = os_get_file_stats(vs_name); - - if (os_filetime_changed(fs_test.timestamp, fs_stats.timestamp) || - os_filetime_changed(vs_test.timestamp, vs_stats.timestamp)) { - fprintf(stderr, "Reloading Shaders!\n"); - fs_stats = fs_test; - vs_stats = vs_test; - - s8 vs_text = os_read_file(&a, vs_name, vs_stats.filesize); - s8 fs_text = os_read_file(&a, fs_name, fs_stats.filesize); + static char *fs_name[SHADER_LAST] = {"frag_render.glsl", "frag_post.glsl"}; + static char *vs_name[SHADER_LAST] = {"vert_render.glsl", "vert_post.glsl"}; + static os_file_stats fs_stats[SHADER_LAST], vs_stats[SHADER_LAST]; + static struct { + char *name; + u32 flag; + } map[SHADER_LAST] = { + [SHADER_RENDER] = {.name = "Render", .flag = UPDATE_RENDER_UNIFORMS}, + [SHADER_POST] = {.name = "Post", .flag = UPDATE_POST_UNIFORMS}, + }; + + for (u32 i = 0; i < SHADER_LAST; i++) { + os_file_stats fs_test = os_get_file_stats(fs_name[i]); + os_file_stats vs_test = os_get_file_stats(vs_name[i]); + + if (!os_filetime_changed(fs_test.timestamp, fs_stats[i].timestamp) && + !os_filetime_changed(vs_test.timestamp, vs_stats[i].timestamp)) + continue; + + fprintf(stderr, "Reloading %s Shader!\n", map[i].name); + fs_stats[i] = fs_test; + vs_stats[i] = vs_test; + + s8 vs_text = os_read_file(&a, vs_name[i], vs_stats[i].filesize); + s8 fs_text = os_read_file(&a, fs_name[i], fs_stats[i].filesize); ASSERT(vs_text.len > 0 && fs_text.len > 0); u32 program = program_from_shader_text(vs_text, fs_text, a); - if (program) { - glDeleteProgram(gl->program); - gl->program = program; - gl->flags |= UPDATE_UNIFORMS; - fprintf(stderr, "Program Updated!\n"); - } + if (!program) + continue; + glDeleteProgram(gl->programs[i]); + gl->programs[i] = program; + gl->flags |= map[i].flag; + fprintf(stderr, "%s Program Updated!\n", map[i].name); } } diff --git a/util.h b/util.h @@ -122,21 +122,6 @@ typedef struct { Line *buf; } LineBuf; -#define GL_UNIFORMS \ - X(Pmat) \ - X(charmap) \ - X(texcolour) \ - X(texscale) \ - X(texslot) \ - X(vertoff) \ - X(vertscale) - -enum gl_flags { - NEEDS_RESIZE = 1 << 0, - DISCARD_BUFFER = 1 << 1, - UPDATE_UNIFORMS = 1 << 30, -}; - typedef struct { /* distance to shift glyph from bounding box origin */ iv2 delta; @@ -144,6 +129,34 @@ typedef struct { uv2 size; } Glyph; +#define GL_RENDER_UNIFORMS \ + X(Pmat) \ + X(charmap) \ + X(texcolour) \ + X(texscale) \ + X(texslot) \ + X(vertoff) \ + X(vertscale) + +#define GL_POST_UNIFORMS \ + X(Pmat) \ + X(param) \ + X(texslot) \ + X(vertscale) \ + X(yoff) + +enum gl_flags { + DISCARD_BUFFER = 1 << 0, + UPDATE_RENDER_UNIFORMS = 1 << 29, + UPDATE_POST_UNIFORMS = 1 << 30, +}; + +enum shader_stages { + SHADER_RENDER, + SHADER_POST, + SHADER_LAST +}; + typedef struct { GLFWwindow *window; v2 window_size; @@ -154,12 +167,16 @@ typedef struct { u32 fb, fb_tex, fb_tex_unit; - u32 program; + u32 programs[SHADER_LAST]; #define X(name) i32 name; union { - struct { GL_UNIFORMS }; + struct { GL_RENDER_UNIFORMS }; i32 uniforms[7]; - }; + } render; + union { + struct { GL_POST_UNIFORMS }; + i32 uniforms[5]; + } post; #undef X u32 flags; diff --git a/vert_post.glsl b/vert_post.glsl @@ -0,0 +1,28 @@ +#version 460 core + +in vec2 position; + +uniform mat4 u_Pmat; +uniform vec2 u_vertscale; +uniform float u_yoff; + +out VS_OUT { + vec2 tex_coord; +} vs_out; + +void main() +{ + vec2 pos = position.xy; + vec2 scale = u_vertscale; + + mat4 transform = mat4( + scale.x, 0, 0, 0, + 0, scale.y, 0, 0, + 0, 0, 1, 0, + 0, u_yoff, 0, 1 + ); + + gl_Position = u_Pmat * transform * vec4(pos, 0.0, 1.0); + + vs_out.tex_coord = pos; +} diff --git a/vert.glsl b/vert_render.glsl diff --git a/vtgl.c b/vtgl.c @@ -10,10 +10,13 @@ #define TEXTURE_GLYPH_COUNT 128 #define X(name) "u_"#name, -static char *uniform_names[] = { GL_UNIFORMS }; +static char *render_uniform_names[] = { GL_RENDER_UNIFORMS }; +static char *post_uniform_names[] = { GL_POST_UNIFORMS }; #undef X -static_assert(ARRAY_COUNT(uniform_names) == ARRAY_COUNT(((GLCtx *)0)->uniforms), - "GLCtx.uniforms must be same length as GL_UNIFORMS\n"); +static_assert(ARRAY_COUNT(render_uniform_names) == ARRAY_COUNT(((GLCtx *)0)->render.uniforms), + "GLCtx.render.uniforms must be same length as GL_RENDER_UNIFORMS\n"); +static_assert(ARRAY_COUNT(post_uniform_names) == ARRAY_COUNT(((GLCtx *)0)->post.uniforms), + "GLCtx.post.uniforms must be same length as GL_POST_UNIFORMS\n"); static v4 normalized_colour(Colour c) @@ -34,14 +37,22 @@ static void resize(GLCtx *gl) { v2 ws = gl->window_size; - f32 pmat[4 * 4] = { - 2.0 / ws.w, 0.0, 0.0, -1.0, - 0.0, 2.0 / ws.h, 0.0, -1.0, + f32 render_pmat[4 * 4] = { + 2.0/ws.w, 0.0, 0.0, -1.0, + 0.0, 2.0/ws.h, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }; - glUniformMatrix4fv(gl->Pmat, 1, GL_TRUE, pmat); - gl->flags &= ~NEEDS_RESIZE; + f32 post_pmat[4 * 4] = { + 2.0/ws.w, 0.0, 0.0, -1.0, + 0.0, 4.0/ws.h, 0.0, -1.0, + 0.0, 0.0, -1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + }; + glUseProgram(gl->programs[SHADER_RENDER]); + glUniformMatrix4fv(gl->render.Pmat, 1, GL_TRUE, render_pmat); + glUseProgram(gl->programs[SHADER_POST]); + glUniformMatrix4fv(gl->post.Pmat, 1, GL_TRUE, post_pmat); } static void @@ -66,16 +77,27 @@ update_font_textures(Term *t) } static void -update_uniforms(Term *t) +update_uniforms(Term *t, enum shader_stages stage) { - for (u32 i = 0; i < ARRAY_COUNT(t->gl.uniforms); i++) - t->gl.uniforms[i] = glGetUniformLocation(t->gl.program, uniform_names[i]); - t->gl.flags &= ~UPDATE_UNIFORMS; + ASSERT(stage != SHADER_LAST); + + switch (stage) { + case SHADER_RENDER: + for (u32 i = 0; i < ARRAY_COUNT(t->gl.render.uniforms); i++) + t->gl.render.uniforms[i] = glGetUniformLocation(t->gl.programs[stage], + render_uniform_names[i]); + t->gl.flags &= ~UPDATE_RENDER_UNIFORMS; + break; + case SHADER_POST: + for (u32 i = 0; i < ARRAY_COUNT(t->gl.post.uniforms); i++) + t->gl.post.uniforms[i] = glGetUniformLocation(t->gl.programs[stage], + post_uniform_names[i]); + t->gl.flags &= ~UPDATE_POST_UNIFORMS; + break; + case SHADER_LAST: ASSERT(0); break; + } - glUniform1i(t->gl.texslot, 0); update_font_textures(t); - - resize(&t->gl); } static i32 @@ -107,11 +129,11 @@ measure_text(GLCtx *gl, s8 text, b32 monospaced) static void push_char(GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, uv2 colours, i32 char_idx) { - glUniform2uiv(gl->texcolour, 1, colours.E); - glUniform1iv(gl->charmap, 1, &char_idx); - glUniform2fv(gl->texscale, 1, texscale.E); - glUniform2fv(gl->vertscale, 1, vertscale.E); - glUniform2fv(gl->vertoff, 1, vertoff.E); + glUniform2uiv(gl->render.texcolour, 1, colours.E); + glUniform1iv(gl->render.charmap, 1, &char_idx); + glUniform2fv(gl->render.texscale, 1, texscale.E); + glUniform2fv(gl->render.vertscale, 1, vertscale.E); + glUniform2fv(gl->render.vertoff, 1, vertoff.E); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); } @@ -176,11 +198,11 @@ push_cell(Term *t, u32 cp, Rect r, u32 bg, u32 fg) colours[2] = fg; colours[3] = bg; - glUniform2uiv(gl->texcolour, 2, colours); - glUniform1iv(gl->charmap, 2, charmap); - glUniform2fv(gl->texscale, 2, (f32 *)texscale); - glUniform2fv(gl->vertscale, 2, (f32 *)vertscale); - glUniform2fv(gl->vertoff, 2, (f32 *)vertoff); + glUniform2uiv(gl->render.texcolour, 2, colours); + glUniform1iv(gl->render.charmap, 2, charmap); + glUniform2fv(gl->render.texscale, 2, (f32 *)texscale); + glUniform2fv(gl->render.vertscale, 2, (f32 *)vertscale); + glUniform2fv(gl->render.vertoff, 2, (f32 *)vertoff); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 2); } @@ -267,7 +289,6 @@ fb_callback(GLFWwindow *win, i32 w, i32 h) Term *t = glfwGetWindowUserPointer(win); t->gl.window_size.w = w; t->gl.window_size.h = FB_HEIGHT_SCALE * h; - t->gl.flags |= NEEDS_RESIZE; v2 cs = get_cell_size(t); t->size.w = (u32)(w / cs.w); @@ -281,6 +302,8 @@ fb_callback(GLFWwindow *win, i32 w, i32 h) glBindTexture(GL_TEXTURE_2D, t->gl.fb_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t->gl.window_size.w, t->gl.window_size.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + resize(&t->gl); } static void @@ -328,11 +351,10 @@ init_callbacks(GLCtx *gl) DEBUG_EXPORT void do_terminal(Term *t, Arena a) { - if (t->gl.flags & UPDATE_UNIFORMS) - update_uniforms(t); - - if (t->gl.flags & NEEDS_RESIZE) - resize(&t->gl); + if (t->gl.flags & UPDATE_RENDER_UNIFORMS) + update_uniforms(t, SHADER_RENDER); + if (t->gl.flags & UPDATE_POST_UNIFORMS) + update_uniforms(t, SHADER_POST); if (os_child_data_available(t->child)) { if (os_child_exited(t->child)) @@ -350,6 +372,8 @@ do_terminal(Term *t, Arena a) v2 ws = t->gl.window_size; /* NOTE: reset the camera/viewport */ + glUseProgram(t->gl.programs[SHADER_RENDER]); + glUniform1i(t->gl.render.texslot, 0); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); clear_colour(); glViewport(0, 0, ws.w, ws.h); @@ -393,12 +417,19 @@ do_terminal(Term *t, Arena a) draw_text(&t->gl, fps, pos, (Colour){.rgba = 0x1e9e33ff}, 1); } - glBindFramebuffer(GL_READ_FRAMEBUFFER, t->gl.fb); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(src_bl.x, src_bl.y, src_tr.x, src_tr.y, - 0, 0, ws.w, ws.h / FB_HEIGHT_SCALE, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - - //glActiveTexture(GL_TEXTURE0 + t->gl.fb_tex_unit); - //glBindTexture(GL_TEXTURE_2D, t->gl.fb_tex); + static f32 param = 0; + static f32 p_scale = 1; + param += p_scale * 0.005 * t->gl.dt; + if (param > 1.0f || param < 0) + p_scale *= -1.0f; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, ws.w, ws.h/FB_HEIGHT_SCALE); + glUseProgram(t->gl.programs[SHADER_POST]); + glUniform1i(t->gl.post.texslot, t->gl.fb_tex_unit); + f32 yoff = -MIN(cursor_pos.y, ws.h/FB_HEIGHT_SCALE); + glUniform1f(t->gl.post.yoff, yoff); + glUniform1f(t->gl.post.param, param); + glUniform2fv(t->gl.post.vertscale, 1, (f32 []){ws.w, ws.h}); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); }