diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-02-18 20:26:17 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-02-18 20:26:17 -0500 |
| commit | 49c26802a6513a14187d4c2e22f74676056de099 (patch) | |
| tree | ed5aaa83d38874643543a2b8730a88584691ef72 /src/font.cpp | |
| parent | fae5df7328306078421cfdda65279f7e90f7658f (diff) | |
pke: font rendering correct glyph transform
Diffstat (limited to 'src/font.cpp')
| -rw-r--r-- | src/font.cpp | 123 |
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) { |
