summaryrefslogtreecommitdiff
path: root/src/font.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-02-18 20:26:17 -0500
committerJonathan Bradley <jcb@pikum.xyz>2025-02-18 20:26:17 -0500
commit49c26802a6513a14187d4c2e22f74676056de099 (patch)
treeed5aaa83d38874643543a2b8730a88584691ef72 /src/font.cpp
parentfae5df7328306078421cfdda65279f7e90f7658f (diff)
pke: font rendering correct glyph transform
Diffstat (limited to 'src/font.cpp')
-rw-r--r--src/font.cpp123
1 files changed, 72 insertions, 51 deletions
diff --git a/src/font.cpp b/src/font.cpp
index 96a93a6..1f97bf1 100644
--- a/src/font.cpp
+++ b/src/font.cpp
@@ -14,6 +14,8 @@
const char *PKE_PROJECT_FONT_TITLE = "title: ";
const char *PKE_PROJECT_FONT_TEXTURE_HANDLE = "texture_handle: ";
const char *PKE_PROJECT_FONT_GLYPH_DETAILS_HANDLE = "glyph_details_handle: ";
+const char *PKE_PROJECT_FONT_MSDF_MIN_SCALE = "msdf_min_scale: ";
+const char *PKE_PROJECT_FONT_MSDF_PX_RANGE = "msdf_px_range: ";
const char *PKE_PROJECT_FONT_SPACING_GEOMETRY_SCALE = "spacing_geometry_scale: ";
const char *PKE_PROJECT_FONT_SPACING_EM_SIZE = "spacing_em_size: ";
const char *PKE_PROJECT_FONT_SPACING_ASCENDER_Y = "spacing_ascender_y: ";
@@ -91,50 +93,48 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta
FontGlyphChar *fgc;
FontInstanceBufferItem *buf_item;
uint32_t i;
- float font_glyph_spacing_inverse;
+ float font_glyph_spacing;
float cursor_head, line_index, line_height;
- float glyph_ratio, screen_ratio;
glm::vec2 glyph_size;
- glm::vec2 translate;
- glm::mat3 tr_scale_glyph = glm::mat3(1);
- glm::mat3 tr_scale_screen = glm::mat3(1);
- glm::mat3 tr_translate = glm::mat3(1);
-
- font_glyph_spacing_inverse = (ft->spacing.em_size / ft->spacing.geometry_scale);
+ glm::vec3 translate;
+ glm::vec3 scale;
+
+ // TODO 2025-02-18 - JCB
+ // 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.
+ // Could be related to uv (set to a .5 value).
+ //
+ // Fonts are not aliased correctly - may or may not be related to ghosting.
+ //
+ // Letter spacing seems off.
+ // Digits and punctuation ',' '.' are the worst offenders.
+
+ font_glyph_spacing = ft->spacing.em_size * fr->settings.char_scale;
cursor_head = 0;
line_index = 0;
- line_height = font_glyph_spacing_inverse * ft->spacing.line_height * fr->settings.char_scale;
+ line_height = font_glyph_spacing * ft->spacing.line_height * fr->settings.line_height_scale;
for (i = 0; i < fr->n_glyphs; ++i) {
-
+ translate = glm::vec3(0);
+ scale = glm::vec3(1);
fgc = &ft->glyphs[fr->glyph_indices[i]];
+ if (fgc->is_whitespace == true) {
+ cursor_head += fgc->advance * font_glyph_spacing;
+ continue;
+ }
+
// left, bottom, right, top
// x, y, z, w
- glyph_size.x = fgc->baseline_bounding_box.z - fgc->baseline_bounding_box.x;
- glyph_size.x *= font_glyph_spacing_inverse;
- glyph_size.x *= fr->settings.char_scale;
-
- glyph_size.y = fgc->baseline_bounding_box.w - fgc->baseline_bounding_box.y;
- glyph_size.y *= font_glyph_spacing_inverse;
- glyph_size.y *= fr->settings.char_scale;
-
- glyph_ratio = glyph_size.x / glyph_size.y;
-
- // this might break if the screen is vertical?
- // scale the uniform box to the glyph ratio
- if (glyph_ratio > 0) {
- tr_scale_glyph[0][0] = glyph_ratio;
- tr_scale_glyph[1][1] = 1;
- screen_ratio = glyph_size.x / (float)Extent.width;
- } else {
- tr_scale_glyph[0][0] = 1;
- tr_scale_glyph[1][1] = glyph_ratio;
- screen_ratio = glyph_size.y / (float)Extent.height;
- }
+ glyph_size.x = fgc->plane_bounds.z - fgc->plane_bounds.x;
+ glyph_size.x *= font_glyph_spacing;
+
+ glyph_size.y = fgc->plane_bounds.w - fgc->plane_bounds.y;
+ glyph_size.y *= font_glyph_spacing;
+
// shrink the correctly sized box to screen size
- tr_scale_screen[0][0] = screen_ratio;
- tr_scale_screen[1][1] = screen_ratio;
+ scale *= glm::vec3(glyph_size.x / (float)Extent.width, glyph_size.y / (float)Extent.height, 1.0);
// move to appropriate position + char placement
@@ -146,34 +146,34 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta
// draw from top left [-1,-1], so add left
// (add because "left" from mtsdf is likely negative)
// (while testing, the char '#' had a negative "left")
- translate.x += font_glyph_spacing_inverse * fgc->baseline_bounding_box.x;
+ translate.x += fgc->plane_bounds.x * font_glyph_spacing;
translate.x -= (Extent.width / 2.0);
translate.x /= (Extent.width / 2.0);
// ((val) - (width/2)) / (width/2)
// box position
translate.y = fr->settings.surface_area_pos.y;
- // current line (+1 to not draw above the box)
- translate.y += ((line_index + 1) * line_height);
- // draw from top left [-1,-1], so subtract top
- // (subtract because vulkan to go up)
- translate.y -= (ft->spacing.em_size / ft->spacing.geometry_scale) * fgc->baseline_bounding_box.w;
- translate.y -= (Extent.width / 2.0);
- translate.y /= (Extent.width / 2.0);
-
- tr_translate[2][0] = translate.x;
- tr_translate[2][1] = translate.y;
+ // baseline - current line (+1 to not draw above the box)
+ translate.y -= ((line_index + 1) * line_height);
+ // places the top-left corner 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)
+ translate.y -= (fgc->plane_bounds.w * font_glyph_spacing);
+ translate.y -= (Extent.height / 2.0);
+ translate.y /= (Extent.height / 2.0);
- cursor_head += fgc->advance * font_glyph_spacing_inverse * fr->settings.char_scale;
+ cursor_head += fgc->advance * font_glyph_spacing;
buf_item = &ptr_dst[i];
- buf_item->pos_scale = tr_translate * tr_scale_glyph * tr_scale_screen;
+ buf_item->pos_scale = glm::translate(glm::mat4(1), translate);
+ buf_item->pos_scale = glm::scale(buf_item->pos_scale, scale);
buf_item->fg_color = glm::vec4(0.4, 0.9, 0.5, 0.8);
buf_item->bg_color = glm::vec4(0.0, 0.0, 0.0, 0.0);
buf_item->sprite_region_min = fgc->sprite_region_min;
buf_item->sprite_region_max = fgc->sprite_region_max;
- // TODO check me, not sure this is correct
- buf_item->width = fr->settings.char_scale;
+ buf_item->width =
+ (ft->msdf_settings.minimum_scale / fr->settings.char_scale)
+ * ft->msdf_settings.px_range;
}
}
@@ -263,6 +263,7 @@ void FontType_Tick(double delta) {
void FontType_Serialize(std::ofstream &stream, FontType *ft) {
FontTypeSpacing sp{};
+ FontTypeMSDFSettings msdf{};
memset(&sp, 0, sizeof(sp));
NULL_CHAR_ARR(handleStr, AssetKeyLength + 2);
const Asset *txtr = AM_Get(ft->fontTextureAssetHandle);
@@ -272,6 +273,12 @@ void FontType_Serialize(std::ofstream &stream, FontType *ft) {
stream << PKE_PROJECT_FONT_TEXTURE_HANDLE << handleStr << std::endl;
snprintf(handleStr, AssetKeyLength + 1, "%s", glyphs->key);
stream << PKE_PROJECT_FONT_GLYPH_DETAILS_HANDLE << handleStr << std::endl;
+ if (ft->msdf_settings.minimum_scale != msdf.minimum_scale) {
+ stream << PKE_PROJECT_FONT_MSDF_MIN_SCALE << ft->msdf_settings.minimum_scale << std::endl;
+ }
+ if (ft->msdf_settings.px_range != msdf.px_range) {
+ stream << PKE_PROJECT_FONT_MSDF_PX_RANGE << ft->msdf_settings.px_range << std::endl;
+ }
if (ft->spacing.geometry_scale != sp.geometry_scale) {
stream << PKE_PROJECT_FONT_SPACING_GEOMETRY_SCALE << ft->spacing.geometry_scale << std::endl;
}
@@ -301,13 +308,14 @@ void FontType_Deserialize(std::ifstream &stream) {
uint64_t i;
NULL_CHAR_ARR(readLine, 128);
FontTypeSpacing sp{};
+ FontTypeMSDFSettings msdf{};
pk_cstr title;
AssetKey fontTextureKey;
AssetKey glyphDetailsKey;
memset(&sp, 0, sizeof(sp));
while (memset(readLine, 0, 128), stream.getline(readLine, 128)) {
if (strcmp("", readLine) == 0) {
- FontType_RegisterFont(title, AM_GetHandle(fontTextureKey), AM_GetHandle(glyphDetailsKey), &sp);
+ FontType_RegisterFont(title, AM_GetHandle(fontTextureKey), AM_GetHandle(glyphDetailsKey), &msdf, &sp);
return;
}
if (strstr(readLine, PKE_PROJECT_FONT_TITLE)) {
@@ -332,6 +340,18 @@ void FontType_Deserialize(std::ifstream &stream) {
}
continue;
}
+ if (strstr(readLine, PKE_PROJECT_FONT_MSDF_MIN_SCALE)) {
+ uint64_t prefixLen = strlen(PKE_PROJECT_FONT_MSDF_MIN_SCALE);
+ auto result = pk_stn_float(&msdf.minimum_scale, readLine + prefixLen);
+ assert(result == PK_STN_RES_SUCCESS);
+ continue;
+ }
+ if (strstr(readLine, PKE_PROJECT_FONT_MSDF_PX_RANGE)) {
+ uint64_t prefixLen = strlen(PKE_PROJECT_FONT_MSDF_PX_RANGE);
+ auto result = pk_stn_float(&msdf.px_range, readLine + prefixLen);
+ assert(result == PK_STN_RES_SUCCESS);
+ continue;
+ }
if (strstr(readLine, PKE_PROJECT_FONT_SPACING_GEOMETRY_SCALE)) {
uint64_t prefixLen = strlen(PKE_PROJECT_FONT_SPACING_GEOMETRY_SCALE);
auto result = pk_stn_double(&sp.geometry_scale, readLine + prefixLen);
@@ -382,7 +402,7 @@ FontType* FontType_GetFonts(FontTypeIndex &count) {
return ftd.arr_ft;
}
-FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeSpacing *spacing) {
+FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeMSDFSettings *msdf_settings, FontTypeSpacing *spacing) {
PKVK_TmpBufferDetails tmpBufferDetails{};
VkResult vkResult;
pk_arr arr_vert_mem_reqs;
@@ -396,6 +416,7 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle
constexpr VkDeviceSize startingGlyphCount = 4;
assert(fontTextureHandle != AssetHandle_MAX);
assert(glyphsHandle != AssetHandle_MAX);
+ assert(msdf_settings != nullptr);
assert(spacing != nullptr);
VkMemoryRequirements combined_vert_mem_reqs;
@@ -419,6 +440,7 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle
ft->glyphDetailsAssetHandle = glyphsHandle;
ft->renders = pk_new<FontRender>(startingGlyphCount);
ft->n_render = FontRenderIndex{startingGlyphCount};
+ ft->msdf_settings = *msdf_settings;
ft->spacing = *spacing;
const Asset *glyphs = AM_Get(glyphsHandle);
@@ -940,7 +962,6 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle
void FontType_Unload(FontTypeIndex idx) {
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx];
-
// TODO specific bucket
if (ft->renders != nullptr) {
for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) {