diff options
| -rw-r--r-- | editor/editor.cpp | 15 | ||||
| -rw-r--r-- | src/font.cpp | 123 | ||||
| -rw-r--r-- | src/font.hpp | 8 | ||||
| -rw-r--r-- | src/game.cpp | 7 |
4 files changed, 85 insertions, 68 deletions
diff --git a/editor/editor.cpp b/editor/editor.cpp index 860e470..8f90c9d 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -795,23 +795,18 @@ void GenerateMTSDF(FontTypeMSDFSettings *msdf_settings, const Asset *a) { arr_glyphs.stride = sizeof(FontGlyphChar); pk_arr_resize(&arr_glyphs, glyphs.size()); FontGlyphChar *arr = reinterpret_cast<FontGlyphChar *>(arr_glyphs.data); - uint32_t u; for (uint64_t i = 0; i < glyphs.size(); ++i) { arr[i].advance = glyphs[i].getAdvance(); arr[i].unicode = glyphs[i].getCodepoint(); arr[i].is_whitespace = glyphs[i].isWhitespace(); - u = arr[i].unicode; - (void)u; - - // TODO double-check this math glyphs[i].getQuadPlaneBounds(dbounds.x, dbounds.y, dbounds.z, dbounds.a); - arr[i].baseline_bounding_box = dbounds; + arr[i].plane_bounds = dbounds; // library counts up from the bottom of the image to the bottom of the glyph - ibounds.y = height - (ibounds.y + ibounds.a); - arr[i].sprite_region_min = glm::vec2(ibounds.x, ibounds.y); - arr[i].sprite_region_max = glm::vec2(ibounds.x, ibounds.y) + glm::vec2(ibounds.z, ibounds.a); + glyphs[i].getQuadAtlasBounds(dbounds.x, dbounds.y, dbounds.z, dbounds.a); + arr[i].sprite_region_min = glm::vec2(dbounds.x, height - dbounds.a); + arr[i].sprite_region_max = glm::vec2(dbounds.z, height - dbounds.y); } qsort(arr_glyphs.data, arr_glyphs.next, arr_glyphs.stride, SortFontGlyphChar); @@ -835,7 +830,7 @@ void GenerateMTSDF(FontTypeMSDFSettings *msdf_settings, const Asset *a) { font_title.val = pk_new<char>(font_title.reserved); snprintf((char *)font_title.val, AssetKeyLength, "%s", a->key); assert(ah_image != ah_glyphs && ah_image != AssetHandle_MAX); - FontType_RegisterFont(font_title, ah_image, ah_glyphs, &ft_spacing); + FontType_RegisterFont(font_title, ah_image, ah_glyphs, msdf_settings, &ft_spacing); } bool RecordImGui_GenerateMTSDFModal() { 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) { diff --git a/src/font.hpp b/src/font.hpp index 5fd0f61..73ffd1d 100644 --- a/src/font.hpp +++ b/src/font.hpp @@ -24,12 +24,12 @@ struct FontGlyphChar { double advance; glm::vec2 sprite_region_min; glm::vec2 sprite_region_max; - glm::dvec4 baseline_bounding_box; + glm::dvec4 plane_bounds; uint32_t unicode; - bool is_whitespace; // TODO + bool is_whitespace; }; struct FontRenderSettings { - float char_scale; // TODO + float char_scale; float line_height_scale; float char_spacing_scale; glm::ivec2 surface_area_size; // TODO @@ -97,7 +97,7 @@ void FontType_Tick(double delta); void FontType_Serialize(std::ofstream &stream, FontType *ft); void FontType_Deserialize(std::ifstream &stream); FontType* FontType_GetFonts(FontTypeIndex &count); -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); void FontType_Unload(FontTypeIndex idx); FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_str str, FontRenderSettings *settings); void FontType_RemoveStringRender(FontRender fr); diff --git a/src/game.cpp b/src/game.cpp index 434dc56..f3e52ce 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -609,12 +609,13 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { } } - // pk_cstr test_text = cstring_to_pk_cstr("*0123456789$"); + // pk_cstr test_text = cstring_to_pk_cstr("0123456789 The quick brown fox jumped over the lazy dog."); + pk_cstr test_text = cstring_to_pk_cstr("%+-*0123456789$"); // pk_cstr test_text = cstring_to_pk_cstr("$#"); - pk_cstr test_text = cstring_to_pk_cstr("$"); + // pk_cstr test_text = cstring_to_pk_cstr("$"); FontTypeIndex font_type_count; FontRenderSettings fr_set; - fr_set.char_scale = 1.0; + fr_set.char_scale = 64.0; fr_set.line_height_scale = 1.0; fr_set.char_spacing_scale = 1.0; fr_set.surface_area_size.x = 1; |
