vtgl

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

Commit: 4630eea3fcc6945743c7224635e0e10887a95720
Parent: 71de90634fc5e1c47ef4d26cd3411e9bf99c7fdf
Author: Randy Palamar
Date:   Fri, 18 Oct 2024 20:27:30 -0600

send ubo to fragment shader with data needed for drawing

soon the fragment shader will do all layout this info will be
needed. In the meantime this is used to apply the BLINK attribute.

Diffstat:
Mconfig.def.h | 3+++
Mfont.c | 3+--
Mfrag_render.glsl | 27++++++++++++++++++++++-----
Mmain.c | 8++++++--
Mterminal.c | 1-
Mutil.c | 7-------
Mutil.h | 28++++++++++++++++++++++++----
Mvtgl.c | 34+++++++++++++++++++++-------------
8 files changed, 77 insertions(+), 34 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -19,6 +19,9 @@ static v2 g_cell_pad = {.w = 0, .h = 0}; static u8 g_tabstop = 8; +/* NOTE: number of blinks per second */ +static f32 g_blink_speed = 1.0f; + static Colour base16_colours[16] = { [0] = { .rgba = 0x000000ff }, /* black */ [1] = { .rgba = 0xaa0000ff }, /* red */ diff --git a/font.c b/font.c @@ -210,7 +210,7 @@ font_atlas_update(FontAtlas *fa) update_font_metrics(&fa->fonts[0][FS_NORMAL], &fa->info); } -static i32 +static void shift_font_sizes(FontAtlas *fa, i32 size_delta) { for (u32 i = 0; i < fa->nfonts; i++) { @@ -224,7 +224,6 @@ shift_font_sizes(FontAtlas *fa, i32 size_delta) f->stbtt_scale = stbtt_ScaleForPixelHeight(&f->font_info, f->fontsize); } } - return 0; } static void diff --git a/frag_render.glsl b/frag_render.glsl @@ -1,4 +1,4 @@ -#version 400 core +#version 430 core out vec4 colour; @@ -7,6 +7,20 @@ in VS_OUT { flat int index; } fs_in; +layout(std140, binding = 0) uniform parameters { + uvec2 cell_size; + uvec2 term_size; + uvec2 top_left_margin; + uint margin_colour; + float blink_parameter; + + uint strike_min; + uint strike_max; + + uint underline_min; + uint underline_max; +}; + uniform sampler2DArray u_texslot; uniform int u_charmap[512]; uniform vec2 u_texscale[512]; @@ -29,17 +43,20 @@ void main() vec3 tex_coord = vec3(fs_in.tex_coord, u_charmap[fs_in.index]); tex_coord.xy *= u_texscale[fs_in.index]; + if ((attr & ATTR_FAINT) != 0) fg *= 0.5; + /* TODO: this causes a bug with reverse video */ + if ((attr & ATTR_BLINK) != 0) fg *= 0.5 * (1 + sin(blink_parameter)); + if ((attr & ATTR_INVERSE) != 0) { vec3 tmp = fg; fg = bg; bg = tmp; } - if ((attr & ATTR_FAINT) != 0) fg *= 0.5; - vec4 smp = texture(u_texslot, tex_coord); float a = u_texscale[fs_in.index].x == 0 ? 0 : smp.a; - colour.xyz = mix(bg, fg * smp.xyz, a); - colour.a = 1; + vec3 result = mix(bg, fg * smp.xyz, a); + + colour = vec4(result, 1); } diff --git a/main.c b/main.c @@ -63,7 +63,6 @@ do_debug(GLCtx *gl) load_library(libname); if (gl) { init_callbacks(gl); - gl->flags |= NEEDS_BLIT; } os_write_err_msg(s8("Reloaded Main Program\n")); } @@ -119,7 +118,7 @@ init_window(Term *t, Arena arena, iv2 requested_size) } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); @@ -191,6 +190,11 @@ init_window(Term *t, Arena arena, iv2 requested_size) glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t->gl.fb_tex, 0); + glGenBuffers(1, &t->gl.render_shader_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, t->gl.render_shader_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderParameters), 0, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); + t->gl.flags |= INIT_DEBUG; } diff --git a/terminal.c b/terminal.c @@ -1266,7 +1266,6 @@ blit_lines(Term *t, Arena a, size line_count) } t->gl.flags &= ~(NEEDS_FULL_REFILL|NEEDS_REFILL); - t->gl.flags |= NEEDS_BLIT; END_CYCLE_COUNT(CC_BLIT_LINES); } diff --git a/util.c b/util.c @@ -23,13 +23,6 @@ equal_uv2(uv2 a, uv2 b) } static b32 -equal_range(Range a, Range b) -{ - b32 result = equal_iv2(a.start, b.start) && equal_iv2(a.end, b.end); - return result; -} - -static b32 is_valid_range(Range r) { b32 result = !equal_iv2(r.end, INVALID_RANGE_END); diff --git a/util.h b/util.h @@ -15,6 +15,7 @@ #define static_assert _Static_assert #endif +#define PI 3.1415926535897932384f #define MEGABYTE (1024ULL * 1024ULL) #define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) @@ -197,9 +198,8 @@ typedef struct { enum gl_flags { NEEDS_RESIZE = 1 << 0, - NEEDS_BLIT = 1 << 1, - NEEDS_REFILL = 1 << 2, - NEEDS_FULL_REFILL = 1 << 3, + NEEDS_REFILL = 1 << 1, + NEEDS_FULL_REFILL = 1 << 2, UPDATE_RENDER_UNIFORMS = 1 << 27, UPDATE_POST_UNIFORMS = 1 << 28, @@ -222,6 +222,22 @@ enum shader_stages { }; typedef struct { + uv2 cell_size; + uv2 term_size; + + uv2 top_left_margin; + u32 margin_colour; + + f32 blink_parameter; + + u32 strike_min; + u32 strike_max; + + u32 underline_min; + u32 underline_max; +} ShaderParameters; + +typedef struct { GLFWwindow *window; v2 window_size; @@ -241,10 +257,14 @@ typedef struct { } post; #undef X + _Alignas(16) ShaderParameters shader_parameters; + u32 render_shader_ubo; + u32 render_shader_ssbo; + u32 flags; u32 mode; - u32 glyph_tex; + u32 glyph_tex; } GLCtx; /* NOTE: This must match the number in the shaders & the number glyphs in diff --git a/vtgl.c b/vtgl.c @@ -354,6 +354,8 @@ render_framebuffer(Term *t, RenderPushBuffer *rpb) if (cursor.style.attr & ATTR_WIDE) cr.size.w *= 2; cursor.style.attr ^= ATTR_INVERSE; + if ((t->mode & TM_ALTSCREEN) == 0) + cursor.style.attr |= ATTR_BLINK; push_cell(rpb, &t->gl, t->arena_for_frame, &t->fa, cursor, cr, cell_font_delta); } @@ -406,7 +408,6 @@ update_selection(Term *t) new_p.x--; } - Range old_range = sel->range; if (sel->state != SS_WORDS) { sel->range.start = sel->anchor.start; sel->range.end = new_p; @@ -429,8 +430,6 @@ update_selection(Term *t) } } sel->range = normalize_range(sel->range); - if (!equal_range(sel->range, old_range)) - t->gl.flags |= NEEDS_BLIT; } KEYBIND_FN(copy) @@ -546,7 +545,7 @@ fb_callback(GLFWwindow *win, i32 w, i32 h) /* NOTE: reactive the glyph texture unit */ glActiveTexture(GL_TEXTURE0); - t->gl.flags |= NEEDS_RESIZE|NEEDS_BLIT; + t->gl.flags |= NEEDS_RESIZE; } static void @@ -569,7 +568,6 @@ key_callback(GLFWwindow *win, i32 key, i32 sc, i32 act, i32 mods) } if (key == GLFW_KEY_F12 && act == GLFW_PRESS) { t->gl.flags ^= DRAW_DEBUG_OVERLAY; - t->gl.flags |= NEEDS_BLIT; return; } #endif @@ -802,16 +800,26 @@ do_terminal(Term *t, f32 dt) update_selection(t); + /* NOTE: this must be done every frame since we have time varying parameters */ RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); glUseProgram(t->gl.programs[SHADER_RENDER]); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); - if (t->gl.flags & NEEDS_BLIT) { - glUniform1i(t->gl.render.texslot, 0); - clear_colour(t->gl.mode & WIN_MODE_REVERSE); - render_framebuffer(t, rpb); - flush_render_push_buffer(rpb, &t->gl); - t->gl.flags &= ~NEEDS_BLIT; - } + + glUniform1i(t->gl.render.texslot, 0); + clear_colour(t->gl.mode & WIN_MODE_REVERSE); + + /* TODO: turns instead of PI nonsense */ + ShaderParameters *sp = &t->gl.shader_parameters; + sp->blink_parameter += 2 * PI * g_blink_speed * dt_for_frame; + if (sp->blink_parameter > 2 * PI) sp->blink_parameter -= 2 * PI; + + glBindBuffer(GL_UNIFORM_BUFFER, t->gl.render_shader_ubo); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(*sp), sp); + + render_framebuffer(t, rpb); + flush_render_push_buffer(rpb, &t->gl); + draw_debug_overlay(t, rpb); flush_render_push_buffer(rpb, &t->gl); @@ -829,6 +837,6 @@ do_terminal(Term *t, f32 dt) glUseProgram(t->gl.programs[SHADER_POST]); glUniform1i(t->gl.post.texslot, t->gl.fb_tex_unit); glUniform1f(t->gl.post.param, param); - glUniform2fv(t->gl.post.vertscale, 1, (f32 []){ws.w, ws.h}); + glUniform2fv(t->gl.post.vertscale, 1, ws.E); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); }