vtgl

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

Commit: 841511e052f412d9738758c36f15d59b4973e431
Parent: 00951ccc0c8bc64084152eec08e0d52cdeed9197
Author: Randy Palamar
Date:   Wed, 23 Oct 2024 06:29:37 -0600

re-add arbitrary text drawing

now everything goes through the font cache and callers can request
a specific font_id to try and match on. There could be a couple
issues with this but I plan on rasterizing glyphs directly on the
GPU soon so I will probably not worry about fixing them for now.

Also the font code now works fine with proportional fonts as well
(besides kerning which will be handled later).

Diffstat:
Mconfig.def.h | 16+++++++++++++---
Mdebug.c | 85+------------------------------------------------------------------------------
Mfont.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mterminal.c | 4+++-
Mtest.c | 10++++++----
Mutil.h | 18+++++++++---------
Mvtgl.c | 153+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
7 files changed, 169 insertions(+), 181 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -6,11 +6,21 @@ static FontDesc g_fonts[][FS_LAST] = { [FS_ITALIC] = {.path = "/usr/share/fonts/gofont/Go-Mono-Italic.ttf", .height = 24}, [FS_BOLD_ITALIC] = {.path = "/usr/share/fonts/gofont/Go-Mono-Bold-Italic.ttf", .height = 24}, }, + { + [FS_NORMAL] = {.path = "/usr/share/fonts/dejavu/DejaVuSans.ttf", .height = 28}, + }, + { + [FS_NORMAL] = {.path = "/usr/share/fonts/dejavu/DejaVuSans.ttf", .height = 22}, + }, + { + [FS_NORMAL] = {.path = "/usr/share/fonts/liberation-fonts/LiberationMono-Regular.ttf", .height = 16}, + }, }; -#ifdef _DEBUG -static FontDesc g_debug_font_desc = {.path = "/usr/share/fonts/gofont/Go-Mono-Bold.ttf", .height = 18}; -#endif +/* NOTE: indices into the array above */ +static u32 g_ui_small_font_id = 2; +static u32 g_ui_large_font_id = 3; +static u32 g_ui_debug_font_id = 4; /* NOTE: terminal margin in pixels */ static v2 g_term_margin = {.w = 8, .h = 8}; diff --git a/debug.c b/debug.c @@ -138,91 +138,8 @@ dump_glyph_cache_to_file(FontAtlas *fa) fclose(f); } -#define MAX_DEBUG_FONT_SIZE 32.0 static void debug_init(Term *t, Arena a) { - Font *f = &t->debug_font; - init_font(f, &g_debug_font_desc); - - glGenTextures(1, &t->debug_glyph_texture); - glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(GL_TEXTURE_2D_ARRAY, t->debug_glyph_texture); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, MAX_DEBUG_FONT_SIZE, MAX_DEBUG_FONT_SIZE, - ARRAY_COUNT(t->debug_glyphs), 0, GL_RED, GL_UNSIGNED_BYTE, 0); - - /* NOTE: calculate glyph sizes and upload rendered glyph to GPU */ - f32 scale = f->stbtt_scale; - for (u32 i = ' '; i < 0x7F; i++) { - Arena tmp = a; - i32 x0, y0, x1, y1; - i32 glyph_idx = stbtt_FindGlyphIndex(&f->font_info, i); - stbtt_GetGlyphBitmapBoxSubpixel(&f->font_info, glyph_idx, scale, scale, 0, 0, - &x0, &y0, &x1, &y1); - Glyph *g = t->debug_glyphs + i - ' '; - g->size.w = x1 - x0; - g->size.h = y1 - y0; - g->delta.x = x0; - g->delta.y = -y1; - - u8 *render_buf = alloc(&tmp, u8, g->size.w * g->size.h); - stbtt_MakeGlyphBitmapSubpixel(tmp, &f->font_info, render_buf, g->size.w, g->size.h, - 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++) { - 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); - } - - glActiveTexture(GL_TEXTURE0); - - i32 x0, x1, y0, y1; - stbtt_GetFontBoundingBox(&t->debug_font.font_info, &x0, &y0, &x1, &y1); - t->debug_glyphs[0].size.w = scale * (x1 - x0) + 0.5; -} - -static void draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour); -static void push_char(RenderPushBuffer *rpb, GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, - uv2 colours, i32 char_idx); - -static v2 -debug_measure_text(Term *t, Font *f, s8 text, b32 monospaced) -{ - v2 result = {0}; - f32 single_space_width = t->debug_glyphs[0].size.w; - for (size i = 0; i < text.len; i++) { - Glyph g = t->debug_glyphs[text.data[i] - ' ']; - /* TODO: should we consider offset characters in y? */ - if (g.size.h > result.y) - result.y = g.size.h; - result.x += monospaced? single_space_width : g.size.w; - } - return result; -} - -static void -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++) { - i32 glyph_idx = text.data[i] - ' '; - Glyph g = t->debug_glyphs[glyph_idx]; - 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 = fg.rgba & 0xFFFFFF00, .y = bg.rgba & 0xFFFFFF00}, glyph_idx); - position.x += monospaced? single_space_width : g.size.w; - } + /* NOTE: this used to be useful but for now its not */ } diff --git a/font.c b/font.c @@ -31,6 +31,22 @@ unpack_gpu_tile_coord(u32 gpu_index) } static void +cached_glyph_to_uv(FontAtlas *fa, CachedGlyph *cg, v2 *start, v2 *end, v2 scale) +{ + v2 cs = {.w = fa->info.w, .h = fa->info.h}; + uv2 tile_coord = unpack_gpu_tile_coord(cg->gpu_tile_index); + + f32 min_x = tile_coord.x * cs.w + cg->x0; + f32 max_x = min_x + cg->width; + f32 min_y = tile_coord.y * cs.h + fa->info.h + cg->y0 - fa->info.baseline; + f32 max_y = min_y + cg->height; + + *start = (v2){.x = min_x * scale.x, .y = max_y * scale.y}; + *end = (v2){.x = max_x * scale.x, .y = min_y * scale.y}; +} + + +static void recycle_cache(GlyphCache *gc) { CachedGlyph *sentinel = gc->glyphs + 0; @@ -135,15 +151,17 @@ get_and_clear_glyph_cache_stats(GlyphCache *gc) } static u32 * -render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph **out_glyph) +render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style, CachedGlyph **out_glyph) { BEGIN_TIMED_BLOCK(); GlyphCache *gc = &fa->glyph_cache; u32 *rgba_bitmap = NULL; /* NOTE: first check if glyph is in the cache and valid */ - /* NOTE: 8 MSB are not used for UTF8 so we can use that to store the style of the glyph */ - u32 packed_cp = cp | ((u32)(style) << 24); + /* NOTE: 8 MSB are not used for UTF8 so we can use that to store some extra info: + * bits 25,26: the style of the glyph + * bits 26-31: requested font_id (limited to first 32 fonts */ + u32 packed_cp = cp | ((u32)style << 24) | (font_id << 26); u32 idx = get_glyph_entry_index(&fa->glyph_cache, packed_cp); CachedGlyph *cg = fa->glyph_cache.glyphs + idx; @@ -155,27 +173,45 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph i32 glyph_idx = 0; i32 font_idx = 0; - for (u32 i = 0; i < fa->nfonts; i++) { - u32 test_style = style; - if (!fa->fonts[i][test_style].buf) - test_style = FS_NORMAL; - glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][test_style].font_info, cp); - if (!glyph_idx) - glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][FS_NORMAL].font_info, cp); - if (glyph_idx) { - font_idx = i; - break; + + /* NOTE: first try the requested font id */ + if (font_id < fa->nfonts && fa->fonts[font_id][style].buf) { + glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[font_id][style].font_info, cp); + if (glyph_idx) + font_idx = font_id; + } + + if (!glyph_idx) { + for (u32 i = 0; i < fa->nfonts; i++) { + u32 test_style = style; + if (!fa->fonts[i][test_style].buf) + test_style = FS_NORMAL; + glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][test_style].font_info, cp); + if (!glyph_idx) + glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][FS_NORMAL].font_info, cp); + if (glyph_idx) { + font_idx = i; + break; + } } } Font *f = &fa->fonts[font_idx][style]; f32 scale = f->stbtt_scale; - i32 x0, y0, x1, y1; + i32 x0, y0, x1, y1, advance, left_bearing; stbtt_GetGlyphBitmapBoxSubpixel(&f->font_info, glyph_idx, scale, scale, 0, 0, &x0, &y0, &x1, &y1); i32 height = y1 - y0; i32 width = x1 - x0; + + stbtt_GetGlyphHMetrics(&f->font_info, glyph_idx, &advance, &left_bearing); + cg->advance = scale * advance; + cg->height = height; + cg->width = width; + cg->x0 = x0; + cg->y0 = y0; + u8 *render_buf = alloc(a, u8, width * height); stbtt_MakeGlyphBitmapSubpixel(*a, &f->font_info, render_buf, width, height, width, scale, scale, 0, 0, glyph_idx); diff --git a/terminal.c b/terminal.c @@ -1229,7 +1229,9 @@ push_line(Term *t, Line *line, Arena a) if (line->has_unicode) { /* TODO: this is obviously complete crap but wcwidth from libc doesn't * actually work so we must check from the rendered glyph */ - get_gpu_glyph_index(t->arena_for_frame, &t->gl, &t->fa, cp, FS_NORMAL, &width); + CachedGlyph *cg; + get_gpu_glyph_index(t->arena_for_frame, &t->gl, &t->fa, cp, 0, 0, &cg); + width = cg->tile_count; } else { width = 1; } diff --git a/test.c b/test.c @@ -15,7 +15,7 @@ void glfwSetWindowTitle(GLFWwindow *w, const char *s) {} const char *glfwGetWindowTitle(GLFWwindow *w) { return "test"; } -static void get_gpu_glyph_index(Arena, void *, void *, u32, u32, u32 *); +static void get_gpu_glyph_index(Arena, void *, void *, u32, u32, u32, CachedGlyph **); static GlyphCacheStats get_and_clear_glyph_cache_stats(void *p) { return (GlyphCacheStats){0}; } static void init_font(void *a, void *b) {} static void push_char(RenderPushBuffer *r, GLCtx *g, v2 vs, v2 vo, v2 ts, uv2 co, i32 ci) {} @@ -29,11 +29,13 @@ KEYBIND_FN(zoom) { return 0; } #include "debug.c" static void -get_gpu_glyph_index(Arena a, void *b, void *c, u32 cp, u32 d, u32 *width) +get_gpu_glyph_index(Arena a, void *b, void *c, u32 cp, u32 d, u32 e, CachedGlyph **cg) { /* TODO: this is wrong but will have to do for these tests */ - *width = wcwidth(cp); - ASSERT(*width != -1); + static CachedGlyph scg; + scg.tile_count = wcwidth(cp); + *cg = &scg; + ASSERT((char)scg.tile_count != -1); } #define ESC(a) s8("\x1B"#a) diff --git a/util.h b/util.h @@ -336,10 +336,16 @@ typedef struct { typedef struct { u32 cp; u32 next_with_same_hash; + u32 prev; + u32 next; u32 gpu_tile_index; - u16 prev, next; - u16 uploaded_to_gpu; - u16 tile_count; + u8 tile_count; + u8 uploaded_to_gpu; + u16 advance; + i16 height; + i16 width; + i16 x0; + i16 y0; } CachedGlyph; typedef union { @@ -447,12 +453,6 @@ typedef struct { u32 tabs[32]; char saved_title[1024]; - - #ifdef _DEBUG - Font debug_font; - Glyph debug_glyphs[0x7F - 0x20]; - u32 debug_glyph_texture; - #endif } Term; static f32 dt_for_frame; diff --git a/vtgl.c b/vtgl.c @@ -8,7 +8,7 @@ #include "font.c" /* TODO this should be removed */ -static u32 get_gpu_glyph_index(Arena, GLCtx *, FontAtlas *, u32, enum face_style, u32 *); +static u32 get_gpu_glyph_index(Arena, GLCtx *, FontAtlas *, u32, u32, enum face_style, CachedGlyph **); #include "terminal.c" @@ -20,7 +20,7 @@ static void draw_debug_overlay(Term *, RenderPushBuffer *); #define REVERSE_VIDEO_MASK (Colour){.r = 0xff, .g = 0xff, .b = 0xff}.rgba static v4 -normalized_colour(Colour c) +normalize_colour(Colour c) { return (v4){.r = c.r / 255.0f, .g = c.g / 255.0f, .b = c.b / 255.0f, .a = c.a / 255.0f}; } @@ -30,7 +30,7 @@ clear_colour(b32 reverse) { Colour c = g_colours.data[g_colours.bgidx]; if (reverse) c.rgba ^= REVERSE_VIDEO_MASK; - v4 cc = normalized_colour(c); + v4 cc = normalize_colour(c); glClearColor(cc.r, cc.g, cc.b, cc.a); glClear(GL_COLOR_BUFFER_BIT); } @@ -140,23 +140,24 @@ update_uniforms(Term *t, enum shader_stages stage) } static iv2 -get_gpu_texture_position(v2 cs, uv2 gpu_position) +get_gpu_texture_position(v2 cs, u32 gpu_tile_index) { + uv2 gpu_position = {.x = gpu_tile_index & 0xFFFF, .y = gpu_tile_index >> 16}; iv2 result = {.y = gpu_position.y * cs.y, .x = gpu_position.x * cs.x}; return result; } static u32 -get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_style style, u32 *tiles) +get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, u32 font_id, + enum face_style style, CachedGlyph **out) { - CachedGlyph *cg; - u32 *data = render_glyph(&a, fa, codepoint, style, &cg); + u32 *data = render_glyph(&a, fa, codepoint, font_id, style, out); if (data) { + CachedGlyph *cg = *out; cg->uploaded_to_gpu = 1; - uv2 gpu_position = unpack_gpu_tile_coord(cg->gpu_tile_index); v2 cell_size = get_cell_size(fa); - iv2 glyph_position = get_gpu_texture_position(cell_size, gpu_position); + iv2 glyph_position = get_gpu_texture_position(cell_size, cg->gpu_tile_index); ASSERT(glyph_position.x + cell_size.w * cg->tile_count < gl->glyph_bitmap_dim.x); ASSERT(glyph_position.y + cell_size.h < gl->glyph_bitmap_dim.y); @@ -164,9 +165,8 @@ get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_ cell_size.w * cg->tile_count, cell_size.h, GL_RGBA, GL_UNSIGNED_BYTE, data); } - ASSERT(cg->uploaded_to_gpu); - *tiles = cg->tile_count; - return cg->gpu_tile_index; + ASSERT((*out)->uploaded_to_gpu); + return (*out)->gpu_tile_index; } /* NOTE: this function assumes we are drawing quads */ @@ -220,7 +220,6 @@ push_rect_full(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, v2 min_tex_c rpb->colours[idx + 1] = colour; rpb->colours[idx + 2] = colour; rpb->colours[idx + 3] = colour; - } static void @@ -245,40 +244,59 @@ push_rect(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour) push_rect_full(rpb, gl, r, colour, (v2){0}, (v2){.x = max_x, .y = max_y}); } -#if 0 - -static void -push_char(RenderPushBuffer *rpb, GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, - uv2 colours, i32 char_idx) +static v2 +push_s8(RenderPushBuffer *rpb, Arena a, GLCtx *gl, FontAtlas *fa, v2 pos, v4 colour, u32 font_id, s8 s) { - u32 idx = get_render_push_buffer_idx(rpb, gl, 1); - rpb->vertscales[idx] = vertscale; - rpb->vertoffsets[idx] = vertoff; - rpb->texscales[idx] = texscale; - rpb->texcolours[idx] = colours; - rpb->charmap[idx] = char_idx; -} + CachedGlyph *cg; + v2 start, end, text_size = {0}; + v2 scale = {.x = 1.0f / gl->glyph_bitmap_dim.x, .y = 1.0f / gl->glyph_bitmap_dim.y}; -static void -push_empty_cell_rect(RenderPushBuffer *rpb, Term *t, u32 minrow, u32 maxrow, u32 mincol, u32 maxcol) -{ - ASSERT(minrow <= maxrow && mincol <= maxcol); - ASSERT(maxrow <= t->size.h && maxcol <= t->size.w); + while (s.len) { + u32 cp = get_utf8(&s); + if (cp == (u32)-1) + break; + + get_gpu_glyph_index(a, gl, fa, cp, font_id, FS_NORMAL, &cg); + cached_glyph_to_uv(fa, cg, &start, &end, scale); + + Rect r = {.pos = pos, .size = {.x = cg->width, .y = cg->height}}; + r.pos.x += cg->x0; + r.pos.y -= (cg->height + cg->y0); - v2 cs = get_cell_size(&t->fa); - v2 size = {.x = (maxcol - mincol + 1) * cs.w, .y = (maxrow - minrow + 1) * cs.h}; - v2 pos = {.x = mincol * cs.w, .y = t->gl.window_size.h - cs.h * (maxrow + 1)}; + push_rect_full(rpb, gl, r, colour, start, end); - Colour colour = g_colours.data[g_colours.fgidx]; - push_char(rpb, &t->gl, size, pos, (v2){0}, (uv2){.y = colour.rgba}, 0); + text_size.x += cg->advance; + pos.x += cg->advance; + if (cg->height > text_size.y) + text_size.y = cg->height; + } + text_size.x -= cg->advance; + text_size.w += cg->width; + + return text_size; } -static void -draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour) +static v2 +measure_text(Arena a, GLCtx *gl, FontAtlas *fa, u32 font_id, s8 text) { - push_char(rpb, gl, r.size, r.pos, (v2){0}, (uv2){.y = colour.rgba}, 0); + v2 result = {0}; + + CachedGlyph *cg; + u32 cp = 0; + while (text.len) { + cp = get_utf8(&text); + if (cp == (u32)-1) + break; + get_gpu_glyph_index(a, gl, fa, cp, font_id, FS_NORMAL, &cg); + if (cg->height > result.y) + result.y = cg->height; + result.x += cg->advance; + } + result.x -= cg->advance; + result.x += cg->width; + + return result; } -#endif /* TODO: this is outdated */ /* NOTE: In this program we render to an offscreen render target that is later drawn @@ -298,9 +316,9 @@ render_framebuffer(Term *t, RenderCell *render_buf) Cell *c = &tv->fb.rows[row][col]; RenderCell *rc = render_buf + (row * t->size.w + col); - u32 tiles; + CachedGlyph *cg; rc->gpu_glyph = get_gpu_glyph_index(t->arena_for_frame, &t->gl, &t->fa, - c->cp, c->style.attr & FS_MASK, &tiles); + c->cp, 0, c->style.attr & FS_MASK, &cg); u32 attr = (c->style.attr & ATTR_SHADER_MASK) >> 2; u32 rmask = (t->gl.mode & WIN_MODE_REVERSE)? REVERSE_VIDEO_MASK : 0; @@ -308,6 +326,7 @@ render_framebuffer(Term *t, RenderCell *render_buf) rc->bg = ((c->style.bg.rgba & 0xFFFFFF00) | attr) ^ rmask; /* TODO: there is probably a better way to do this */ + u32 tiles = cg->tile_count; if (tiles > 1) { for (u32 i = 1; i < tiles; i++) { rc[i].gpu_glyph = rc->gpu_glyph + i; @@ -776,6 +795,8 @@ init_callbacks(GLCtx *gl) DEBUG_EXPORT void do_terminal(Term *t, f32 dt) { + BEGIN_TIMED_BLOCK(); + dt_for_frame = dt; if (t->gl.flags & UPDATE_POST_UNIFORMS) @@ -869,20 +890,20 @@ do_terminal(Term *t, f32 dt) push_rect_textured(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 1); flush_render_push_buffer(rpb, &t->gl); - #if 0 + /* TODO: update debug info at the start of the frame so that this function can + * be properly included */ + END_TIMED_BLOCK(); + /* NOTE: this happens at the end so that ui stuff doesn't go through the post * processing/effects shader */ glUseProgram(t->gl.programs[SHADER_RECTS]); - push_rect(rpb, &t->gl, (Rect){.size = {.w = 300, .h = 200}}, (v4){.r = 0.5, .a = 1}); - push_rect(rpb, &t->gl, (Rect){.pos = {.x = 300, .y = 200}, .size = {.w = 300, .h = 200}}, (v4){.g = 0.5, .a = 1}); + draw_debug_overlay(t, rpb); flush_render_push_buffer(rpb, &t->gl); - #endif } #ifdef _DEBUG DebugRecord debug_records[__COUNTER__]; -#if 0 static void draw_debug_overlay(Term *t, RenderPushBuffer *rpb) { @@ -902,33 +923,34 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) if (!(t->gl.flags & DRAW_DEBUG_OVERLAY)) return; - glUniform1i(t->gl.render.texslot, 1); - v2 ws = t->gl.window_size; s8 buf = s8alloc(&t->arena_for_frame, 1024); static GlyphCacheStats glyph_stats; static Rect r; static f32 max_text_width; + static f32 line_height; r.pos.x = ws.w - (max_text_width + 20); r.size.x = max_text_width + 20; - Colour fg = {.rgba = 0x1e9e33ff}; - Colour bg = {.rgba = 0x090909ff}; + v4 fg = normalize_colour((Colour){.rgba = 0x1e9e33ff}); + v4 bg = normalize_colour((Colour){.rgba = 0x090909bf}); - draw_rectangle(rpb, &t->gl, r, bg); + push_rect(rpb, &t->gl, r, bg); + u32 font_id = g_ui_debug_font_id; f32 line_pad = 5; - v2 txt_pos = {.x = (u32)(r.pos.x + 5), .y = ws.h}; + v2 txt_pos = {.x = r.pos.x, .y = ws.h - 20}; { s8 txt = buf; 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, fg, bg, 1); + v2 ts = measure_text(t->arena_for_frame, &t->gl, &t->fa, font_id, txt); + txt_pos.y = (u32)(txt_pos.y - ts.h - line_pad); + push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); if (ts.w > max_text_width) max_text_width = ts.w; + if (ts.h > line_height) line_height = ts.h; } for (u32 i = 0; i < ARRAY_COUNT(debug_records); i++) { @@ -941,21 +963,20 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) txt.len = snprintf((char *)txt.data, buf.len, "%29s: %5u %4s %11.02f cycs/hit", dr->function_name, hits[i], hits[i] > 1? "hits" : "hit", (f32)cycs[i]/(f32)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, fg, bg, 1); + txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); + v2 ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); if (ts.w > max_text_width) max_text_width = ts.w; + if (ts.h > line_height) line_height = ts.h; } GlyphCacheStats new_glyph_stats = get_and_clear_glyph_cache_stats(&t->fa.glyph_cache); if (new_glyph_stats.hit_count != 0) glyph_stats = new_glyph_stats; { - 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, fg, bg, 1); + s8 header = s8("Glyph Cache Stats:"); + txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); + v2 ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, header); /* TODO: This doesn't really work when we are redrawing on every frame */ static char *fmts[ARRAY_COUNT(glyph_stats.E)] = { @@ -966,10 +987,11 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) for (u32 i = 0; i < ARRAY_COUNT(glyph_stats.E); i++) { s8 txt = buf; 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, fg, bg, 1); + txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); + ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); + if (ts.w > max_text_width) max_text_width = ts.w; + if (ts.h > line_height) line_height = ts.h; } } @@ -977,4 +999,3 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) r.size.h = ws.h - r.pos.y; } #endif -#endif