diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-02-28 22:33:58 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-02-28 22:33:58 -0500 |
| commit | 37347bf7811a5fa42c98e2a19adfee15252ee479 (patch) | |
| tree | 70fe178ad777f52404f51b90c06b8d14ef101276 /src/static-ui.cpp | |
| parent | 85bbecbdebf4f096418aea1cd4f9616f9d97e451 (diff) | |
pke: checkpoint: vk renames + first-pass ui
Renamed pipeline and descriptor names to be more
self-descriptive.
UI work is not done, and will not record.
Needs vulkan items created (buffers).
Diffstat (limited to 'src/static-ui.cpp')
| -rw-r--r-- | src/static-ui.cpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/static-ui.cpp b/src/static-ui.cpp new file mode 100644 index 0000000..0c5d124 --- /dev/null +++ b/src/static-ui.cpp @@ -0,0 +1,200 @@ + +#include "static-ui.hpp" + +#include "pk.h" +#include "vendor-glm-include.hpp" +#include "window.hpp" + +#include <cassert> +#include <cstdio> +#include <cstring> + +struct pke_ui_box_instance_buffer_item { + glm::mat4 pos_scale; + glm::vec2 px_scale; + float depth; + float padding[1]; +}; + +struct pke_ui_master { + pk_membucket *bkt; + pke_ui_box **root_boxes; + pke_ui_box_count_T h_root_boxes; + pke_ui_box_count_T r_root_boxes; + pke_ui_graphics_bindings bindings; + bool should_recalc_ui = false; + glm::vec2 px_scale; +} pke_ui_master; + +void pke_ui_init() { + pke_ui_master.bkt = pk_bucket_create("pke ui", PK_DEFAULT_BUCKET_SIZE, false); + pke_ui_master.root_boxes = pk_new<pke_ui_box*>(1, pke_ui_master.bkt); + pke_ui_master.h_root_boxes = 0; + pke_ui_master.r_root_boxes = 1; + pke_ui_master.bindings = {}; +} + +void pke_ui_init_bindings() { + // TODO vulkan +} + +/* UI layout notes +Some restrictions: +- children cannot change the size of a parent, parents must be sized manually + - e.g.: exact font width + - consider writing a method to calculate text +*/ + +void pke_ui_calc_px(pke_ui_box *box) { + assert(box != nullptr); + glm::vec2 size; + glm::vec2 parent_pos_and_offset; + + assert(box->pos_top_left_x >= 0.0); + assert(box->pos_top_left_y >= 0.0); + assert(box->max_width >= 0.0); + assert(box->max_height >= 0.0); + + if (box->internal.parent != nullptr) { + parent_pos_and_offset.x = box->internal.parent->internal.px_corner_x + box->internal.parent->internal.px_offset_x; + parent_pos_and_offset.y = box->internal.parent->internal.px_corner_y + box->internal.parent->internal.px_offset_y; + size.x = box->internal.parent->internal.px_width - box->internal.parent->internal.px_offset_x; + size.y = box->internal.parent->internal.px_height - box->internal.parent->internal.px_offset_y; + // built-in padding + size -= glm::vec2(2); + } else { + parent_pos_and_offset = glm::vec2(0); + size = glm::vec2(Extent.width, Extent.height); + } + + if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC)) { + size.x -= box->pos_top_left_x; + size.y -= box->pos_top_left_y; + box->internal.px_corner_x = 0 + + parent_pos_and_offset.x + + box->pos_top_left_x; + box->internal.px_corner_y = 0 + + parent_pos_and_offset.y + + box->pos_top_left_y; + } else { + assert(box->pos_top_left_x < 1.0); + assert(box->pos_top_left_y < 1.0); + box->internal.px_corner_x = parent_pos_and_offset.x; + box->internal.px_corner_y = parent_pos_and_offset.y; + float px_left = size.x * box->pos_top_left_x; + float px_top = size.y * box->pos_top_left_y; + box->internal.px_corner_x += px_left; + box->internal.px_corner_y += px_top; + size -= px_left; + size -= px_top; + } + size.x = PK_MIN(size.x, box->max_width); + size.y = PK_MIN(size.y, box->max_height); + if (box->internal.parent != nullptr) { + box->internal.parent->internal.px_offset_y += size.y; + } + // built-in padding + box->internal.px_offset_x = 1; + box->internal.px_offset_y = 1; + box->internal.px_width = size.x; + box->internal.px_height = size.y; +} + +void pke_ui_recalc_sizes_recursive(pke_ui_box *box, uint8_t depth = 0) { + uint64_t flags_masked; + + for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { + flags_masked = box->flags & (PKE_UI_BOX_FLAG_POSITION_TYPE_BOTH); + if (flags_masked == 0 || flags_masked == PKE_UI_BOX_FLAG_POSITION_TYPE_BOTH) { + fprintf(stderr, "[%s] ui box invalid flags: position", __FILE__); + return; + } + } + + for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { + pke_ui_calc_px(box->internal.children[i]); + pke_ui_recalc_sizes_recursive(box->internal.children[i], depth + 1); + } +} + +void pke_ui_tick(double delta) { + (void)delta; + if (pke_ui_master.should_recalc_ui == true) { + pke_ui_master.should_recalc_ui = false; + pke_ui_master.px_scale = glm::vec2( + 2.0 / (float)Extent.width, + 2.0 / (float)Extent.height + ); + for (pke_ui_box_count_T i = 0; i < pke_ui_master.h_root_boxes; ++i) { + pke_ui_box *box = pke_ui_master.root_boxes[i]; + pke_ui_calc_px(box); + pke_ui_recalc_sizes_recursive(box, 0); + } + } +} + +void pke_ui_teardown_box_recursive(pke_ui_box *box) { + for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { + pke_ui_teardown_box_recursive(box->internal.children[i]); + } + if (box->internal.children != nullptr) { + pk_delete<pke_ui_box *>(box->internal.children, box->internal.r_children); + } +} + +void pke_ui_teardown() { + for (pke_ui_box_count_T i = 0; i < pke_ui_master.h_root_boxes; ++i) { + pke_ui_teardown_box_recursive(pke_ui_master.root_boxes[i]); + } + pk_delete<pke_ui_box *>(pke_ui_master.root_boxes, pke_ui_master.r_root_boxes); + pk_bucket_destroy(pke_ui_master.bkt); + pke_ui_master.bkt = nullptr; + pke_ui_master.root_boxes = nullptr; + pke_ui_master.h_root_boxes = 0; + pke_ui_master.r_root_boxes = 0; + // TODO vulkan +} + +pke_ui_box *pke_ui_box_new_root() { + if (pke_ui_master.h_root_boxes == pke_ui_master.r_root_boxes) { + pke_ui_box_count_T prev_r_root_boxes = pke_ui_master.r_root_boxes; + pke_ui_master.r_root_boxes *= 1.5; + pke_ui_box **boxes = pk_new<pke_ui_box*>(pke_ui_master.r_root_boxes); + for (pke_ui_box_count_T i = 0; i < pke_ui_master.h_root_boxes; ++i) { + boxes[i] = pke_ui_master.root_boxes[i]; + } + pk_delete<pke_ui_box*>(pke_ui_master.root_boxes, prev_r_root_boxes); + pke_ui_master.root_boxes = boxes; + } + pke_ui_box *box = pk_new<pke_ui_box>(pke_ui_master.bkt); + memset(box, 0, sizeof(pke_ui_box)); + pke_ui_master.root_boxes[pke_ui_master.h_root_boxes] = box; + pke_ui_master.h_root_boxes += 1; + return box; +} + +pke_ui_box *pke_ui_box_new_child(pke_ui_box *parent) { + assert(parent != nullptr); + if (parent->internal.h_children == parent->internal.r_children) { + pke_ui_box_count_T prev_r_children = parent->internal.r_children; + parent->internal.r_children *= PK_MIN(1.5, 2); + pke_ui_box **boxes = pk_new<pke_ui_box*>(parent->internal.r_children); + for (pke_ui_box_count_T i = 0; i < parent->internal.h_children; ++i) { + boxes[i] = parent->internal.children[i]; + } + if (parent->internal.children != nullptr) { + pk_delete<pke_ui_box*>(parent->internal.children, prev_r_children); + } + parent->internal.children = boxes; + } + pke_ui_box *box = pk_new<pke_ui_box>(pke_ui_master.bkt); + memset(box, 0, sizeof(pke_ui_box)); + parent->internal.children[parent->internal.h_children] = box; + parent->internal.h_children += 1; + box->internal.parent = parent; + return box; +} + +pke_ui_graphics_bindings *pke_ui_get_graphics_bindings() { + return &pke_ui_master.bindings; +} |
