summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-06-16 09:51:00 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-06-16 09:51:00 -0400
commit66ebed74456f76277597b3b07f3e67cc45388ece (patch)
tree5e7d0c429867a294bca78269124954ce0a4823fc
parentc1ad6ceeb301bc1f2a4f850e08587748a6d9107b (diff)
pke: update FontRender text (editor: for ui-box)
-rw-r--r--Makefile1
-rw-r--r--editor/editor.cpp129
-rw-r--r--src/font.cpp315
-rw-r--r--src/font.hpp1
-rw-r--r--src/static-ui.cpp4
-rw-r--r--src/static-ui.hpp49
-rw-r--r--src/vendor-imgui-ext.cpp42
-rw-r--r--src/vendor-imgui-ext.hpp13
8 files changed, 339 insertions, 215 deletions
diff --git a/Makefile b/Makefile
index cbb8f1a..d364bff 100644
--- a/Makefile
+++ b/Makefile
@@ -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 */