Improve text measuring & better explanation on how to use

This commit is contained in:
Charlie Malmqvist 2024-07-18 11:16:55 +02:00
parent e4649e564d
commit 05c9811f38
2 changed files with 51 additions and 17 deletions

View file

@ -47,11 +47,11 @@ int entry(int argc, char **argv) {
// ... So we have to justify that bottom_left according to text metrics
Vector2 justified = v2_sub(bottom_left, hello_metrics.functional_pos_min);
// If we wanted to center it:
// justified = v2_sub(justified, v2_divf(hello_metrics.functional_size, 2));
draw_text(font, hello_str, font_height, justified, v2(1, 1), COLOR_WHITE);
// If for example we wanted to center the text, we would do the same but then add
// the text size divided by two:
// justified = v2_add(justified, v2_divf(hello_metrics.functional_size, 2.0));
local_persist bool show_bounds = false;
if (is_key_just_pressed('E')) show_bounds = !show_bounds;

View file

@ -19,14 +19,43 @@ TODO:
typedef struct Gfx_Font Gfx_Font;
typedef struct Gfx_Text_Metrics {
// "functional" is what you would use for example for text editing for constistent
// placements.
// To draw text with it's origin at the bottom left, you need to sub this from the bottom
// left. I.e:
// Vector2 justified_pos = v2_sub(bottom_left, metrics.functional_pos_min);
// If you want to center, you have to first justify to bottom left and then add half of
// metrics.functional_size (or visual_size if you want perfect alignment and the text
// is static).
/*
FUNCTIONAL BOX:
x0: left start of text box
x1: right end of text box
y0: The baseline for the bottom line of text
y1: The baseline for the top line of text + latin_ascent
VISUAL BOX:
x0: The minimum X of any pixels
x1: The maximum X of any pixels
y0: The minimum Y of any pixels
y1: The maximum Y of any pixels
Usage:
For a single piece of static text, it might look better to use the visual box for aligning it somewhere.
I might be stupid and that might be useless tho.
Most of the time, you are probably going to want to use the functional box.
For example, to center:
Gfx_Text_Metrics m = measure_text(...);
// This is the point where the center of the text box will be
Vector2 draw_pos = v2(...);
// First justify for the bottom-left to be at the draw point
Vector2 justified = v2_sub(draw_pos, m.functional_pos_min);
// Then move text backwards by functional_size/2 to align its center to the draw point
justified = v2_sub(justified, v2_divf(m.functional_size, 2));
*/
Vector2 functional_pos_min;
Vector2 functional_pos_max;
Vector2 functional_size;
@ -157,12 +186,12 @@ void font_variation_init(Gfx_Font_Variation *variation, Gfx_Font *font, u32 font
variation->metrics.latin_descent = c_descent;
}
}
for (u32 c = 'A'; c <= 'Z'; c++) {
// This one is bottom-top as opposed to normally in stbtt where it's top-bottom
int x0, y0, x1, y1;
stbtt_GetCodepointBitmapBox(&font->stbtt_handle, (int)c, variation->scale, variation->scale, &x0, &y0, &x1, &y1);
float c_ascent = (float)(y1-y0);
float c_ascent = (float)abs(y0);
if (c_ascent > variation->metrics.latin_ascent)
variation->metrics.latin_ascent = c_ascent;
}
@ -325,7 +354,8 @@ Gfx_Font_Metrics get_font_metrics_scaled(Gfx_Font *font, u32 raster_height, Vect
typedef struct {
Gfx_Text_Metrics m;
Gfx_Font *font;
u32 raster_height;
Vector2 scale;
} Measure_Text_Walk_Glyphs_Context;
@ -333,10 +363,12 @@ bool measure_text_glyph_callback(Gfx_Glyph glyph, Gfx_Font_Atlas *atlas, float g
Measure_Text_Walk_Glyphs_Context *c = (Measure_Text_Walk_Glyphs_Context*)ud;
Gfx_Font_Metrics m = get_font_metrics_scaled(c->font, c->raster_height, c->scale);
float functional_left = glyph_x-glyph.xoffset*c->scale.x;
float functional_bottom = glyph_y-glyph.yoffset*c->scale.y;
float functional_right = functional_left + glyph.width*c->scale.x;
float functional_top = functional_bottom + glyph.height*c->scale.y;
float functional_bottom = glyph_y-glyph.yoffset*c->scale.y; // baseline
float functional_right = functional_left + (glyph.width+glyph.xoffset)*c->scale.x;
float functional_top = functional_bottom + (m.latin_ascent+glyph.yoffset)*c->scale.y;
c->m.functional_pos_min.x = min(c->m.functional_pos_min.x, functional_left);
c->m.functional_pos_min.y = min(c->m.functional_pos_min.y, functional_bottom);
@ -359,6 +391,8 @@ Gfx_Text_Metrics measure_text(Gfx_Font *font, string text, u32 raster_height, Ve
Measure_Text_Walk_Glyphs_Context c = ZERO(Measure_Text_Walk_Glyphs_Context);
c.scale = scale;
c.font = font;
c.raster_height = raster_height;
walk_glyphs((Walk_Glyphs_Spec){font, text, raster_height, scale, true, &c}, measure_text_glyph_callback);