#ifndef PKE_STATIC_UI_HPP #define PKE_STATIC_UI_HPP #include "components-vk.hpp" #include "font.hpp" #include "pk.h" #include "vendor-glm-include.hpp" #include #define built_in_offset 2.0 struct MSDFGlyphSettings { float width; float height; float scale; float translate_em; float range_em; }; TypeSafeInt_H(PKE_UI_BOX_TYPE, uint8_t, 0xFF); TypeSafeInt_H(PKE_UI_BOX_FLAG, uint64_t, 0xFFFFFFFFFFFFFFFF); TypeSafeInt_H(PKE_UI_BOX_STATE_FLAG, uint64_t, 0xFFFFFFFFFFFFFFFF); // layouts const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_STANDARD = PKE_UI_BOX_TYPE(0); // TODO columns, rows, tabs, etc // special (content) const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_TEXT = PKE_UI_BOX_TYPE(50); // TODO image, render target, etc // inputs // TODO const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_BUTTON_TEXT = PKE_UI_BOX_TYPE(100); // TODO const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_BUTTON_IMAGE = PKE_UI_BOX_TYPE(101); const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_INPUT_TEXT = PKE_UI_BOX_TYPE(105); // TODO const PKE_UI_BOX_TYPE PKE_UI_BOX_TYPE_INPUT_MULTILINE_TEXT = PKE_UI_BOX_TYPE(106); // TODO scalar, float, slider, etc const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_NONE = PKE_UI_BOX_FLAG(0); // [00-04] position type // exact screen coordinates 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 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-14] visibility const 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_DISABLED = PKE_UI_BOX_FLAG((1 << 8)); const PKE_UI_BOX_FLAG PKE_UI_BOX_FLAG_VISIBILITY_PIXEL_PERFECT = PKE_UI_BOX_FLAG((1 << 9)); // [14-??] // PKE_UI_BOX_STATE_FLAG represent the current state THIS TICK. // So, e.g. // Did the mouse enter this tick. // Is the mouse hovered. const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_NONE = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(0) << 0)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_MOUSE_ENTERED = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 0)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_MOUSE_EXITED = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 1)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_MOUSE_HOVER = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 2)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_PRIMARY_PRESS = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 3)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_PRIMARY_RELEASE = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 4)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_PRIMARY_PRESSED = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 5)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_SECONDARY_PRESS = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 6)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_SECONDARY_RELEASE = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 7)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_SECONDARY_PRESSED = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 8)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_MIDDLE_PRESS = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 9)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_MIDDLE_RELEASE = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 10)); const PKE_UI_BOX_STATE_FLAG PKE_UI_BOX_STATE_FLAG_ON_BTN_MIDDLE_PRESSED = PKE_UI_BOX_STATE_FLAG((PKE_UI_BOX_STATE_FLAG_T(1) << 11)); typedef uint16_t pke_ui_box_count_T; struct pke_ui_box; struct pke_ui_box : public Entity_Base { PKE_UI_BOX_FLAG flags; glm::vec2 pos_top_left; glm::vec2 min_size; glm::vec2 max_size; float flex_weight; float flex_padding; PKE_UI_BOX_TYPE type; uint8_t flex_direction; uint8_t layer; glm::vec4 color_border = glm::vec4(1.0, 0.0, 0.0, 1.0); glm::vec4 color_background = glm::vec4(0.2, 0.3, 0.2, 0.5); union pke_ui_box_type_data *type_data; PKE_UI_BOX_STATE_FLAG state_flags; PKE_UI_BOX_STATE_FLAG state_flags_mem; struct pke_ui_box_internals { // the exact px to translate (shader) glm::vec2 px_corner; // the exact px for scaling (shader) glm::vec2 px_size; // internal padding + running offset for adding children // glm::vec4 px_padding; float px_padding_l, px_padding_b, px_padding_r, px_padding_t; pke_ui_box *parent; pke_ui_box **children; pke_ui_box_count_T h_children; pke_ui_box_count_T r_children; uint8_t depth; } internal; }; // separate these if they become silly union pke_ui_box_type_data { struct pke_ui_box_type_data_text { FontTypeRender font_type_render; } text; struct pke_ui_box_type_data_button_text { FontTypeRender font_type_render; PkeEventHandle pke_event_handle; pk_ev_id_T ev_id; } button_text; struct pke_ui_box_type_data_button_image { AssetKey img_key_default; AssetKey img_key_hovered; AssetKey img_key_pressed; pk_bkt_arr_handle gr_binds_bkt_arr_handle; PkeEventHandle pke_event_handle; pk_ev_id_T ev_id; } button_image; }; struct pke_ui_graphics_bindings { VkDeviceMemory deviceMemoryVert = VK_NULL_HANDLE; VkDeviceMemory deviceMemoryInst = VK_NULL_HANDLE; BufferBindingDetails bd_vertex; BufferBindingDetails bd_uv; BufferBindingDetails bd_index; BufferBindingDetails bd_instance; uint32_t index_count; uint32_t instance_counter; uint32_t instance_buffer_max_count; }; /* minimum amount of data needed to reuse the normal bindings but also bind textures */ struct pke_ui_graphics_bindings_texture { uint32_t instance_offset; uint32_t instance_count; VkDescriptorSet *descriptor_sets; VkDescriptorPool descriptor_pool; VkDeviceMemory image_memory; VkImage image; VkImageView image_view; }; 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); pke_ui_box *pke_ui_box_new_root(const PKE_UI_BOX_TYPE type = PKE_UI_BOX_TYPE_STANDARD, pk_uuid uuid = pk_uuid_zed); pke_ui_box *pke_ui_box_new_child(pke_ui_box *parent, const PKE_UI_BOX_TYPE type = PKE_UI_BOX_TYPE_STANDARD, pk_uuid uuid = pk_uuid_zed); void pke_ui_box_update_textures(pke_ui_box *box); #ifdef PKE_TEST_EXPOSE void pke_ui_calc_px(pk_arr_t &buffer, pk_arr_t> &tmp_txtr_buffer, pke_ui_flex_params *flex_params, pke_ui_box *box, uint8_t child_index); void pke_ui_recalc_sizes_recursive(pk_arr_t &arr, pk_arr_t> &tmp_txtr_buffer, pke_ui_box *box); #endif const pke_ui_graphics_bindings &pke_ui_get_graphics_bindings(); void pke_ui_get_graphics_bindings_texture(pk_arr *arr); #endif /* PKE_STATIC_UI_HPP */