diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-09-23 09:44:19 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-09-23 09:44:31 -0400 |
| commit | b1409537eb5a3bbdbae892cf3f6a451dee5472a9 (patch) | |
| tree | a8b6f04eda5f803a5993bcc66fbe25eaea560790 | |
| parent | 2e72d3b1b2688f2f20a313885e1bf90eedc41093 (diff) | |
pke: ui box text center first-pass
| -rw-r--r-- | src/font.cpp | 78 | ||||
| -rw-r--r-- | src/font.hpp | 41 | ||||
| -rw-r--r-- | tests/pke-test-serialization.cpp | 6 |
3 files changed, 97 insertions, 28 deletions
diff --git a/src/font.cpp b/src/font.cpp index 3dba635..3204f58 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -108,6 +108,47 @@ float FontType_Inner_LookAheadWordLength(const FontType *const ft, const FontRen return ret; } +float FontType_Inner_LookAheadLineLength(const FontType *const ft, const FontRender *const fr, uint32_t index, float font_glyph_spacing) { + uint32_t i; + float ret = 0; + FontGlyphChar *fgc; + for (i = index; i < fr->n_glyphs; ++i) { + fgc = &ft->glyphs[fr->glyph_indices[i]]; + if (PK_HAS_FLAG(fgc->flags, FONT_GLYPH_CHAR_FLAGS_NEW_LINE) == true) { + break; + } + if (ret + (fgc->advance * font_glyph_spacing) > fr->settings.surface_area_size.x) { + break; + } + ret += fgc->advance * font_glyph_spacing; + } + return ret; +} + +float FontType_Inner_LookAheadLineCount(const FontType *const ft, const FontRender *const fr, const uint32_t index) { + uint32_t i, u; + float ret = 1; + FontGlyphChar *fgc; + for (i = index; i < fr->n_glyphs; ++i) { + fgc = &ft->glyphs[fr->glyph_indices[i]]; + if (PK_HAS_FLAG(fgc->flags, FONT_GLYPH_CHAR_FLAGS_NEW_LINE) == true) { + if (i+1 < fr->n_glyphs) { + if (fgc->unicode == 10) { + u = 11; + } else { + u = 10; + } + // handle \r\n + if (ft->glyphs[fr->glyph_indices[i+1]].unicode == u) { + i += 1; // burn + } + } + ret += 1; + } + } + return ret; +} + void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInstanceBufferItem *ptr_dst) { assert(ft != nullptr); assert(fr != nullptr); @@ -117,7 +158,7 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta bool new_word = true; uint32_t i; float font_glyph_spacing; - float cursor_head, line_index, line_height; + float cursor_head, line_index, line_height, line_length, line_offset; glm::vec2 glyph_size; glm::vec3 translate; glm::vec3 scale; @@ -129,12 +170,31 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta // Trying to get pixel-perfect rendering with mannequin-7. // Everything is now sized and positioned correctly. // However, there is a ghost layer around the letter. + // 2025-09-22 - JCB + // I believe this is because of how the anti-aliasing works. + // When this gets re-visited, attempt to disable anti-aliasing entirely. + // Suggestion: require min distance to be 0? + // Also note that I don't think we're doing any calculations to make sure the + // left-most pixel is exact to the Extent (screen size). font_glyph_spacing = ft->spacing.em_size * fr->settings.char_scale; cursor_head = 0; line_index = 0; + line_offset = 0; line_height = font_glyph_spacing * ft->spacing.line_height * fr->settings.line_height_scale; + line_length = FontType_Inner_LookAheadLineLength(ft, fr, 0, font_glyph_spacing); + if (PK_HAS_FLAG(fr->settings.surface_area_type_flags, FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_HORIZONTAL)) { + cursor_head = (fr->settings.surface_area_size.x - line_length) / 2.0; + } + if (PK_HAS_FLAG(fr->settings.surface_area_type_flags, FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_VERTICAL)) { + float text_height = FontType_Inner_LookAheadLineCount(ft, fr, 0) * line_height; + // TODO + // This is wrong but I'm not sure how/why. + // Mathematically it should be ` / 2.0`. + line_offset += (fr->settings.surface_area_size.y - text_height) / 4.0; + } + for (i = 0; i < fr->n_glyphs; ++i) { translate = glm::vec3(0); scale = glm::vec3(1); @@ -149,7 +209,12 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta } } line_index += 1; - cursor_head = 0; + line_length = FontType_Inner_LookAheadLineLength(ft, fr, i+1, font_glyph_spacing); + if (PK_HAS_FLAG(fr->settings.surface_area_type_flags, FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_HORIZONTAL)) { + cursor_head = (fr->settings.surface_area_size.x - line_length) / 2.0; + } else { + cursor_head = 0; + } continue; } if (PK_HAS_FLAG(fgc->flags, FONT_GLYPH_CHAR_FLAGS_WHITESPACE) == true) { @@ -172,7 +237,13 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta float word_width = FontType_Inner_LookAheadWordLength(ft, fr, i, font_glyph_spacing); if (cursor_head + word_width > fr->settings.surface_area_size.x) { line_index += 1; - cursor_head = 0; + line_length = FontType_Inner_LookAheadLineLength(ft, fr, i+1, font_glyph_spacing); + + if (PK_HAS_FLAG(fr->settings.surface_area_type_flags, FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_HORIZONTAL)) { + cursor_head = (fr->settings.surface_area_size.x - line_length) / 2.0; + } else { + cursor_head = 0; + } } new_word = false; } @@ -207,6 +278,7 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta translate.y = fr->settings.surface_area_pos.y; // baseline - current line (+1 to not draw above the box) translate.y += ((line_index + 1) * line_height); + translate.y += line_offset; // places the top line of the glyph on the baseline translate.y += (font_glyph_spacing / 2.0) + (glyph_size.y / 2.0); // move glyph to the height relative to the baseline (cursor) diff --git a/src/font.hpp b/src/font.hpp index 75035b8..fce99a0 100644 --- a/src/font.hpp +++ b/src/font.hpp @@ -16,28 +16,25 @@ TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF); TypeSafeInt_H(FONT_GLYPH_CHAR_FLAG, uint8_t, 0xFF); TypeSafeInt_H(FONT_RENDER_SURFACE_AREA_TYPE_FLAG, uint8_t, 0xFF); -constexpr FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_NONE - = FONT_GLYPH_CHAR_FLAG((0 << 0)); -constexpr FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_CONTROL - = FONT_GLYPH_CHAR_FLAG((1 << 0)); -constexpr FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_WHITESPACE - = FONT_GLYPH_CHAR_FLAG((1 << 1)); -constexpr FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_ALIGN_ADVANCE - = FONT_GLYPH_CHAR_FLAG((1 << 2)); -constexpr FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_NEW_LINE - = FONT_GLYPH_CHAR_FLAG((1 << 3)); +const FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_NONE + = FONT_GLYPH_CHAR_FLAG(0u); +const FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_CONTROL + = FONT_GLYPH_CHAR_FLAG((1u << 0)); +const FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_WHITESPACE + = FONT_GLYPH_CHAR_FLAG((1u << 1)); +const FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_ALIGN_ADVANCE + = FONT_GLYPH_CHAR_FLAG((1u << 2)); +const FONT_GLYPH_CHAR_FLAG FONT_GLYPH_CHAR_FLAGS_NEW_LINE + = FONT_GLYPH_CHAR_FLAG((1u << 3)); -constexpr FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_NONE - = FONT_RENDER_SURFACE_AREA_TYPE_FLAG(0); -constexpr FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_GROW_VERTICAL - = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1 << 0)); -constexpr FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_GROW_HORIZONTAL - = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1 << 1)); - -constexpr FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_STATIC - = FONT_RENDER_SURFACE_AREA_TYPE_FLAG(0); -constexpr FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_FLUID - = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1 << 0) | (1 << 1)); +const FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_NONE + = FONT_RENDER_SURFACE_AREA_TYPE_FLAG(0u); +const FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_VERTICAL + = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1u << 0)); +const FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_HORIZONTAL + = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1u << 1)); +const FONT_RENDER_SURFACE_AREA_TYPE_FLAG FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH + = FONT_RENDER_SURFACE_AREA_TYPE_FLAG((1u << 0) | (1u << 1)); struct FontRenderHandle { FontTypeIndex index_ft; @@ -65,7 +62,7 @@ struct FontRenderSettings { float char_spacing_scale = 1.f; glm::ivec2 surface_area_size; glm::ivec2 surface_area_pos; - FONT_RENDER_SURFACE_AREA_TYPE_FLAG surface_area_type_flags; // TODO + FONT_RENDER_SURFACE_AREA_TYPE_FLAG surface_area_type_flags; }; struct FontRender : public Entity_Base { uint32_t *glyph_indices = nullptr; diff --git a/tests/pke-test-serialization.cpp b/tests/pke-test-serialization.cpp index de483f7..0d97174 100644 --- a/tests/pke-test-serialization.cpp +++ b/tests/pke-test-serialization.cpp @@ -411,7 +411,7 @@ FontRenderUUID:01010101-0101-0101-0101-010101010101 UIBox:00000000!00000003 ChildId:00000000!00000002 UUID:02020202-0202-0202-0202-020202020202 -Flags:0x84 +Flags:0x3 PosTopLeft:0.100000;0.100000 MaxSize:0.800000;0.800000 Type:0x32 @@ -434,7 +434,7 @@ int pke_test_serialization_003() { frs.line_height_scale = 1.0; frs.surface_area_size = glm::ivec2(250, 250); frs.surface_area_pos = glm::ivec2(0, 0); - frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_FLUID; + frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH; FontRenderHandle fr_handle = FontType_AddStringRender(FontType_GetFonts(idx_unused)[0].index_ft, std::move(cstring_to_pk_cstr("asdf")), &frs, nullptr, uuid_n[1]); pke_ui_box *ui_box = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT, uuid_n[2]); @@ -541,7 +541,7 @@ int pke_test_deserialization_103() { PKE_TEST_ASSERT(fr->settings.char_spacing_scale == 1.f, err_index); PKE_TEST_ASSERT(fr->settings.surface_area_size == glm::ivec2(250,250), err_index); PKE_TEST_ASSERT(fr->settings.surface_area_pos == glm::ivec2(0,0), err_index); - PKE_TEST_ASSERT(fr->settings.surface_area_type_flags == FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_FLUID, err_index); + PKE_TEST_ASSERT(fr->settings.surface_area_type_flags == FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_CENTER_BOTH, err_index); // auto equal_4 = glm::epsilonEqual(fr->settings.color_foreground, glm::vec4(0.4, 0.9, 0.5, 0.8), epsilon_4); // PKE_TEST_ASSERT(equal_4 == bool_4, err_index); PKE_TEST_ASSERT(fr->settings.color_foreground == glm::vec4(0.4, 0.9, 0.5, 0.8), err_index); |
