vtgl

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

Commit: 19d64a874f62f9f170c78bd45a5bf544241e10d2
Parent: 6b46e481b70f74a0f0515502262573d377c81a26
Author: Randy Palamar
Date:   Thu, 17 Oct 2024 20:56:02 -0600

start moving cell style calculations to fragment shader

ideally most calculations in push_cell get moved to the shader.

this also sets the shader up for proper colour blending with
coloured glyphs.

Diffstat:
Mdebug.c | 31+++++++++++++++++++------------
Mfont.c | 2+-
Mfrag_render.glsl | 34+++++++++++++++++++++++++++-------
Mutil.h | 1+
Mvert_render.glsl | 2+-
Mvtgl.c | 9+++------
6 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/debug.c b/debug.c @@ -174,9 +174,12 @@ debug_init(Term *t, Arena a) g->size.w, scale, scale, 0, 0, glyph_idx); u32 *rgba_bitmap = alloc(&tmp, u32, g->size.w * g->size.h); - for (u32 i = 0; i < g->size.h; i++) - for (u32 j = 0; j < g->size.w; j++) - rgba_bitmap[i * g->size.w + j] = (u32)(render_buf[i * g->size.w + j]) << 24; + for (u32 i = 0; i < g->size.h; i++) { + for (u32 j = 0; j < g->size.w; j++) { + u32 pixel = (render_buf[i * g->size.w + j] << 24) | 0x00FFFFFF; + rgba_bitmap[i * g->size.w + j] = pixel; + } + } glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i - ' ', g->size.w, g->size.h, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba_bitmap); @@ -209,7 +212,7 @@ debug_measure_text(Term *t, Font *f, s8 text, b32 monospaced) } static void -debug_draw_text(Term *t, RenderPushBuffer *rpb, s8 text, v2 position, Colour colour, b32 monospaced) +debug_draw_text(Term *t, RenderPushBuffer *rpb, s8 text, v2 position, Colour fg, Colour bg, b32 monospaced) { f32 single_space_width = t->debug_glyphs[0].size.w; for (size i = 0; i < text.len; i++) { @@ -218,7 +221,8 @@ debug_draw_text(Term *t, RenderPushBuffer *rpb, s8 text, v2 position, Colour col v2 texscale = {.x = g.size.w / MAX_DEBUG_FONT_SIZE, .y = g.size.h / MAX_DEBUG_FONT_SIZE}; v2 vertscale = {.x = g.size.w, .y = g.size.h}; v2 vertoff = {.x = position.x + g.delta.x, .y = position.y + g.delta.y}; - push_char(rpb, &t->gl, vertscale, vertoff, texscale, (uv2){.x = colour.rgba}, glyph_idx); + push_char(rpb, &t->gl, vertscale, vertoff, texscale, + (uv2){.x = fg.rgba & 0xFFFFFF00, .y = bg.rgba & 0xFFFFFF00}, glyph_idx); position.x += monospaced? single_space_width : g.size.w; } } @@ -265,7 +269,10 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) r.pos.x = ws.w - 1.1 * max_text_width; r.size.x = 1.1 * max_text_width; - draw_rectangle(rpb, &t->gl, r, (Colour){.rgba = 0x222222ff}); + Colour fg = {.rgba = 0x1e9e33ff}; + Colour bg = {.rgba = 0x222222ff}; + + draw_rectangle(rpb, &t->gl, r, bg); f32 line_pad = 5; v2 txt_pos = {.x = (u32)(r.pos.x + 5), .y = ws.h}; @@ -275,7 +282,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) txt.len = snprintf((char *)txt.data, buf.len, "Render Time: %0.02f ms/f", dt_for_frame * 1e3); v2 ts = debug_measure_text(t, &t->debug_font, txt, 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, txt, txt_pos, fg, bg, 1); if (ts.w > max_text_width) max_text_width = ts.w; } @@ -287,14 +294,14 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) txt.len = snprintf((char *)txt.data, buf.len, fmts[i].line1, cycs[i], hits[i]); v2 ts = debug_measure_text(t, &t->debug_font, txt, 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, txt, txt_pos, fg, bg, 1); if (ts.w > max_text_width) max_text_width = ts.w; txt.len = snprintf((char *)txt.data, buf.len, fmts[i].line2, (f32)cycs[i]/(f32)hits[i]); ts = debug_measure_text(t, &t->debug_font, txt, 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, txt, txt_pos, fg, bg, 1); if (ts.w > max_text_width) max_text_width = ts.w; } @@ -305,7 +312,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) cycs[CC_RENDER_FRAMEBUFFER] / (f32)(t->size.w * t->size.h)); v2 ts = debug_measure_text(t, &t->debug_font, txt, 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, txt, txt_pos, fg, bg, 1); if (ts.w > max_text_width) max_text_width = ts.w; } @@ -317,7 +324,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) v2 ts = debug_measure_text(t, &t->debug_font, s8("Glyph Cache Stats:"), 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, s8("Glyph Cache Stats:"), txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, s8("Glyph Cache Stats:"), txt_pos, fg, bg, 1); static char *fmts[ARRAY_COUNT(glyph_stats.E)] = { " Hits: %u", @@ -329,7 +336,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) txt.len = snprintf((char *)txt.data, buf.len, fmts[i], glyph_stats.E[i]); ts = debug_measure_text(t, &t->debug_font, txt, 1); txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); - debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + debug_draw_text(t, rpb, txt, txt_pos, fg, bg, 1); if (ts.w > max_text_width) max_text_width = ts.w; } } diff --git a/font.c b/font.c @@ -172,7 +172,7 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph u32 pixel = 0; if (0 /* COLOURED */) { } else { - pixel = (u32)(render_buf[i * cg->g.size.w + j]) << 24; + pixel = render_buf[i * cg->g.size.w + j] << 24 | 0x00FFFFFF; } rgba_bitmap[i * cg->g.size.w + j] = pixel; } diff --git a/frag_render.glsl b/frag_render.glsl @@ -1,4 +1,4 @@ -#version 460 core +#version 400 core out vec4 colour; @@ -12,14 +12,34 @@ uniform int u_charmap[512]; uniform vec2 u_texscale[512]; uniform uvec2 u_texcolour[512]; +#define ATTR_MASK 0xFFu +#define ATTR_FAINT (1u << 0u) +#define ATTR_UNDERLINED (1u << 1u) +#define ATTR_BLINK (1u << 2u) +#define ATTR_INVERSE (1u << 3u) +#define ATTR_INVISIBLE (1u << 4u) +#define ATTR_STRUCK (1u << 5u) + void main() { - vec4 fg = unpackUnorm4x8(u_texcolour[fs_in.index].x).wzyx; - vec4 bg = unpackUnorm4x8(u_texcolour[fs_in.index].y).wzyx; + uint attr = u_texcolour[fs_in.index].x & ATTR_MASK; + vec3 fg = unpackUnorm4x8(u_texcolour[fs_in.index].x).wzy; + vec3 bg = unpackUnorm4x8(u_texcolour[fs_in.index].y).wzy; + + vec3 tex_coord = vec3(fs_in.tex_coord, u_charmap[fs_in.index]); + tex_coord.xy *= u_texscale[fs_in.index]; + + if ((attr & ATTR_INVERSE) != 0) { + vec3 tmp = fg; + fg = bg; + bg = tmp; + } + + if ((attr & ATTR_FAINT) != 0) fg *= 0.5; - vec3 tex_coord = vec3(fs_in.tex_coord, u_charmap[fs_in.index]); - tex_coord.xy *= u_texscale[fs_in.index]; + vec4 smp = texture(u_texslot, tex_coord); + float a = u_texscale[fs_in.index].x == 0 ? 0 : smp.a; - float a = u_texscale[fs_in.index].x == 0 ? 0 : texture(u_texslot, tex_coord).a; - colour = mix(bg, fg, a); + colour.xyz = mix(bg, fg * smp.xyz, a); + colour.a = 1; } diff --git a/util.h b/util.h @@ -109,6 +109,7 @@ enum cell_attribute { ATTR_WIDE = 1 << 8, ATTR_WDUMMY = 1 << 9, /* NOTE: used to skip cells when copying */ }; +#define ATTR_SHADER_MASK (ATTR_FAINT|ATTR_UNDERLINED|ATTR_BLINK|ATTR_INVERSE|ATTR_INVISIBLE|ATTR_STRUCK) typedef struct { Colour fg, bg; diff --git a/vert_render.glsl b/vert_render.glsl @@ -1,4 +1,4 @@ -#version 460 core +#version 400 core in vec2 position; diff --git a/vtgl.c b/vtgl.c @@ -281,13 +281,10 @@ push_cell(RenderPushBuffer *rpb, GLCtx *gl, Arena a, FontAtlas *fa, Cell c, Rect rpb->charmap[idx + 1] = depth_idx; CellStyle cs = c.style; - if (cs.attr & ATTR_FAINT) { - if (cs.attr & ATTR_INVERSE) cs.bg.a = 0.5 * 255; - else cs.fg.a = 0.5 * 255; - } - u32 fg = (cs.attr & ATTR_INVERSE)? cs.bg.rgba : cs.fg.rgba; - u32 bg = (cs.attr & ATTR_INVERSE)? cs.fg.rgba : cs.bg.rgba; + u32 attr = (cs.attr & ATTR_SHADER_MASK) >> 2; + u32 fg = (cs.fg.rgba & 0xFFFFFF00) | attr; + u32 bg = (cs.bg.rgba & 0xFFFFFF00) | attr; u32 rmask = (gl->mode & WIN_MODE_REVERSE)? REVERSE_VIDEO_MASK : 0; rpb->texcolours[idx + 0].x = fg ^ rmask;