summaryrefslogtreecommitdiff
path: root/src/font.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-02-13 17:38:13 -0500
committerJonathan Bradley <jcb@pikum.xyz>2025-02-13 17:38:13 -0500
commit5f77c5f905d2a3063230bde1176372ebd074bc99 (patch)
tree223e8e1443972a8829c5b92f0b00cc6236ebc0d6 /src/font.cpp
parent570498ee77505d44654fdbc97d094ae429323379 (diff)
pke: add FontRenderSettings + first pass advance
Diffstat (limited to 'src/font.cpp')
-rw-r--r--src/font.cpp224
1 files changed, 182 insertions, 42 deletions
diff --git a/src/font.cpp b/src/font.cpp
index 1ecb831..203eea3 100644
--- a/src/font.cpp
+++ b/src/font.cpp
@@ -32,21 +32,15 @@ struct FontTypeData {
} ftd;
struct FontInstanceBufferItem {
+ glm::mat4 pos_scale;
glm::vec4 fg_color;
glm::vec4 bg_color;
glm::vec2 sprite_region_min;
glm::vec2 sprite_region_max;
float width;
+ float padding[3];
};
-const VkDeviceSize instance_buffer_item_size = 0
- + sizeof(glm::vec4)
- + sizeof(glm::vec4)
- + sizeof(glm::vec2)
- + sizeof(glm::vec2)
- + sizeof(float)
- + 0;
-
// BucketContainer<FontType, TextRenderHandle, 2> bktFont;
uint32_t utf8_to_unicode(const char* str, uint32_t &out) {
@@ -90,23 +84,148 @@ uint32_t utf8_to_unicode(const char* str, uint32_t &out) {
return i;
}
+void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInstanceBufferItem *ptr_dst) {
+ assert(ft != nullptr);
+ assert(fr != nullptr);
+ assert(ptr_dst != nullptr);
+ FontGlyphChar *fgc;
+ FontInstanceBufferItem *buf_item;
+ uint32_t i;
+ float cursor_head, line_index, line_height;
+ float glyph_ratio, screen_ratio;
+ glm::vec2 glyph_size;
+ glm::mat3 tr_scale_glyph = glm::mat3(1);
+ glm::mat3 tr_scale_screen = glm::mat3(1);
+ glm::mat3 tr_translate = glm::mat3(1);
+
+ cursor_head = 0;
+ line_index = 0;
+ line_height = (1 / ft->spacing.geometry_scale) * ft->spacing.line_height;
+
+ for (i = 0; i < fr->n_glyphs; ++i) {
+
+ fgc = &ft->glyphs[fr->glyph_indices[i]];
+
+ glyph_size.x = fgc->baseline_bounding_box.z - fgc->baseline_bounding_box.x;
+ glyph_size.y = fgc->baseline_bounding_box.w - fgc->baseline_bounding_box.y;
+ 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;
+ }
+ // shrink the correctly sized box to screen size
+ tr_scale_screen[0][0] = screen_ratio;
+ tr_scale_screen[1][1] = screen_ratio;
+
+ // move to appropriate position + char placement
+ tr_translate[2][0] = ((fr->settings.surface_area_pos.x + cursor_head) - (Extent.width / 2.0)) / (Extent.width / 2.0);
+ tr_translate[2][1] = ((fr->settings.surface_area_pos.y + ((line_index + 1) * line_height)) - (Extent.width / 2.0)) / (Extent.width / 2.0);
+
+ cursor_head += fgc->advance * fr->settings.char_scale * (ft->spacing.em_size / ft->spacing.geometry_scale);
+
+ buf_item = &ptr_dst[i];
+ buf_item->pos_scale = tr_translate * tr_scale_glyph * tr_scale_screen;
+ 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;
+ buf_item->width = 1;
+ // buf_item->pos_scale[0][1] *= -1.0;
+ }
+}
+
void FontType_Init() {
ftd.n_ft = FontTypeIndex{5};
ftd.arr_ft = pk_new<FontType>(5);
- // memset(ftd.arr_ft, 0, sizeof(FontType) * 5);
+ for (FontTypeIndex_T i = 0; i < 5; ++i) {
+ FontType *ft = &ftd.arr_ft[i];
+ ft->glyphs = nullptr;
+ ft->renders = nullptr;
+ }
}
void FontType_Teardown() {
FontTypeIndex i;
- FontType *ft;
for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) {
FontType_Unload(i);
- ft = &ftd.arr_ft[(FontTypeIndex_T)i];
- if (ft->renders != nullptr) pk_delete<FontRender>(ft->renders, (FontTypeIndex_T)ft->n_render);
}
if (ftd.arr_ft != nullptr) pk_delete(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft);
}
+void FontType_Tick(double delta) {
+ (void)delta;
+ VkResult vkResult;
+ FontInstanceBufferItem *fibis = nullptr;
+ size_t index;
+ FontRender *fr;
+ for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.h_ft; ++i) {
+ index = 0;
+ FontType *ft = &ftd.arr_ft[i];
+ if (ft->last_graphics_resize_index == pkeRuntime.graphics.resize_index)
+ continue;
+ if (ft->bindings.instanceCounter == 0)
+ continue;
+ ft->last_graphics_resize_index = pkeRuntime.graphics.resize_index;
+
+ // TODO specific bucket
+ fibis = pk_new<FontInstanceBufferItem>(ft->bindings.instanceCounter);
+ for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->n_render; ++k) {
+ fr = &ft->renders[k];
+ FontType_Inner_CalcTransforms(ft, fr, &fibis[index]);
+ index += fr->n_glyphs;
+ }
+
+ PKVK_TmpBufferDetails tmpBufferDetails{};
+ PKVK_BeginBuffer(graphicsFamilyIndex, sizeof(FontInstanceBufferItem) * ft->bindings.instanceCounter, tmpBufferDetails);
+ {
+ VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
+ vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ vkCommandBufferBeginInfo.pNext = nullptr;
+ // TODO consider single-use?
+ vkCommandBufferBeginInfo.flags = 0;
+ vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
+ vkResult = vkBeginCommandBuffer(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo);
+ assert(vkResult == VK_SUCCESS);
+
+ memcpy(tmpBufferDetails.deviceData, fibis, sizeof(FontInstanceBufferItem) * ft->bindings.instanceCounter);
+
+ VkBufferCopy vk_buffer_copy{};
+ vk_buffer_copy.srcOffset = 0;
+ vk_buffer_copy.dstOffset = 0;
+ vk_buffer_copy.size = sizeof(FontInstanceBufferItem) * ft->bindings.instanceCounter;
+ vkCmdCopyBuffer(tmpBufferDetails.cmdBuffer, tmpBufferDetails.buffer, ft->bindings.instanceBD.buffer, 1, &vk_buffer_copy);
+
+ vkResult = vkEndCommandBuffer(tmpBufferDetails.cmdBuffer);
+ assert(vkResult == VK_SUCCESS);
+
+ VkSubmitInfo submitInfo;
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.pNext = nullptr;
+ submitInfo.waitSemaphoreCount = 0;
+ submitInfo.pWaitSemaphores = nullptr;
+ submitInfo.pWaitDstStageMask = nullptr;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &tmpBufferDetails.cmdBuffer;
+ submitInfo.signalSemaphoreCount = 0;
+ submitInfo.pSignalSemaphores = nullptr;
+ vkResult = vkQueueSubmit(tmpBufferDetails.queue, 1, &submitInfo, nullptr);
+ assert(vkResult == VK_SUCCESS);
+ vkResult = vkQueueWaitIdle(tmpBufferDetails.queue);
+ assert(vkResult == VK_SUCCESS);
+ }
+ PKVK_EndBuffer(tmpBufferDetails);
+ pk_delete<FontInstanceBufferItem>(fibis, ft->bindings.instanceCounter);
+ }
+}
+
void FontType_Serialize(std::ofstream &stream, FontType *ft) {
FontTypeSpacing sp{};
memset(&sp, 0, sizeof(sp));
@@ -786,6 +905,17 @@ 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) {
+ if (ft->renders[i].glyph_indices != nullptr) {
+ pk_delete<uint32_t>(ft->renders[i].glyph_indices, ft->renders[i].n_glyphs);
+ }
+ }
+ pk_delete<FontRender>(ft->renders, (FontTypeIndex_T)ft->n_render);
+ }
+
if (ft->gr.vkDescriptorSets != VK_NULL_HANDLE && ft->gr.vkDescriptorPool != VK_NULL_HANDLE) {
// 2023-09-27 - JCB (copied from entities.cpp)
// We are not setting the pool flag for allowing freeing descriptor sets
@@ -864,13 +994,13 @@ void FontType_Unload(FontTypeIndex idx) {
// This could probably be shortened or deferred by creating a larger-than-needed
// buffer.
// TODO threading
-FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
+FontRender FontType_AddStringRender(FontTypeIndex idx_ft, const pk_str str, FontRenderSettings *settings) {
+ assert(settings != nullptr);
VkResult vkResult;
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx_ft];
FontRender *fr;
FontGlyphChar *fgc;
FontRenderIndex idx_fr = ft->n_render;
- DynArray<FontInstanceBufferItem> instance_buffer_items;
uint32_t i, ii, u, count;
int32_t l, m, r;
@@ -882,27 +1012,26 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
ft->renders = arr;
}
fr = &ft->renders[(FontRenderIndex_T)idx_fr];
- fr->len = cstr.length;
fr->index_ft = idx_ft;
fr->index_fr = idx_fr;
+ fr->settings = *settings;
// insert new characters into tmp buffer
- instance_buffer_items.Reserve(cstr.length);
{
+ DynArray<uint32_t> glyph_indices;
+ glyph_indices.Reserve(str.length);
count = 0;
- FontInstanceBufferItem *buf_item;
- for (i = 0; i < cstr.length;) {
+ for (i = 0; i < str.length;) {
fgc = nullptr;
u = 0;
// determine unicode char
- ii = utf8_to_unicode(&cstr.val[i], u);
+ ii = utf8_to_unicode(&str.val[i], u);
if (ii == 0) {
- fprintf(stderr, "failed to determine unicode for character: '%c'\n", cstr.val[i]);
+ fprintf(stderr, "failed to determine unicode for character: '%c' at byte index: '%i'\n", str.val[i], i);
i += 1;
continue;
}
i += ii;
- count += 1;
// binary search for glyph details
l = 0;
@@ -917,23 +1046,27 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
} while (fgc->unicode != u && l <= r);
if (fgc->unicode != u) {
- fprintf(stderr, "font: '%s' doesn't contain unicode character: '%u'\n", ft->title.val, u);
+ fprintf(stderr, "font: '%s' doesn't contain unicode character '%u': '%lc'\n", ft->title.val, u, (wint_t)u);
continue;
}
+ count += 1;
+ glyph_indices.Push(m);
+ }
- buf_item = &instance_buffer_items.Push();
- 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;
- buf_item->width = 24;
+ // TODO specific bucket
+ fr->n_glyphs = count;
+ fr->glyph_indices = pk_new<uint32_t>(count);
+ for (i = 0; i < count; ++i) {
+ fr->glyph_indices[i] = glyph_indices[i];
}
}
+
VkDeviceSize item_count_orig = ft->bindings.instanceCounter;
VkDeviceSize item_count_new = ft->bindings.instanceCounter + count;
// copy existing buffer to new buffer
- VkDeviceSize byteCount = instance_buffer_item_size * item_count_new;
+ // create new buffer
+ VkDeviceSize byteCount = sizeof(FontInstanceBufferItem) * item_count_new;
PKVK_TmpBufferDetails tmpBufferDetails{};
{
VkBuffer newBuffer;
@@ -951,6 +1084,7 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
VkMemoryRequirements vkMemReqs;
vkGetBufferMemoryRequirements(vkDevice, newBuffer, &vkMemReqs);
+ assert(sizeof(FontInstanceBufferItem) % vkMemReqs.alignment == 0);
vkDestroyBuffer(vkDevice, newBuffer, vkAllocator);
newBuffer = VK_NULL_HANDLE;
@@ -972,8 +1106,8 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
vkResult = vkBindBufferMemory(vkDevice, newBuffer, new_memory, 0);
assert(vkResult == VK_SUCCESS);
- PKVK_BeginBuffer(transferFamilyIndex, byteCount, tmpBufferDetails, PKVK_TmpBufferFlags_NONE);
if (ft->bindings.instanceBD.buffer != VK_NULL_HANDLE) {
+ PKVK_BeginBuffer(transferFamilyIndex, byteCount, tmpBufferDetails, PKVK_TmpBufferFlags_NONE);
VkCommandBufferBeginInfo vkCommandBufferBeginInfo;
vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -981,15 +1115,17 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
// TODO consider single-use?
vkCommandBufferBeginInfo.flags = 0;
vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
- vkBeginCommandBuffer(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo);
+ vkResult = vkBeginCommandBuffer(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo);
+ assert(vkResult == VK_SUCCESS);
VkBufferCopy vk_buffer_copy{};
vk_buffer_copy.srcOffset = 0;
vk_buffer_copy.dstOffset = 0;
- vk_buffer_copy.size = instance_buffer_item_size * item_count_orig;
+ vk_buffer_copy.size = sizeof(FontInstanceBufferItem) * item_count_orig;
vkCmdCopyBuffer(tmpBufferDetails.cmdBuffer, ft->bindings.instanceBD.buffer, newBuffer, 1, &vk_buffer_copy);
- vkEndCommandBuffer(tmpBufferDetails.cmdBuffer);
+ vkResult = vkEndCommandBuffer(tmpBufferDetails.cmdBuffer);
+ assert(vkResult == VK_SUCCESS);
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -1001,11 +1137,13 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
submitInfo.pCommandBuffers = &tmpBufferDetails.cmdBuffer;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr;
- vkQueueSubmit(tmpBufferDetails.queue, 1, &submitInfo, nullptr);
- vkQueueWaitIdle(tmpBufferDetails.queue);
+ vkResult = vkQueueSubmit(tmpBufferDetails.queue, 1, &submitInfo, nullptr);
+ assert(vkResult == VK_SUCCESS);
+ vkResult = vkQueueWaitIdle(tmpBufferDetails.queue);
+ assert(vkResult == VK_SUCCESS);
+ PKVK_EndBuffer(tmpBufferDetails, PKVK_TmpBufferFlags_NONE);
}
- PKVK_EndBuffer(tmpBufferDetails, PKVK_TmpBufferFlags_NONE);
if (ft->bindings.instanceBD.buffer != VK_NULL_HANDLE)
vkDestroyBuffer(vkDevice, ft->bindings.instanceBD.buffer, vkAllocator);
if (ft->gr.deviceMemoryInst != VK_NULL_HANDLE)
@@ -1017,7 +1155,7 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
}
// create tmp local buffer & copy data to graphics card
- byteCount = instance_buffer_item_size * count;
+ byteCount = sizeof(FontInstanceBufferItem) * count;
PKVK_BeginBuffer(transferFamilyIndex, byteCount, tmpBufferDetails);
{
@@ -1027,17 +1165,19 @@ FontRender FontType_AddStringRender(FontTypeIndex idx_ft, pk_cstr cstr) {
// TODO consider single-use?
vkCommandBufferBeginInfo.flags = 0;
vkCommandBufferBeginInfo.pInheritanceInfo = nullptr;
- vkBeginCommandBuffer(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo);
+ vkResult = vkBeginCommandBuffer(tmpBufferDetails.cmdBuffer, &vkCommandBufferBeginInfo);
+ assert(vkResult == VK_SUCCESS);
- memcpy(tmpBufferDetails.deviceData, instance_buffer_items.GetPtr(), instance_buffer_items.Count() * instance_buffer_item_size);
+ FontType_Inner_CalcTransforms(ft, fr, (FontInstanceBufferItem*)tmpBufferDetails.deviceData);
VkBufferCopy vk_buffer_copy{};
vk_buffer_copy.srcOffset = 0;
- vk_buffer_copy.dstOffset = instance_buffer_item_size * item_count_orig;
- vk_buffer_copy.size = instance_buffer_item_size * count;
+ vk_buffer_copy.dstOffset = sizeof(FontInstanceBufferItem) * item_count_orig;
+ vk_buffer_copy.size = sizeof(FontInstanceBufferItem) * count;
vkCmdCopyBuffer(tmpBufferDetails.cmdBuffer, tmpBufferDetails.buffer, ft->bindings.instanceBD.buffer, 1, &vk_buffer_copy);
- vkEndCommandBuffer(tmpBufferDetails.cmdBuffer);
+ vkResult = vkEndCommandBuffer(tmpBufferDetails.cmdBuffer);
+ assert(vkResult == VK_SUCCESS);
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;