diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-16 09:51:00 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-06-16 09:51:00 -0400 |
| commit | 66ebed74456f76277597b3b07f3e67cc45388ece (patch) | |
| tree | 5e7d0c429867a294bca78269124954ce0a4823fc | |
| parent | c1ad6ceeb301bc1f2a4f850e08587748a6d9107b (diff) | |
pke: update FontRender text (editor: for ui-box)
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | editor/editor.cpp | 129 | ||||
| -rw-r--r-- | src/font.cpp | 315 | ||||
| -rw-r--r-- | src/font.hpp | 1 | ||||
| -rw-r--r-- | src/static-ui.cpp | 4 | ||||
| -rw-r--r-- | src/static-ui.hpp | 49 | ||||
| -rw-r--r-- | src/vendor-imgui-ext.cpp | 42 | ||||
| -rw-r--r-- | src/vendor-imgui-ext.hpp | 13 |
8 files changed, 339 insertions, 215 deletions
@@ -163,6 +163,7 @@ $(DIR_OBJ)/libImgui.$(LIB_EXT): $(DIR_OBJ)/imgui_widgets.$(OBJ_EXT) $(DIR_OBJ)/libImgui.$(LIB_EXT): $(DIR_OBJ)/imgui_impl_glfw.$(OBJ_EXT) $(DIR_OBJ)/libImgui.$(LIB_EXT): $(DIR_OBJ)/imgui_impl_vulkan.$(OBJ_EXT) $(DIR_OBJ)/libImgui.$(LIB_EXT): $(DIR_OBJ)/imgui_stdlib.$(OBJ_EXT) +$(DIR_OBJ)/libImgui.$(LIB_EXT): $(DIR_OBJ)/vendor-imgui-ext.$(OBJ_EXT) ar rc $@ $^ ranlib $@ diff --git a/editor/editor.cpp b/editor/editor.cpp index b48a40e..9257f6a 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -24,6 +24,7 @@ #include "static-ui.hpp" #include "thread-pool.hpp" #include "vendor-glm-include.hpp" +#include "vendor-imgui-ext.hpp" #include "vendor-tinyfiledialogs.h" #include "window.hpp" #include "pk.h" @@ -65,12 +66,21 @@ bool shouldDisableEditor = false; bool shouldRebuildProjectDir = true; bool shouldRebuildAssetList = true; +// TODO Can't make certain changes *this* tick through DearImGui. +// ex: Changing text in a FontRender, adding an instance, etc. +// Specifically when it causes a vulkan buffer resize. +// Each "should" should be refactored *out* of the editor. +// ex: ecs should be responsible for creating instances in a deferred manner. +// - COULD lead to ugly callbacks or listeners? +// Suggestion: Consider a minor engine change that adds a post-tick phase, so that if the engine sleeps we don't slow down the next tick when it can be avoided. +// Note: Could have ecs implications (marked for removal, etc) pk_arr_t<EntityType *> entityInstancesToCreate{}; CompInstance *selectedEntity = nullptr; CompInstance *hoveredEntity = nullptr; bool shouldCreateEntityType = false; EntityType entityTypeToCreate{}; CameraHandle selectedCamera = CameraHandle_MAX; +static pke_ui_box *selected_ui_box = NULL; const char* const newSceneName = "newScene.pstf"; bool shouldOpenLoadSceneDialog = false; @@ -228,6 +238,7 @@ void PkeEditor_Tick(double delta) { const PkeMouseButtonEvent *mbEvent = static_cast<PkeMouseButtonEvent *>(holder.ptr); if (mbEvent->isPressed) { selectedEntity = nullptr; + selected_ui_box = nullptr; } } } @@ -1225,6 +1236,122 @@ void RecordImGuiCameras() { ImGui::End(); } +void RecordImGuiUITree_inner(pke_ui_box *box) { + if (ImGui::TreeNode(box, pk_uuid_printf_format, pk_uuid_printf_var(box->uuid))) { + ImGui::SameLine(); + if (ImGui::Selectable("SELECT", false, 0)) { + selected_ui_box = box; + } + for (int i = 0; i < box->internal.h_children; ++i) { + RecordImGuiUITree_inner(box->internal.children[i]); + } + ImGui::TreePop(); + } +} +void RecordImGuiUITree() { + if (!ImGui::Begin("pke_ui_tree")) { + ImGui::End(); + return; + } + pke_ui_box_count_T count; + pke_ui_box ** root_boxes = pke_ui_get_root_boxes(&count); + for (int i = 0; i < count; ++i) { + pke_ui_box *box = root_boxes[i]; + RecordImGuiUITree_inner(box); + } + // if (ImGui::Selectable( + ImGui::End(); +} +void RecordImGuiUIEdit() { + const ImGuiInputTextFlags text_flags = ImGuiInputTextFlags_AllowTabInput; + bool changed; + if (!ImGui::Begin("pke_ui_edit")) { + ImGui::End(); + return; + } + if (selected_ui_box == NULL) { + ImGui::End(); + return; + } + + changed = false; + + ImGui::Text("Position Type:"); + ImGui::BeginDisabled(PK_HAS_FLAG(selected_ui_box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX)); + if (ImGui::Button("Flex")) { + selected_ui_box->flags &= ~(const_cast<PKE_UI_BOX_FLAG&>(PKE_UI_BOX_FLAG_POSITION_TYPE_ALL)); + selected_ui_box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX; + changed = true; + } + ImGui::EndDisabled(); + ImGui::SameLine(); + ImGui::BeginDisabled(PK_HAS_FLAG(selected_ui_box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC)); + if (ImGui::Button("Static")) { + selected_ui_box->flags &= ~(const_cast<PKE_UI_BOX_FLAG&>(PKE_UI_BOX_FLAG_POSITION_TYPE_ALL)); + selected_ui_box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; + changed = true; + } + ImGui::EndDisabled(); + ImGui::SameLine(); + ImGui::BeginDisabled(PK_HAS_FLAG(selected_ui_box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC)); + if (ImGui::Button("Dynamic")) { + selected_ui_box->flags &= ~(const_cast<PKE_UI_BOX_FLAG&>(PKE_UI_BOX_FLAG_POSITION_TYPE_ALL)); + selected_ui_box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC; + changed = true; + } + ImGui::EndDisabled(); + + ImGui::Separator(); + + if (ImGui::CheckboxFlags("flag: Center Horizontal", reinterpret_cast<PKE_UI_BOX_FLAG_T*>(&selected_ui_box->flags), static_cast<PKE_UI_BOX_FLAG_T>(PKE_UI_BOX_FLAG_CENTER_HORIZONTAL))) { + changed = true; + } + if (ImGui::CheckboxFlags("flag: Center Vertical", reinterpret_cast<PKE_UI_BOX_FLAG_T*>(&selected_ui_box->flags), static_cast<PKE_UI_BOX_FLAG_T>(PKE_UI_BOX_FLAG_CENTER_VERTICAL))) { + changed = true; + } + ImGui::Separator(); + + changed = ImGui::InputScalarN("flags", ImGuiDataType_U64, &selected_ui_box->flags, 1, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly) || changed; + changed = ImGui::InputScalarN("pos_top_left", ImGuiDataType_Float, &selected_ui_box->pos_top_left, 2, nullptr, nullptr, nullptr, 0) || changed; + changed = ImGui::InputScalarN("min_size", ImGuiDataType_Float, &selected_ui_box->min_size, 2, nullptr, nullptr, nullptr, 0) || changed; + changed = ImGui::InputScalarN("max_size", ImGuiDataType_Float, &selected_ui_box->max_size, 2, nullptr, nullptr, nullptr, 0) || changed; + changed = ImGui::InputScalarN("flex_weight", ImGuiDataType_Float, &selected_ui_box->flex_weight, 1, nullptr, nullptr, nullptr, 0) || changed; + changed = ImGui::InputScalarN("flex_direction", ImGuiDataType_U8, &selected_ui_box->flex_direction, 1, nullptr, nullptr, nullptr, 0) || changed; + changed = ImGui::InputScalarN("layer", ImGuiDataType_U8, &selected_ui_box->layer, 1, nullptr, nullptr, nullptr, 0) || changed; + + if (selected_ui_box->type == PKE_UI_BOX_TYPE_TEXT) { + assert(selected_ui_box->type_data != NULL); + ImGui::Text("Type: Text"); + ImGui::Separator(); + FontRender fr = *FontType_GetFontRender(selected_ui_box->type_data->text.font_render_handle); + const int buffer_len = 1024; + char *text_buffer = pk_new<char>(buffer_len, pkeSettings.mem_bkt.game_transient); + size_t len = fr.text.length; + sprintf(text_buffer, "%s", fr.text.val); + // nocheckin test this + if (ImGui::InputText("Text", text_buffer, buffer_len-1, text_flags)) { + // TODO specific bucket + len = strlen(text_buffer); + char *s = pk_new<char>(len + 1); + sprintf(s, "%s", text_buffer); + pk_cstr cstr{}; + cstr.reserved = len+1; + cstr.length = len; + cstr.val = s; + FontType_UpdateStringRenderText(fr.fr_handle, std::move(cstr)); + changed = true; + } + ImGui::SameLine(); + ImGui::Text("(%.4zu/%4i)", len, buffer_len); + } + + if (changed) { + pke_ui_force_recalc(); + } + + ImGui::End(); +} + void RecordImGuiUBO() { if (!ImGui::Begin("UBO", &pkeSettings.editorSettings.isShowingUBO)) { ImGui::End(); @@ -1784,6 +1911,8 @@ void PkeEditor_RecordImGui() { RecordImGuiSceneEditor(); RecordImGuiUBO(); RecordImGuiCameras(); + RecordImGuiUITree(); + RecordImGuiUIEdit(); RecordImGuiLevels(); RecordImGuiEntityTypes(); RecordImGuiAssets(); diff --git a/src/font.cpp b/src/font.cpp index 1c06a06..9a0692c 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -295,20 +295,53 @@ void FontType_Tick(double delta) { if (pkeSettings.rt.was_framebuffer_resized == false && ft->gr.should_update_instance_buffer == false) { continue; } - if (ft->bindings.instance_counter == 0) + + // TODO specific bucket + for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) { + index += ft->renders[k].n_glyphs; + } + + if (index == 0) { continue; + } ft->gr.should_update_instance_buffer = false; - // TODO specific bucket - fibis = pk_new<FontInstanceBufferItem>(ft->bindings.instance_counter); + fibis = pk_new<FontInstanceBufferItem>(index); + ft->bindings.instance_counter = index; + index = 0; for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) { fr = &ft->renders[k]; FontType_Inner_CalcTransforms(ft, fr, &fibis[index]); index += fr->n_glyphs; } + // check recreate buffer + if (ft->bindings.instance_buffer_max_count < index) { + if (ft->bindings.bd_instance.buffer != VK_NULL_HANDLE) { + vkDestroyBuffer(vkDevice, ft->bindings.bd_instance.buffer, vkAllocator); + ft->bindings.bd_instance.buffer = VK_NULL_HANDLE; + ft->bindings.bd_instance.offsets[0] = 0; + vkFreeMemory(vkDevice, ft->gr.deviceMemoryInst, vkAllocator); + ft->gr.deviceMemoryInst = VK_NULL_HANDLE; + } + + pkvk_buffer_create_data create_data{}; + create_data.buffer_byte_length[0] = sizeof(FontInstanceBufferItem) * ft->bindings.instance_counter; + create_data.n_buffers = 1; + create_data.index_instance = 0; + create_data.index_index = -1; + + pkvk_buffer_create_data_out out{}; + pkvk_buffer_create(&create_data, &out); + + ft->bindings.bd_instance.buffer = out.buffers[0]; + ft->gr.deviceMemoryInst = out.device_memory_instance; + ft->bindings.instance_buffer_max_count = out.memory_requirements_instance.size / sizeof(FontInstanceBufferItem); + } + PKVK_TmpBufferDetails tmpBufferDetails{}; PKVK_BeginBuffer(graphicsFamilyIndex, sizeof(FontInstanceBufferItem) * ft->bindings.instance_counter, tmpBufferDetails); + assert(tmpBufferDetails.buffer != VK_NULL_HANDLE); { VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -769,6 +802,42 @@ void FontType_Unload(FontTypeIndex idx) { ECS_MarkForRemoval(ft); } +void FontType_cstr_to_unicode(const FontType &ft, pk_arr_t<uint32_t> &arr, const pk_cstr &str) { + uint32_t i, ii, u; + int32_t l, m, r; + FontGlyphChar *fgc; + for (i = 0; i < str.length;) { + fgc = nullptr; + u = 0; + // determine unicode char + ii = utf8_to_unicode(&str.val[i], u); + if (ii == 0) { + fprintf(stderr, "failed to determine unicode for character: at byte index: '%i'\n", i); + i += 1; + continue; + } + i += ii; + + // binary search for glyph details + l = 0; + r = ft.n_glyphs - 1; + do { + m = l + (r-l)/2; + fgc = &ft.glyphs[m]; + if (fgc->unicode < u) + l = m + 1; + else + r = m - 1; + } while (fgc->unicode != u && l <= r); + + if (fgc->unicode != u) { + fprintf(stderr, "font: '%s' does not contain unicode character '%u'\n", ft.title.val, u); + continue; + } + pk_arr_append_t(&arr, uint32_t(m)); + } +} + // TODO perf? // 2025-02-19 - JCB // We only create a new buffer if it is needed. @@ -777,22 +846,18 @@ void FontType_Unload(FontTypeIndex idx) { // At the time of writing, the only way to do this is to un-register text. FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr &&str, FontRenderSettings *settings, Entity_Base *parent, pk_uuid uuid) { assert(settings != nullptr); - PKVK_TmpBufferDetails tmpBufferDetails{}; - VkDeviceSize byteCount; - VkResult vkResult; FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx_ft]; FontRender *fr; - FontGlyphChar *fgc; - uint32_t i, ii, u, count; - int32_t l, m, r; + uint32_t i, count; FontRenderIndex idx_fr = ft->h_render; ft->h_render += FontRenderIndex{1}; if (ft->h_render >= ft->n_render) { + FontRenderIndex_T old_count{static_cast<FontRenderIndex_T>(ft->n_render)}; ft->n_render += FontRenderIndex{5}; FontRender *arr = pk_new<FontRender>((FontRenderIndex_T)ft->n_render); - memcpy(arr, ft->renders, sizeof(FontRender) * (FontRenderIndex_T)idx_fr); - pk_delete<FontRender>(ft->renders, (FontRenderIndex_T)idx_fr); + memcpy(arr, ft->renders, sizeof(FontRender) * old_count); + pk_delete<FontRender>(ft->renders, old_count); ft->renders = arr; } fr = &ft->renders[(FontRenderIndex_T)idx_fr]; @@ -804,190 +869,28 @@ FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr && fr->settings = *settings; fr->text = str; - if (window != NULL) { - // insert new characters into tmp buffer - { - pk_arr_t<uint32_t> glyph_indices{}; - glyph_indices.bkt = pkeSettings.mem_bkt.game_transient; - pk_arr_reserve(&glyph_indices, str.length); - count = 0; - for (i = 0; i < str.length;) { - fgc = nullptr; - u = 0; - // determine unicode char - ii = utf8_to_unicode(&str.val[i], u); - if (ii == 0) { - fprintf(stderr, "failed to determine unicode for character: at byte index: '%i'\n", i); - i += 1; - continue; - } - i += ii; - - // binary search for glyph details - l = 0; - r = ft->n_glyphs - 1; - do { - m = l + (r-l)/2; - fgc = &ft->glyphs[m]; - if (fgc->unicode < u) - l = m + 1; - else - r = m - 1; - } while (fgc->unicode != u && l <= r); - - if (fgc->unicode != u) { - fprintf(stderr, "font: '%s' does not contain unicode character '%u'\n", ft->title.val, u); - continue; - } - count += 1; - pk_arr_append_t(&glyph_indices, uint32_t(m)); - } - - // 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]; - } - glyph_indices.data = nullptr; - } - - VkDeviceSize item_count_orig = ft->bindings.instance_counter; - VkDeviceSize item_length_new = PK_MAX(ft->bindings.instance_buffer_max_count, ft->bindings.instance_counter + count); - - // copy existing buffer to new buffer - // create new buffer - if (ft->bindings.instance_buffer_max_count < item_length_new) { - byteCount = sizeof(FontInstanceBufferItem) * item_length_new; - VkBuffer newBuffer; - VkBufferCreateInfo bufferCI; - bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCI.pNext = nullptr; - bufferCI.flags = {}; - bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufferCI.queueFamilyIndexCount = 1; - bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex; - bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - bufferCI.size = byteCount; - vkResult = vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &newBuffer); - assert(vkResult == VK_SUCCESS); - - VkMemoryRequirements vkMemReqs; - vkGetBufferMemoryRequirements(vkDevice, newBuffer, &vkMemReqs); - assert(sizeof(FontInstanceBufferItem) % vkMemReqs.alignment == 0); - - vkDestroyBuffer(vkDevice, newBuffer, vkAllocator); - newBuffer = VK_NULL_HANDLE; - - bufferCI.size = vkMemReqs.size + (vkMemReqs.alignment - (vkMemReqs.size & vkMemReqs.alignment)); - vkResult = vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &newBuffer); - assert(vkResult == VK_SUCCESS); - - VkDeviceMemory new_memory; - VkMemoryAllocateInfo vkMemoryAllocateInfo; - vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - vkMemoryAllocateInfo.pNext = nullptr; - vkMemoryAllocateInfo.allocationSize = bufferCI.size; - vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - vkResult = vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &new_memory); - assert(vkResult == VK_SUCCESS); - - vkResult = vkBindBufferMemory(vkDevice, newBuffer, new_memory, 0); - assert(vkResult == VK_SUCCESS); - - if (ft->bindings.bd_instance.buffer != VK_NULL_HANDLE && ft->bindings.instance_counter > 0) { - PKVK_BeginBuffer(transferFamilyIndex, byteCount, tmpBufferDetails, PKVK_TmpBufferFlags_NONE); - - 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); - - VkBufferCopy vk_buffer_copy{}; - vk_buffer_copy.srcOffset = 0; - vk_buffer_copy.dstOffset = 0; - vk_buffer_copy.size = sizeof(FontInstanceBufferItem) * ft->bindings.instance_counter; - assert(vk_buffer_copy.size != 0); - vkCmdCopyBuffer(tmpBufferDetails.cmdBuffer, ft->bindings.bd_instance.buffer, newBuffer, 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, PKVK_TmpBufferFlags_NONE); - } - if (ft->bindings.bd_instance.buffer != VK_NULL_HANDLE) - vkDestroyBuffer(vkDevice, ft->bindings.bd_instance.buffer, vkAllocator); - if (ft->gr.deviceMemoryInst != VK_NULL_HANDLE) - vkFreeMemory(vkDevice, ft->gr.deviceMemoryInst, vkAllocator); - - ft->gr.deviceMemoryInst = new_memory; - ft->bindings.bd_instance.buffer = newBuffer; - } - ft->bindings.instance_buffer_max_count = item_length_new; - ft->bindings.instance_counter += count; - - // create tmp local buffer & copy data to graphics card - byteCount = sizeof(FontInstanceBufferItem) * count; - PKVK_BeginBuffer(transferFamilyIndex, byteCount, 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); - - FontType_Inner_CalcTransforms(ft, fr, (FontInstanceBufferItem*)tmpBufferDetails.deviceData); + if (window == NULL) { + return fr->fr_handle; + } - VkBufferCopy vk_buffer_copy{}; - vk_buffer_copy.srcOffset = 0; - vk_buffer_copy.dstOffset = sizeof(FontInstanceBufferItem) * item_count_orig; - vk_buffer_copy.size = sizeof(FontInstanceBufferItem) * count; - vkCmdCopyBuffer(tmpBufferDetails.cmdBuffer, tmpBufferDetails.buffer, ft->bindings.bd_instance.buffer, 1, &vk_buffer_copy); + // insert new characters into tmp buffer + pk_arr_t<uint32_t> glyph_indices{}; + glyph_indices.bkt = pkeSettings.mem_bkt.game_transient; + glyph_indices.next = 0; // hide garbage val warning + pk_arr_reserve(&glyph_indices, str.length); - vkResult = vkEndCommandBuffer(tmpBufferDetails.cmdBuffer); - assert(vkResult == VK_SUCCESS); + FontType_cstr_to_unicode(*ft, glyph_indices, str); - 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); + // TODO specific bucket + count = glyph_indices.next; + 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]; } + glyph_indices.data = nullptr; + + ft->gr.should_update_instance_buffer = true; return fr->fr_handle; } @@ -1008,6 +911,36 @@ void FontType_UpdateStringRender(FontRenderHandle frh, FontRenderSettings *setti ft->renders[(FontRenderIndex_T)frh.index_fr].settings = *settings; } +void FontType_UpdateStringRenderText(FontRenderHandle frh, pk_cstr &&cstr) { + uint32_t i, count; + assert(frh.index_ft < ftd.h_ft); + FontType &ft = ftd.arr_ft[static_cast<FontTypeIndex_T>(frh.index_ft)]; + assert(frh.index_fr < ft.h_render); + FontRender &fr = ft.renders[static_cast<FontRenderIndex_T>(frh.index_fr)]; + pk_cstr old_str = fr.text; + if (window == NULL) { + return; + } + pk_arr_t<uint32_t> glyph_indices{}; + glyph_indices.bkt = pkeSettings.mem_bkt.game_transient; + pk_arr_reserve(&glyph_indices, PK_MAX(1, fr.n_glyphs + (cstr.length - old_str.length))); + + FontType_cstr_to_unicode(ft, glyph_indices, cstr); + + // TODO specific bucket + count = glyph_indices.next; + 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]; + } + glyph_indices.data = nullptr; + if (fr.text.reserved > 0 && fr.text.val != NULL) pk_delete<char>(fr.text.val, fr.text.reserved); + fr.text = cstr; + + ft.gr.should_update_instance_buffer = true; +} + void FontType_RemoveStringRender(FontRenderHandle handle) { FontRender *fr; uint32_t buffer_start_index; diff --git a/src/font.hpp b/src/font.hpp index f07e640..567062e 100644 --- a/src/font.hpp +++ b/src/font.hpp @@ -126,6 +126,7 @@ void FontType_Unload(FontTypeIndex idx); FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr &&str, FontRenderSettings *settings, Entity_Base *parent = nullptr, pk_uuid uuid = pk_uuid_zed); FontRender *FontType_GetFontRender(FontRenderHandle frh); void FontType_UpdateStringRender(FontRenderHandle frh, FontRenderSettings *settings); +void FontType_UpdateStringRenderText(FontRenderHandle frh, pk_cstr &&cstr); void FontType_RemoveStringRender(FontRenderHandle frh); #endif /* PKE_FONT_TYPE_HPP */ diff --git a/src/static-ui.cpp b/src/static-ui.cpp index c6b7108..81e0511 100644 --- a/src/static-ui.cpp +++ b/src/static-ui.cpp @@ -44,6 +44,10 @@ void pke_ui_init() { pke_ui_master.bindings = {}; } +void pke_ui_force_recalc() { + pke_ui_master.should_recalc_ui = true; +} + void pke_ui_init_bindings() { pkvk_buffer_create_data create_data{}; create_data.buffer_byte_length[0] = sizeof(pkeIntrinsicsPlane.vert[0]) * 4; diff --git a/src/static-ui.hpp b/src/static-ui.hpp index f0e5c3c..6d5c61c 100644 --- a/src/static-ui.hpp +++ b/src/static-ui.hpp @@ -22,43 +22,43 @@ TypeSafeInt_H(PKE_UI_BOX_TYPE, uint8_t, 0xFF); TypeSafeInt_H(PKE_UI_BOX_FLAG, uint64_t, 0xFFFFFFFFFFFFFFFF); // layouts -constexpr PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_STANDARD - = PKE_UI_BOX_TYPE(000); +const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_STANDARD + = PKE_UI_BOX_TYPE(000); // TODO columns, rows, tabs, etc // special (content) -constexpr PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_TEXT - = PKE_UI_BOX_TYPE(050); +const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_TEXT + = PKE_UI_BOX_TYPE(050); // TODO image, render target, etc // inputs -constexpr PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_INPUT_TEXT - = PKE_UI_BOX_TYPE(100); +const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_INPUT_TEXT + = PKE_UI_BOX_TYPE(100); // TODO multi-line text, scalar, float, slider, button, etc -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_NONE - = PKE_UI_BOX_FLAG(0); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_NONE + = PKE_UI_BOX_FLAG(0); // [00-04] position type // exact screen coordinates -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX - = PKE_UI_BOX_FLAG((1 << 0)); -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC - = PKE_UI_BOX_FLAG((1 << 1)); -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC - = PKE_UI_BOX_FLAG((1 << 2)); -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_ALL - = PKE_UI_BOX_FLAG((1 << 0) | (1 << 1) | (1 << 2)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX + = PKE_UI_BOX_FLAG((1 << 0)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC + = PKE_UI_BOX_FLAG((1 << 1)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC + = PKE_UI_BOX_FLAG((1 << 2)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_POSITION_TYPE_ALL + = PKE_UI_BOX_FLAG((1 << 0) | (1 << 1) | (1 << 2)); // [05-06] center -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_HORIZONTAL - = PKE_UI_BOX_FLAG((1 << 5)); -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_VERTICAL - = PKE_UI_BOX_FLAG((1 << 6)); -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_BOTH - = PKE_UI_BOX_FLAG((1 << 5) | (1 << 6)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_HORIZONTAL + = PKE_UI_BOX_FLAG((1 << 5)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_VERTICAL + = PKE_UI_BOX_FLAG((1 << 6)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_CENTER_BOTH + = PKE_UI_BOX_FLAG((1 << 5) | (1 << 6)); // [07-09] visibility -constexpr PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE - = PKE_UI_BOX_FLAG((1 << 7)); +const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE + = PKE_UI_BOX_FLAG((1 << 7)); // [10-??] typedef uint16_t pke_ui_box_count_T; @@ -113,6 +113,7 @@ void pke_ui_init(); void pke_ui_init_bindings(); void pke_ui_tick(double delta); void pke_ui_teardown(); +void pke_ui_force_recalc(); pke_ui_box **pke_ui_get_root_boxes(pke_ui_box_count_T *count); diff --git a/src/vendor-imgui-ext.cpp b/src/vendor-imgui-ext.cpp new file mode 100644 index 0000000..743261b --- /dev/null +++ b/src/vendor-imgui-ext.cpp @@ -0,0 +1,42 @@ + +#include "vendor-imgui-ext.hpp" +#include "imgui_internal.h" + +// copy-pasted +// TODO submit PR so this isn't necessary +template<typename T> +bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) +{ + bool all_on = (*flags & flags_value) == flags_value; + bool any_on = (*flags & flags_value) != 0; + bool pressed; + if (!all_on && any_on) + { + ImGuiContext& g = *GImGui; + g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue; + pressed = Checkbox(label, &all_on); + } + else + { + pressed = Checkbox(label, &all_on); + + } + if (pressed) + { + if (all_on) + *flags |= flags_value; + else + *flags &= ~flags_value; + } + return pressed; +} + +bool ImGui::CheckboxFlags(const char* label, long int* flags, long int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, unsigned long int* flags, unsigned long int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} diff --git a/src/vendor-imgui-ext.hpp b/src/vendor-imgui-ext.hpp new file mode 100644 index 0000000..94e4212 --- /dev/null +++ b/src/vendor-imgui-ext.hpp @@ -0,0 +1,13 @@ +#ifndef PKE_VENDOR_IMGUI_EXT_H +#define PKE_VENDOR_IMGUI_EXT_H + +#include "imgui.h" + +namespace ImGui { + +IMGUI_API bool CheckboxFlags(const char* label, long int* flags, long int flags_value); +IMGUI_API bool CheckboxFlags(const char* label, unsigned long int* flags, unsigned long int flags_value); + +} // namespace ImGui + +#endif /* PKE_VENDOR_IMGUI_EXT_H */ |
