From 85a2ba407b1ae285b4080e14f8a18ecf4ec7da2c Mon Sep 17 00:00:00 2001 From: Jonathan Bradley Date: Wed, 12 Mar 2025 17:26:48 -0400 Subject: pke: more testing features + more ui flex work --- Makefile | 180 +++++++++++++++++++++++-------------------- src/static-ui.cpp | 91 ++++++++++++++++------ src/static-ui.hpp | 21 +++-- tests/pke-test-dummy.c | 22 ------ tests/pke-test-dummy.cpp | 23 ++++++ tests/pke-test-dummy.h | 8 ++ tests/pke-test-static-ui.cpp | 106 +++++++++++++++++++++++++ tests/pke-test-static-ui.h | 16 ++++ tests/pke-test-types.h | 11 +++ tests/pke-test.c | 57 -------------- tests/pke-test.cpp | 77 ++++++++++++++++++ 11 files changed, 416 insertions(+), 196 deletions(-) delete mode 100644 tests/pke-test-dummy.c create mode 100644 tests/pke-test-dummy.cpp create mode 100644 tests/pke-test-static-ui.cpp create mode 100644 tests/pke-test-static-ui.h delete mode 100644 tests/pke-test.c create mode 100644 tests/pke-test.cpp diff --git a/Makefile b/Makefile index f7b4542..f730467 100644 --- a/Makefile +++ b/Makefile @@ -22,43 +22,12 @@ FLG_PKE = -Isub/imgui -Isub/stb -Isub/cgltf -Isub/bullet3/src FLG_EDT = $(FLG_PKE) -Isrc -I/home/pikum/build/msdfgen -I/home/pikum/build/msdf-atlas-gen FLG_MPL = $(FLG_PKE) -Isrc FLG_RUN = $(FLG_PKE) -Isrc +FLG_TST = $(FLG_PKE) -Isrc DIR_OBJ=obj DIR_BIN=bin DIR_DBG=dbg -SRC = \ - src/vendor-pkh-include.cpp \ - src/arg-handler.cpp \ - src/camera.cpp \ - src/ecs.cpp \ - src/entities.cpp \ - src/event.cpp \ - src/font.cpp \ - src/game.cpp \ - src/game-settings.cpp \ - src/helpers.cpp \ - src/level-types.cpp \ - src/level.cpp \ - src/math-helpers.cpp \ - src/dynamic-array.cpp \ - src/asset-manager.cpp \ - src/physics.cpp \ - src/player-input.cpp \ - src/plugins.cpp \ - src/project.cpp \ - src/project-settings.cpp \ - src/static-cube.cpp \ - src/static-plane.cpp \ - src/static-ui.cpp \ - src/thread-pool.cpp \ - src/vendor-cgltf-include.cpp \ - src/vendor-stb-image-include.c \ - src/vendor-tinyfiledialogs.c \ - src/window.cpp \ - tests/pke-test.c \ - tests/pke-test-dummy.c \ - DST_SHADERS = \ $(DIR_OBJ)/shaders/vertex.vert.spv \ $(DIR_OBJ)/shaders/present.vert.spv \ @@ -69,20 +38,8 @@ DST_SHADERS = \ $(DIR_OBJ)/shaders/ui-base.vert.spv \ $(DIR_OBJ)/shaders/ui-base.frag.spv \ -SRC_C = $(filter %.c,$(SRC)) -SRC_CXX = $(filter %.cpp,$(SRC)) -OBJ = $(SRC_C:%.c=%.o) -SOBJ = $(SRC_C:%.c=%.so) -CXXOBJ = $(SRC_CXX:%.cpp=%.o) -CXXSOBJ = $(SRC_CXX:%.cpp=%.so) -TMP_OUT_OBJ = $(notdir $(OBJ)) -TMP_OUT_SOBJ = $(notdir $(SOBJ)) -TMP_OUT_CXXOBJ = $(notdir $(CXXOBJ)) -TMP_OUT_CXXSOBJ = $(notdir $(CXXSOBJ)) -OUT_OBJ = $(TMP_OUT_OBJ:%.o=$(DIR_OBJ)/%.o) -OUT_SOBJ = $(TMP_OUT_SOBJ:%.so=$(DIR_OBJ)/%.so) -OUT_CXXOBJ = $(TMP_OUT_CXXOBJ:%.o=$(DIR_OBJ)/%.o) -OUT_CXXSOBJ = $(TMP_OUT_CXXSOBJ:%.so=$(DIR_OBJ)/%.so) +MAINS_OBJ = obj/editor-main.o obj/pke-runtime.o obj/test-pke.o +MAINS_SOBJ = $(MAINS_OBJ:%.o=%.so) .PHONY: default default: options $(DIR_BIN)/pke-editor $(DIR_BIN)/libpke-example.a $(DIR_BIN)/pke-runtime ; @@ -110,20 +67,22 @@ config.h: %.h: ; -$(SRC_C): config.h config.mk -$(SRC_CXX): config.h config.mk +%.hpp: ; + +$(DIR_OBJ)/%.o : config.h config.mk +$(DIR_OBJ)/%.so : config.h config.mk -$(DIR_OBJ)/%.o: sub/imgui/%.cpp +$(DIR_OBJ)/%.o : sub/imgui/%.cpp $(cxx-bin-command) -Isub/imgui -$(DIR_OBJ)/%.so: sub/imgui/%.cpp +$(DIR_OBJ)/%.so : sub/imgui/%.cpp $(cxx-dbg-command) -Isub/imgui -$(DIR_OBJ)/%.o: sub/imgui/backends/%.cpp +$(DIR_OBJ)/%.o : sub/imgui/backends/%.cpp $(cxx-bin-command) -Isub/imgui -$(DIR_OBJ)/%.so: sub/imgui/backends/%.cpp +$(DIR_OBJ)/%.so : sub/imgui/backends/%.cpp $(cxx-dbg-command) -Isub/imgui -$(DIR_OBJ)/%.o: sub/imgui/misc/cpp/%.cpp +$(DIR_OBJ)/%.o : sub/imgui/misc/cpp/%.cpp $(cxx-bin-command) -Isub/imgui -$(DIR_OBJ)/%.so: sub/imgui/misc/cpp/%.cpp +$(DIR_OBJ)/%.so : sub/imgui/misc/cpp/%.cpp $(cxx-dbg-command) -Isub/imgui $(DIR_OBJ)/shaders/%.vert.spv: assets/shaders/%.vert @@ -131,39 +90,39 @@ $(DIR_OBJ)/shaders/%.vert.spv: assets/shaders/%.vert $(DIR_OBJ)/shaders/%.frag.spv: assets/shaders/%.frag $(GLSLC) $^ -o $@ -$(DIR_OBJ)/%.o : src/%.c +$(DIR_OBJ)/%.o : src/%.c $(cc-bin-command) $(FLG_PKE) $(DIR_OBJ)/%.so : src/%.c $(cc-dbg-command) $(FLG_PKE) -$(DIR_OBJ)/%.o : src/vendor/tinyfiledialogs/%.c +$(DIR_OBJ)/%.o : src/vendor/tinyfiledialogs/%.c $(cc-bin-command) $(FLG_PKE) $(DIR_OBJ)/%.so : src/vendor/tinyfiledialogs/%.c $(cc-dbg-command) $(FLG_PKE) +$(DIR_OBJ)/%.o : tests/%.c + $(cc-bin-command) $(FLG_TST) +$(DIR_OBJ)/%.so : tests/%.c + $(cc-dbg-command) $(FLG_TST) -$(DIR_OBJ)/%.o : src/%.cpp +$(DIR_OBJ)/%.o : src/%.cpp $(cxx-bin-command) $(FLG_PKE) $(DIR_OBJ)/%.so : src/%.cpp $(cxx-dbg-command) $(FLG_PKE) -$(DIR_OBJ)/%.o : tests/%.c - $(cc-bin-command) $(FLG_PKE) -$(DIR_OBJ)/%.so : tests/%.c - $(cc-dbg-command) $(FLG_PKE) -$(DIR_OBJ)/%.o : tests/%.cpp - $(cxx-bin-command) $(FLG_PKE) -$(DIR_OBJ)/%.so : tests/%.cpp - $(cxx-dbg-command) $(FLG_PKE) -$(DIR_OBJ)/%.o : editor/%.cpp +$(DIR_OBJ)/%.o : editor/%.cpp $(cxx-bin-command) $(FLG_EDT) $(DIR_OBJ)/%.so : editor/%.cpp $(cxx-dbg-command) $(FLG_EDT) -$(DIR_OBJ)/%.o : example/%.cpp +$(DIR_OBJ)/%.o : example/%.cpp $(cxx-bin-command) $(FLG_MPL) $(DIR_OBJ)/%.so : example/%.cpp $(cxx-dbg-command) $(FLG_MPL) -$(DIR_OBJ)/%.o : runtime/%.cpp +$(DIR_OBJ)/%.o : runtime/%.cpp $(cxx-bin-command) $(FLG_RUN) $(DIR_OBJ)/%.so : runtime/%.cpp $(cxx-dbg-command) $(FLG_RUN) +$(DIR_OBJ)/%.o : tests/%.cpp + $(cxx-bin-command) $(FLG_TST) +$(DIR_OBJ)/%.so : tests/%.cpp + $(cxx-dbg-command) $(FLG_TST) $(DIR_BIN)/libImgui.a: $(DIR_OBJ)/imgui.o $(DIR_BIN)/libImgui.a: $(DIR_OBJ)/imgui_demo.o @@ -204,13 +163,67 @@ $(DIR_DBG)/libBullet3.a: ranlib $@ $(DIR_BIN)/libpke.a: $(DST_SHADERS) -$(DIR_BIN)/libpke.a: $(OUT_OBJ) $(OUT_CXXOBJ) +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/arg-handler.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/asset-manager.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/camera.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/dynamic-array.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/ecs.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/entities.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/event.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/font.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/game-settings.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/game.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/helpers.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/level-types.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/level.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/math-helpers.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/physics.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/player-input.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/plugins.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/project-settings.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/project.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-cube.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-plane.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-ui.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/thread-pool.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/vendor-cgltf-include.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/vendor-pkh-include.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/vendor-stb-image-include.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/vendor-tinyfiledialogs.o +$(DIR_BIN)/libpke.a: $(DIR_OBJ)/window.o $(DIR_BIN)/libpke.a: ar rc $@ $(filter %.o,$^) ranlib $@ $(DIR_DBG)/libpke.a: $(DST_SHADERS) -$(DIR_DBG)/libpke.a: $(OUT_SOBJ) $(OUT_CXXSOBJ) +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/arg-handler.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/asset-manager.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/camera.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/dynamic-array.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/ecs.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/entities.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/event.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/font.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/game-settings.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/game.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/helpers.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/level-types.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/level.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/math-helpers.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/physics.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/player-input.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/plugins.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/project-settings.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/project.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-cube.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-plane.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-ui.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/thread-pool.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/vendor-cgltf-include.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/vendor-pkh-include.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/vendor-stb-image-include.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/vendor-tinyfiledialogs.so +$(DIR_DBG)/libpke.a: $(DIR_OBJ)/window.so $(DIR_DBG)/libpke.a: ar rc $@ $(filter %.so,$^) ranlib $@ @@ -224,12 +237,12 @@ $(DIR_DBG)/libpke-example.a: $(DIR_OBJ)/example.so ranlib $@ $(DIR_BIN)/libpke-test.a: $(DIR_OBJ)/pke-test-dummy.o - ar rc $@ $(filter %.o,$^) - ranlib $@ +$(DIR_BIN)/libpke-test.a: $(DIR_OBJ)/pke-test-static-ui.o + ar rcs $@ $(filter %.o,$^) $(DIR_DBG)/libpke-test.a: $(DIR_OBJ)/pke-test-dummy.so - ar rc $@ $(filter %.so,$^) - ranlib $@ +$(DIR_DBG)/libpke-test.a: $(DIR_OBJ)/pke-test-static-ui.so + ar rcs $@ $(filter %.so,$^) $(DIR_BIN)/pke-editor: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a $(DIR_BIN)/pke-editor: $(DIR_OBJ)/editor-main.o $(DIR_OBJ)/editor.o @@ -250,22 +263,21 @@ $(DIR_DBG)/pke-runtime: $(DIR_OBJ)/runtime.so @echo $^ $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ -$(DIR_BIN)/test-pke: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a -$(DIR_DBG)/test-pke: $(DIR_BIN)/libpke-test.a -$(DIR_BIN)/test-pke: $(DIR_OBJ)/pke-test.o -$(DIR_BIN)/test-pke: +$(DIR_BIN)/pke-test: $(DIR_BIN)/libpke-test.a $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a +$(DIR_BIN)/pke-test: $(DIR_OBJ)/pke-test.o @echo $^ - $(CC) -std=c2x -v $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ + $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ -$(DIR_DBG)/test-pke: $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a -$(DIR_DBG)/test-pke: $(DIR_DBG)/libpke-test.a -$(DIR_DBG)/test-pke: $(DIR_OBJ)/pke-test.so +$(DIR_DBG)/pke-test: $(DIR_DBG)/libpke-test.a $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a +$(DIR_DBG)/pke-test: $(DIR_OBJ)/pke-test.so @echo $^ - $(CC) -std=c2x -v $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ + $(CXX) -v -std=c++23 $(INCS) $^ $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@ .PHONY: print print: - @echo $(DST_SHADERS) + @echo $(OUT_OBJ) + @echo $(MAINS_OBJ) + @echo $(MAINS_SOBJ) .PHONY: clean clean: diff --git a/src/static-ui.cpp b/src/static-ui.cpp index 01af0db..fff8ecc 100644 --- a/src/static-ui.cpp +++ b/src/static-ui.cpp @@ -83,14 +83,19 @@ Some restrictions: - this means that tables or similar need to consist of rows of columns */ -void pke_ui_calc_px(pke_ui_box *box, DynArray &buffer) { +struct pke_ui_flex_params { + float px_per_unit; + float unit_total; +}; + +void pke_ui_calc_px(DynArray &buffer, pke_ui_flex_params *flex_params, pke_ui_box *box) { assert(box != nullptr); - static const float built_in_offset = 2.0; glm::vec2 px_size; + glm::vec2 px_min_size; + glm::vec2 px_max_size; glm::vec2 parent_size_padded; glm::vec2 parent_pos_and_offset; - assert(PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_ALL)); assert(box->pos_top_left_x >= 0.0); assert(box->pos_top_left_y >= 0.0); assert(box->max_width >= 0.0); @@ -114,7 +119,20 @@ void pke_ui_calc_px(pke_ui_box *box, DynArray & px_size = glm::vec2(Extent.width, Extent.height); } + px_min_size.x = box->min_width; + px_min_size.y = box->min_height; + px_max_size.x = box->max_width; + px_max_size.y = box->max_height; + 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; + if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX)) { + assert(flex_params != nullptr); + assert(box->internal.parent != nullptr); // TODO - think through how to organize this. // It's almost like the parent needs to set the widths/heights of the children // In every other method, the child determines its size, @@ -122,19 +140,14 @@ void pke_ui_calc_px(pke_ui_box *box, DynArray & // Could pass a struct around with all the needed details: // - width or height per weight unit, current used weight or current offset // Parent should assert that all or none of the children are position type flex? - px_size.x = PK_CLAMP(parent_size_padded.x, box->min_width, box->max_width); - px_size.y = PK_CLAMP(parent_size_padded.y, box->min_height, box->max_height); + if (box->internal.parent->flex_direction == 0) { + px_size.x = flex_params->px_per_unit * box->flex_weight; + } else { + px_size.y = flex_params->px_per_unit * box->flex_weight; + } } else if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC)) { px_size.x -= box->pos_top_left_x; px_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; - px_size.x = PK_CLAMP(parent_size_padded.x, box->min_width, box->max_width); - px_size.y = PK_CLAMP(parent_size_padded.y, box->min_height, box->max_height); } else { assert(box->pos_top_left_x < 1.0); assert(box->pos_top_left_y < 1.0); @@ -144,33 +157,43 @@ void pke_ui_calc_px(pke_ui_box *box, DynArray & float px_top = px_size.y * box->pos_top_left_y; box->internal.px_corner_x += px_left; box->internal.px_corner_y += px_top; - px_size -= px_left; - px_size -= px_top; - px_size.x = PK_CLAMP(parent_size_padded.x, box->min_width * parent_size_padded.x, box->max_width * parent_size_padded.x); - px_size.y = PK_CLAMP(parent_size_padded.y, box->min_height * parent_size_padded.y, box->max_height * parent_size_padded.y); + px_size.x -= px_left; + px_size.y -= px_top; + px_min_size.x = box->min_width * parent_size_padded.x; + px_min_size.y = box->min_height * parent_size_padded.y; + px_max_size.x = box->max_width * parent_size_padded.x; + px_max_size.y = box->max_height * parent_size_padded.y; } + + px_size = glm::clamp(px_size, px_min_size, px_max_size); + // built-in padding box->internal.px_offset_x = built_in_offset; box->internal.px_offset_y = built_in_offset; if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_CENTER_HORIZONTAL)) { if (parent_size_padded.x > px_size.x) { - box->internal.px_offset_x += (parent_size_padded.x - px_size.x) / 2.0; + box->internal.px_corner_x += (parent_size_padded.x - px_size.x) / 2.0; } } if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_CENTER_VERTICAL)) { if (parent_size_padded.y > px_size.y) { - box->internal.px_offset_y += (parent_size_padded.y - px_size.y) / 2.0; + box->internal.px_corner_y += (parent_size_padded.y - px_size.y) / 2.0; } } box->internal.px_width = px_size.x; box->internal.px_height = px_size.y; if (box->internal.parent != nullptr) { + box->internal.parent->internal.px_offset_x += px_size.x; box->internal.parent->internal.px_offset_y += px_size.y; } + if (PK_HAS_FLAG(box->flags, PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE)) { + return; + } + // update buffer glm::vec3 scale = glm::vec3(box->internal.px_width / (float)Extent.width, box->internal.px_height / (float)Extent.height, 1.0); glm::vec3 translate = glm::vec3(1); @@ -200,17 +223,35 @@ void pke_ui_calc_px(pke_ui_box *box, DynArray & void pke_ui_recalc_sizes_recursive(DynArray &arr, pke_ui_box *box, uint8_t depth = 0) { uint64_t flags_masked; + uint8_t flex_count = 0; + pke_ui_flex_params flex_params{}; + + flags_masked = box->flags & (PKE_UI_BOX_FLAG_POSITION_TYPE_ALL); + if (flags_masked == 0b000 || flags_masked == 0b011 || flags_masked == 0b101 || flags_masked == 0b110 || flags_masked == 0b111) { + fprintf(stderr, "[%s] ui box invalid flags: position type", __FILE__); + return; + } for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { - flags_masked = box->flags & (PKE_UI_BOX_FLAG_POSITION_TYPE_ALL); - if (flags_masked == 0 || flags_masked == 3 || flags_masked == 5 || flags_masked == 6 || flags_masked == 7) { - fprintf(stderr, "[%s] ui box invalid flags: position", __FILE__); - return; + if (PK_HAS_FLAG(box->internal.children[i]->flags, PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX)) { + flex_count += 1; + flex_params.unit_total += box->internal.children[i]->flex_weight; } } + if (flex_count != 0 && flex_count != box->internal.h_children) { + fprintf(stderr, "[%s] ui box invalid flags: if one child is type FLEX, then all children must be type FLEX", __FILE__); + return; + } + if (flex_count != 0) { + flex_params.px_per_unit = + box->flex_direction == 0 + ? box->internal.px_width / flex_params.unit_total + : box->internal.px_height / flex_params.unit_total; + } + for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) { - pke_ui_calc_px(box->internal.children[i], arr); + pke_ui_calc_px(arr, &flex_params, box->internal.children[i]); pke_ui_recalc_sizes_recursive(arr, box->internal.children[i], depth + 1); } } @@ -316,7 +357,7 @@ void pke_ui_tick(double delta) { ); 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, arr); + pke_ui_calc_px(arr, nullptr, box); pke_ui_recalc_sizes_recursive(arr, box, 0); } pke_ui_update_instance_buffer(arr); diff --git a/src/static-ui.hpp b/src/static-ui.hpp index 0cc7aa2..a9b751b 100644 --- a/src/static-ui.hpp +++ b/src/static-ui.hpp @@ -4,6 +4,8 @@ #include "components-vk.hpp" #include +#define built_in_offset 2.0 + struct MSDFGlyphSettings { float width; float height; @@ -14,22 +16,18 @@ struct MSDFGlyphSettings { enum PKE_UI_BOX_FLAGS : uint64_t { PKE_UI_BOX_FLAG_NONE = 0, - // position type [0-1] + // position type [0-4] // exact screen coordinates PKE_UI_BOX_FLAG_POSITION_TYPE_FLEX = (1 << 0), PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC = (1 << 1), PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC = (1 << 2), PKE_UI_BOX_FLAG_POSITION_TYPE_ALL = (1 << 0) | (1 << 1) | (1 << 2), - /* - // grow [2-3] - PKE_UI_BOX_FLAG_GROW_HORIZONTAL = (1 << 3), - PKE_UI_BOX_FLAG_GROW_VERTICAL = (1 << 4), - PKE_UI_BOX_FLAG_GROW_BOTH = (1 << 3) | (1 << 4), - */ - // center [4-5] + // center [5-6] PKE_UI_BOX_FLAG_CENTER_HORIZONTAL = (1 << 5), PKE_UI_BOX_FLAG_CENTER_VERTICAL = (1 << 6), PKE_UI_BOX_FLAG_CENTER_BOTH = (1 << 5) | (1 << 6), + // visibility [7-9] + PKE_UI_BOX_FLAG_VISIBILITY_INVISIBLE = (1 << 7), }; typedef uint16_t pke_ui_box_count_T; @@ -41,6 +39,8 @@ struct pke_ui_box { float pos_top_left_x, pos_top_left_y; float min_width, min_height; float max_width, max_height; + float flex_weight; + uint8_t flex_direction; uint8_t layer; struct pke_ui_box_internals { float px_corner_x, px_corner_y; @@ -73,6 +73,11 @@ void pke_ui_teardown(); pke_ui_box *pke_ui_box_new_root(); pke_ui_box *pke_ui_box_new_child(pke_ui_box *parent); +#ifdef PKE_TEST_EXPOSE +void pke_ui_calc_px(DynArray &buffer, pke_ui_flex_params *flex_params, pke_ui_box *box); +void pke_ui_recalc_sizes_recursive(DynArray &arr, pke_ui_box *box, uint8_t depth = 0); +#endif + pke_ui_graphics_bindings *pke_ui_get_graphics_bindings(); #endif /* PKE_STATIC_UI_HPP */ diff --git a/tests/pke-test-dummy.c b/tests/pke-test-dummy.c deleted file mode 100644 index ea92c34..0000000 --- a/tests/pke-test-dummy.c +++ /dev/null @@ -1,22 +0,0 @@ - -#include "./pke-test-dummy.h" - -int pke_test_dummy_001() { - return 0; -} - -struct pke_test_group *pke_test_dummy_get_group() { - static struct pke_test tests[1] = { - { - .title = "test 001", - .func = pke_test_dummy_001, - .expected_result = 0, - } - }; - static struct pke_test_group group = {0}; - group.title = "dummy test"; - group.n_tests = 1; - group.tests = &tests[0]; - - return &group; -} diff --git a/tests/pke-test-dummy.cpp b/tests/pke-test-dummy.cpp new file mode 100644 index 0000000..a7e2ddc --- /dev/null +++ b/tests/pke-test-dummy.cpp @@ -0,0 +1,23 @@ + +#include "./pke-test-dummy.h" + +int pke_test_dummy_001() { + return 0; +} + +struct pke_test_group *pke_test_dummy_get_group() { + static const uint64_t test_count = 1; + static struct pke_test tests[test_count] = { + { + .title = "test 001", + .func = pke_test_dummy_001, + .expected_result = 0, + } + }; + static struct pke_test_group group = {}; + group.title = "dummy test"; + group.n_tests = test_count; + group.tests = &tests[0]; + + return &group; +} diff --git a/tests/pke-test-dummy.h b/tests/pke-test-dummy.h index b69609e..6abf8b7 100644 --- a/tests/pke-test-dummy.h +++ b/tests/pke-test-dummy.h @@ -3,6 +3,14 @@ #include "pke-test-types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct pke_test_group *pke_test_dummy_get_group(); +#ifdef __cplusplus +} +#endif + #endif /* PKE_PKE_TEST_DUMMY_H */ diff --git a/tests/pke-test-static-ui.cpp b/tests/pke-test-static-ui.cpp new file mode 100644 index 0000000..6e6fb4b --- /dev/null +++ b/tests/pke-test-static-ui.cpp @@ -0,0 +1,106 @@ + +#include "./pke-test-static-ui.h" + +#include "window.hpp" +#include "dynamic-array.hpp" +#include "vendor-glm-include.hpp" +struct pke_ui_box_instance_buffer_item { + glm::mat4 pos_scale; + glm::vec2 px_scale; + float depth; + float padding[1]; +}; +struct pke_ui_flex_params { + float px_per_unit; + float unit_total; +}; +#define PKE_TEST_EXPOSE +#include "static-ui.hpp" + +void pke_test_static_ui_setup() { + Extent.width = 1920; + Extent.height = 1080; + pke_ui_init(); +} + +void pke_test_static_ui_teardown() { + pke_ui_teardown(); +} + +// test static +int pke_test_static_ui_000() { + DynArray arr{}; + float calculated_offset; + uint8_t err_index = 0; + + pke_ui_box *ui_box = pke_ui_box_new_root(); + ui_box->flags = PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; + ui_box->pos_top_left_x = 10; + ui_box->pos_top_left_y = 10; + ui_box->max_width = 500; + ui_box->max_height = 500; + + pke_ui_box *c_ui_box = pke_ui_box_new_child(ui_box); + c_ui_box->flags = PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC; + c_ui_box->pos_top_left_x = 10; + c_ui_box->pos_top_left_y = 10; + c_ui_box->max_width = 100; + c_ui_box->max_height = 100; + + calculated_offset = ui_box->pos_top_left_x + c_ui_box->pos_top_left_x + built_in_offset; + + pke_ui_calc_px(arr, nullptr, ui_box); + pke_ui_recalc_sizes_recursive(arr, ui_box, 0); + + PKE_TEST_ASSERT(ui_box->internal.parent == nullptr, err_index); + PKE_TEST_ASSERT(c_ui_box->internal.parent != nullptr, err_index); + + PKE_TEST_ASSERT(ui_box->internal.px_corner_x == 10, err_index); + PKE_TEST_ASSERT(ui_box->internal.px_corner_y == 10, err_index); + PKE_TEST_ASSERT(c_ui_box->internal.px_corner_x == calculated_offset, err_index); + PKE_TEST_ASSERT(c_ui_box->internal.px_corner_y == calculated_offset, err_index); + + return 0; +} + +// test dynamic +int pke_test_static_ui_100() { + return 0; +} + + +// test flex +int pke_test_static_ui_200() { + return 0; +} + +pke_test_group *pke_test_static_ui_get_group() { + static const uint64_t test_count = 3; + static struct pke_test tests[test_count] = { + { + .title = "test 000", + .func = pke_test_static_ui_000, + .expected_result = 0, + }, + { + .title = "test 100", + .func = pke_test_static_ui_100, + .expected_result = 0, + }, + { + .title = "test 200", + .func = pke_test_static_ui_200, + .expected_result = 0, + }, + }; + static struct pke_test_group group = {}; + group.title = "static_ui"; + group.group_setup = NULL; + group.group_teardown = NULL; + group.test_setup = pke_test_static_ui_setup; + group.test_teardown = pke_test_static_ui_teardown; + group.tests = &tests[0]; + group.n_tests = test_count; + + return &group; +} diff --git a/tests/pke-test-static-ui.h b/tests/pke-test-static-ui.h new file mode 100644 index 0000000..673adf8 --- /dev/null +++ b/tests/pke-test-static-ui.h @@ -0,0 +1,16 @@ +#ifndef PKE_PKE_TEST_STATIC_UI_H +#define PKE_PKE_TEST_STATIC_UI_H + +#include "pke-test-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pke_test_group *pke_test_static_ui_get_group(); + +#ifdef __cplusplus +} +#endif + +#endif /* PKE_PKE_TEST_STATIC_UI_H */ diff --git a/tests/pke-test-types.h b/tests/pke-test-types.h index 5278eae..5a9ee24 100644 --- a/tests/pke-test-types.h +++ b/tests/pke-test-types.h @@ -15,6 +15,11 @@ typedef int (pke_test_func)(); struct pke_test_group; typedef struct pke_test_group *(pke_test_get_group)(); +typedef void (pke_test_group_setup()); +typedef void (pke_test_group_teardown()); +typedef void (pke_test_setup()); +typedef void (pke_test_teardown()); + struct pke_test { const char *title; pke_test_func *func; @@ -23,8 +28,14 @@ struct pke_test { struct pke_test_group { const char *title; + pke_test_group_setup *group_setup; + pke_test_group_teardown *group_teardown; + pke_test_setup *test_setup; + pke_test_teardown *test_teardown; struct pke_test *tests; uint32_t n_tests; }; +#define PKE_TEST_ASSERT(condition, index) if (!(condition)) { return ++index; } else { ++index; } + #endif /* PKE_PKE_TEST_TYPES_H */ diff --git a/tests/pke-test.c b/tests/pke-test.c deleted file mode 100644 index 4f88dbf..0000000 --- a/tests/pke-test.c +++ /dev/null @@ -1,57 +0,0 @@ - -#include "./pke-test-types.h" - -#include "./pke-test-dummy.h" - -#include "unistd.h" -#include - -#define CLR_WHITE "\033[0m" -#define CLR_GREEN "\033[92m" -#define CLR_RED "\033[31m" - -// https://stackoverflow.com/questions/64190847/how-to-catch-a-call-to-exit-for-unit-testing -struct pke_test_long_jump lj; -void exit(int code) { - if (lj.expected_exit) { - lj.caught = 1; - longjmp(lj.jump_env, 1); - } - _exit(code); -} - -int main(int argc, char *argv[]) -{ - (void)argc; - (void)argv; - int i = 0; - uint32_t k, pass_count; - - pke_test_get_group *group_fns[] = { - pke_test_dummy_get_group, - NULL, - }; - - pke_test_get_group *fn = group_fns[i]; - while (fn != NULL) { - pass_count = 0; - struct pke_test_group *group = (fn)(); - fprintf(stdout, "[pke-test]:[%s] Begin.\n", group->title); - for (k = 0; k < group->n_tests; ++k) { - fprintf(stdout, "[pke-test]:[%s]:[%s] Begin.\n", group->title, group->tests[k].title); - lj.expected_exit = 0; - lj.caught = 0; - if (group->tests[k].expected_result == (group->tests[k].func)()){ - pass_count += 1; - fprintf(stdout, "[pke-test]:[%s]:[%s] %sPassed.%s\n", group->title, group->tests[k].title, CLR_GREEN, CLR_WHITE); - } else { - fprintf(stdout, "[pke-test]:[%s]:[%s] %sFailed.%s\n", group->title, group->tests[k].title, CLR_RED, CLR_WHITE); - } - } - fprintf(stdout, "[pke-test]:[%s] End. ( %s%03d%s / %03d ) Tests Completed.\n\n", group->title, pass_count == group->n_tests ? CLR_GREEN : CLR_RED, pass_count, CLR_WHITE, group->n_tests); - i += 1; - fn = group_fns[i]; - } - - return 0; -} diff --git a/tests/pke-test.cpp b/tests/pke-test.cpp new file mode 100644 index 0000000..61b6fb8 --- /dev/null +++ b/tests/pke-test.cpp @@ -0,0 +1,77 @@ + +#include "./pke-test-types.h" + +#include "./pke-test-dummy.h" +#include "./pke-test-static-ui.h" + +#include "pk.h" +#include "unistd.h" +#include + +#define CLR_WHITE "\033[0m" +#define CLR_GREEN "\033[92m" +#define CLR_RED "\033[31m" + +// https://stackoverflow.com/questions/64190847/how-to-catch-a-call-to-exit-for-unit-testing +struct pke_test_long_jump lj; +void exit(int code) { + if (lj.expected_exit) { + lj.caught = 1; + longjmp(lj.jump_env, 1); + } + _exit(code); +} + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + int i = 0; + int result; + uint32_t k, pass_count; + double nanoseconds; + double group_nanoseconds; + pk_tmr func_tmr; + + pke_test_get_group *group_fns[] = { + pke_test_dummy_get_group, + pke_test_static_ui_get_group, + NULL, + }; + + fprintf(stdout, "\r\n"); + pke_test_get_group *fn = group_fns[i]; + while (fn != NULL) { + pass_count = 0; + group_nanoseconds = 0; + struct pke_test_group *group = (fn)(); + fprintf(stdout, "[pke-test]:[%s] Begin.\n", group->title); + if (group->group_setup != NULL) (group->group_setup)(); + for (k = 0; k < group->n_tests; ++k) { + fprintf(stdout, "[pke-test]:[%s]:[%s] Begin.\n", group->title, group->tests[k].title); + if (group->test_setup != NULL) (group->test_setup)(); + lj.expected_exit = 0; + lj.caught = 0; + pk_tmr_start(func_tmr); + result = (group->tests[k].func)(); + pk_tmr_stop(func_tmr); + nanoseconds = pk_tmr_duration_double(func_tmr); + group_nanoseconds += nanoseconds; + if (result == group->tests[k].expected_result){ + pass_count += 1; + fprintf(stdout, "[pke-test]:[%s]:[%s] %sPassed.%s\n", group->title, group->tests[k].title, CLR_GREEN, CLR_WHITE); + fprintf(stdout, "[pke-test]:[%s]:[%s] Elapsed ms: '%f'.\n", group->title, group->tests[k].title, nanoseconds); + } else { + fprintf(stdout, "[pke-test]:[%s]:[%s] %sFailed.%s Expected: '%i' Got: '%i'.\n", group->title, group->tests[k].title, CLR_RED, CLR_WHITE, group->tests[k].expected_result, result); + } + if (group->test_teardown != NULL) (group->test_teardown)(); + } + if (group->group_teardown != NULL) (group->group_teardown)(); + fprintf(stdout, "[pke-test]:[%s] End. ( %s%03d%s / %03d ) Tests Completed.\n", group->title, pass_count == group->n_tests ? CLR_GREEN : CLR_RED, pass_count, CLR_WHITE, group->n_tests); + fprintf(stdout, "[pke-test]:[%s] End. Elapsed ms: '%f'.\n\n", group->title, group_nanoseconds); + i += 1; + fn = group_fns[i]; + } + + return 0; +} -- cgit v1.2.3