summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-09-16 16:58:02 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-09-16 17:00:08 -0400
commit73c5e170260638cc566cba2689ea570caee39251 (patch)
tree256b36398d33650054a885e572437909f88485cb
parente52ef2e49ae660833370befc34ba79d412cb4604 (diff)
pke: major object lifetime overhaul.
Added pke-test-load-unload to ensure objects are managed as expected.
-rw-r--r--Makefile1
-rw-r--r--config.mk2
-rw-r--r--src/camera.cpp32
-rw-r--r--src/camera.hpp1
-rw-r--r--src/ecs.cpp23
-rw-r--r--src/font.cpp159
-rw-r--r--src/font.hpp20
-rw-r--r--src/game.cpp15
-rw-r--r--src/level.cpp29
-rw-r--r--src/level.hpp1
-rw-r--r--src/physics.cpp24
-rw-r--r--src/project.cpp9
-rw-r--r--src/scene.cpp24
-rw-r--r--src/scene.hpp2
-rw-r--r--src/serialization.cpp10
-rw-r--r--src/static-ui.cpp106
-rw-r--r--src/thread-pool.cpp10
-rw-r--r--src/window.cpp10
-rw-r--r--tests/pke-test-asset-manager.cpp7
-rw-r--r--tests/pke-test-dummy.cpp9
-rw-r--r--tests/pke-test-load-unload.cpp303
-rw-r--r--tests/pke-test-load-unload.h16
-rw-r--r--tests/pke-test-serialization.cpp51
-rw-r--r--tests/pke-test-static-ui.cpp9
-rw-r--r--tests/pke-test.cpp10
25 files changed, 671 insertions, 212 deletions
diff --git a/Makefile b/Makefile
index 88a8a84..3d9f0ce 100644
--- a/Makefile
+++ b/Makefile
@@ -250,6 +250,7 @@ $(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-dummy.$(OBJ_EXT)
$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-audio.$(OBJ_EXT)
$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-static-ui.$(OBJ_EXT)
$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-serialization.$(OBJ_EXT)
+$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-load-unload.$(OBJ_EXT)
$(DIR_OBJ)/libpke-test.$(LIB_EXT): $(DIR_OBJ)/pke-test-asset-manager.$(OBJ_EXT)
ar rcs $@ $(filter %.$(OBJ_EXT),$^)
diff --git a/config.mk b/config.mk
index 4a12e00..a649d02 100644
--- a/config.mk
+++ b/config.mk
@@ -33,6 +33,7 @@ LIBS = -lm `$(PKG_CONFIG) --libs $(USED_LIBS)` -lpthread
# -fsanitize=address \
# -rdynamic is for pkfuncinstr
# -finstrument-functions is for pkfuncinstr
+# -DPKE_AUDIO_IMPL_PIPEWIRE \
SHARED_FLAGS = -D_DEFAULT_SOURCE \
-D_POSIX_C_SOURCE=200809L \
@@ -42,7 +43,6 @@ SHARED_FLAGS = -D_DEFAULT_SOURCE \
-pthread \
-rdynamic \
-finstrument-functions \
- -DPKE_AUDIO_IMPL_PIPEWIRE \
CFLAGS += -Wall -Wextra $(SHARED_FLAGS)
CXXFLAGS += -Wall -Wextra $(SHARED_FLAGS)
diff --git a/src/camera.cpp b/src/camera.cpp
index ca2c11f..07e4253 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -158,20 +158,6 @@ void PkeCamera_SetPrimary(CameraHandle cameraHandle) {
}
}
-void PkeCamera_Destroy(CameraHandle cameraHandle) {
- assert(cameraHandle != CameraHandle_MAX);
- auto *camPtr = &cam_mstr.bktc_cameras[cameraHandle];
- auto &cam = *camPtr;
-
- if (cam.phys.constraint != nullptr && cam.phys.constraint != CAFE_BABE(btTypedConstraint)) {
- // reminder: this is not currently handled by ECS
- BtDynamicsWorld->removeConstraint(cam.phys.constraint);
- pk_delete<btTypedConstraint>(cam.phys.constraint, MemBkt_Bullet);
- }
-
- ECS_MarkForRemoval(camPtr);
-}
-
pk_bkt_arr &PkeCamera_GetPkBktArr() {
return cam_mstr.bktc_cameras;
}
@@ -217,16 +203,30 @@ void PkeCamera_Tick(double delta) {
bool b;
b = pk_bkt_arr_iter_begin(&cam_mstr.bktc_cameras, &iter_cam);
while (b == true) {
+ inst = ECS_GetInstance(iter_cam->phys.instHandle);
if (iter_cam->isMarkedForRemoval == true) {
- pk_bkt_arr_free_handle(&cam_mstr.bktc_cameras, iter_cam->camHandle);
if (ActiveCamera == iter_cam.data) {
ActiveCamera = &NullCamera;
}
+ if (iter_cam->phys.constraint != nullptr && iter_cam->phys.constraint != CAFE_BABE(btTypedConstraint)) {
+ // reminder: this is not currently handled by ECS
+ BtDynamicsWorld->removeConstraint(iter_cam->phys.constraint);
+ pk_delete<btTypedConstraint>(iter_cam->phys.constraint, MemBkt_Bullet);
+ }
+ if (inst != nullptr) {
+ if (inst->bt.rigidBody != nullptr) {
+ BtDynamicsWorld->removeRigidBody(inst->bt.rigidBody);
+ pk_delete<btRigidBody>(inst->bt.rigidBody, MemBkt_Bullet);
+ }
+ if (inst->bt.motionState != nullptr) {
+ pk_delete<btDefaultMotionState>(inst->bt.motionState, MemBkt_Bullet);
+ }
+ }
+ pk_bkt_arr_free_handle(&cam_mstr.bktc_cameras, iter_cam->camHandle);
new (iter_cam.data) PkeCamera{};
b = pk_bkt_arr_iter_increment(&cam_mstr.bktc_cameras, &iter_cam);
continue;
}
- inst = ECS_GetInstance(iter_cam->phys.instHandle);
assert(inst != nullptr);
if (inst->isNeedingUpdated == true) {
iter_cam->stale = iter_cam->stale | PKE_CAMERA_STALE_POSROT;
diff --git a/src/camera.hpp b/src/camera.hpp
index 9486c84..1226c11 100644
--- a/src/camera.hpp
+++ b/src/camera.hpp
@@ -51,7 +51,6 @@ void PkeCamera_TargetInstance(CameraHandle cameraHandle, CompInstance *inst);
void PkeCamera_UntargetInstance(CameraHandle cameraHandle);
pk_bkt_arr &PkeCamera_GetPkBktArr();
void PkeCamera_SetPrimary(CameraHandle handle);
-void PkeCamera_Destroy(CameraHandle handle);
void PkeCamera_Teardown();
void PkeCamera_Tick(double delta);
diff --git a/src/ecs.cpp b/src/ecs.cpp
index dd521ce..b4391dc 100644
--- a/src/ecs.cpp
+++ b/src/ecs.cpp
@@ -15,6 +15,7 @@ typedef pk_bkt_arr_t<Entity_Base *> type_bkt_arr_entities ;
struct ECS {
struct pk_membucket *bkt = nullptr;
+ pk_ev_mgr_id_T ev_mgr_id;
struct ECSBucketContainers {
pk_bkt_arr_t<Entity_Base> generics{};
type_bkt_arr_entities entityPtrs{};
@@ -28,6 +29,15 @@ struct ECS {
* Entities that have been marked for removal by calling ECS_MarkForRemoval
*
* Used to build the other "removal" lists.
+ *
+ * Each ECS module is REQUIRED to manage the lifetimes of its objects.
+ * Each module MUST wait for an entity to be flagged "IsMarkedForRemoval".
+ * Even though the module itself is sometimes the source of reporting the
+ * entity to be cleaned up, it must wait to free resources until marked.
+ * Do note that this means that it can take several ticks for all resources
+ * of a level to get freed.
+ * Ex: box with text; text isn't marked for removal until after box.
+ * (This happens when deserializing, the FontRender doesn't know about its parent")
*/
pk_arr_t<Entity_Base *> entitiesMarkedForRemoval{};
/*
@@ -68,7 +78,7 @@ void ECS_Init() {
pk_arr_reserve(&entitiesMarkedForRemoval, 16);
pk_arr_reserve(&entitiesYetToBeRemoved, 16);
pk_arr_reserve(&EntitiesWithExcessInstances, 16);
- pk_ev_create_mgr();
+ ecs.ev_mgr_id = pk_ev_create_mgr();
}
Entity_Base *ECS_CreateGenericEntity() {
@@ -105,8 +115,8 @@ Entity_Base *ECS_GetEntityByUUID(pk_uuid uuid) {
auto entity_ptr_find_cb = [](void *user_data, const void *arr_user_data, const void *arr_obj_data) {
(void)user_data;
const pk_uuid &uuid = *reinterpret_cast<const pk_uuid*>(arr_user_data);;
- const Entity_Base &ent = **reinterpret_cast<const Entity_Base*const*>(arr_obj_data);
- return (ent.uuid == uuid);
+ const Entity_Base *ent = *reinterpret_cast<const Entity_Base*const*>(arr_obj_data);
+ return (ent->uuid == uuid);
};
EntityHandle handle { pk_bkt_arr_find_first_handle(&ecs.bc.entityPtrs, entity_ptr_find_cb, NULL, &uuid) };
if (handle == EntityHandle_MAX) return nullptr;
@@ -203,8 +213,7 @@ void ECS_Tick_Early(double delta) {
while (b == true) {
Entity_Base *ent = ecs.bc.entityPtrs[iter_comp_ev->entity_handle];
if (ent->isMarkedForRemoval) {
- pk_ev_destroy_mgr(iter_comp_ev->ev_mgr_id);
- pk_bkt_arr_free_handle(&ecs.bc.ev_mgrs, iter_comp_ev->entity_handle);
+ pk_bkt_arr_free_handle(&ecs.bc.ev_mgrs, iter_comp_ev->pke_event_handle);
new (&(*iter_comp_ev)) pke_component_event{};
}
b = pk_bkt_arr_iter_increment(&ecs.bc.ev_mgrs, &iter_comp_ev);
@@ -565,9 +574,8 @@ CompInstance *ECS_GetInstance(InstanceHandle instanceHandle ) {
if (instanceHandle == InstanceHandle_MAX) return nullptr;
assert(pk_bkt_arr_handle_validate(&ecs.bc.instances, instanceHandle) == PK_BKT_ARR_HANDLE_VALIDATION_VALID);
- auto *inst = &ecs.bc.instances[instanceHandle];
- return inst;
+ return &ecs.bc.instances[instanceHandle];
}
void ECS_GetInstances(Entity_Base *entity, pk_arr_t<CompInstance *> &arr) {
@@ -657,6 +665,7 @@ pk_bkt_arr *ECS_GetEvs() {
}
void ECS_Teardown() {
+ pk_ev_destroy_mgr(ecs.ev_mgr_id);
pk_arr_reset(&EntitiesWithExcessInstances);
pk_arr_reset(&entitiesYetToBeRemoved);
pk_arr_reset(&entitiesMarkedForRemoval);
diff --git a/src/font.cpp b/src/font.cpp
index b24ea8f..58d5f50 100644
--- a/src/font.cpp
+++ b/src/font.cpp
@@ -34,9 +34,9 @@ TypeSafeInt_B(FONT_GLYPH_CHAR_FLAG);
TypeSafeInt_B(FONT_RENDER_SURFACE_AREA_TYPE_FLAG);
struct FontTypeData {
- FontType *arr_ft;
+ FontType *arr_ft = nullptr;
+ uint64_t unused_fts = 0xFFFFFFFFFFFFFFFF;
FontTypeIndex n_ft{0};
- FontTypeIndex h_ft{0};
} ftd;
struct FontInstanceBufferItem {
@@ -51,6 +51,8 @@ struct FontInstanceBufferItem {
float padding[3];
};
+void FontType_Unload(FontTypeIndex idx);
+
uint32_t utf8_to_unicode(const char* str, uint32_t &out) {
uint32_t i = 0;
out = 0;
@@ -243,10 +245,9 @@ void FontType_Inner_CalcTransforms(const FontType *ft, FontRender *fr, FontInsta
void FontType_Init() {
FontTypeIndex fti;
- ftd.h_ft = FontTypeIndex{0};
- ftd.n_ft = FontTypeIndex{5};
- ftd.arr_ft = pk_new_arr<FontType>(5);
- for (FontTypeIndex_T i = 0; i < 5; ++i) {
+ ftd.n_ft = FontTypeIndex{8};
+ ftd.arr_ft = pk_new_arr<FontType>(8);
+ for (FontTypeIndex_T i = 0; i < 8; ++i) {
FontType *ft = &ftd.arr_ft[i];
ft->glyphs = nullptr;
ft->renders = nullptr;
@@ -276,9 +277,10 @@ void FontType_Init() {
}
void FontType_Teardown() {
- FontTypeIndex i;
- for (i = FontTypeIndex{0}; i < ftd.h_ft; ++i) {
- FontType_Unload(i);
+ int i;
+ for (i = (int)(FontTypeIndex_T)ftd.n_ft-1; i >= 0; --i) {
+ if ((ftd.unused_fts & (1llu << i)) != 0) continue;
+ FontType_Unload(FontTypeIndex{(FontTypeIndex_T)i});
}
if (ftd.arr_ft != nullptr) pk_delete_arr<FontType>(ftd.arr_ft, (FontTypeIndex_T)ftd.n_ft);
}
@@ -294,19 +296,43 @@ void FontType_Tick(double delta) {
size_t index;
FontType *ft;
FontRender *fr;
- for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.h_ft; ++i) {
+ for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.n_ft; ++i) {
+
+ if ((ftd.unused_fts & (1llu << i)) != 0) continue;
+
index = 0;
ft = &ftd.arr_ft[i];
- if (pkeSettings.rt.was_framebuffer_resized == false && ft->gr.should_update_instance_buffer == false) {
+
+ for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->n_render; ++k) {
+ if ((ft->unused_frs & (1llu << k)) != 0) continue;
+ fr = &ft->renders[k];
+ if (fr->isMarkedForRemoval == true) {
+ if (fr->text.reserved > 0) {
+ // 2025-04-16 - JCB
+ // not passing a specific bucket because pk_cstr doesn't store it.
+ // FontType_AddStringRender requires a `pk_cstr &&`, so we are the proper owner.
+ // It's up to us to free it.
+ pk_delete_arr<char>(fr->text.val, fr->text.reserved);
+ }
+ ft->unused_frs |= (1llu << k);
+ new (fr) FontRender{};
+ ft->gr.should_update_instance_buffer = true;
+ continue;
+ }
+ index += fr->n_glyphs;
+ }
+
+ if (ft->isMarkedForRemoval == true) {
+ FontType_Unload(FontTypeIndex{i});
continue;
}
- // TODO specific bucket
- for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) {
- index += ft->renders[k].n_glyphs;
+ if (pkeSettings.rt.was_framebuffer_resized == false && ft->gr.should_update_instance_buffer == false) {
+ continue;
}
if (index == 0) {
+ ft->bindings.instance_counter = index;
continue;
}
ft->gr.should_update_instance_buffer = false;
@@ -314,7 +340,8 @@ void FontType_Tick(double delta) {
fibis = pk_new_arr<FontInstanceBufferItem>(index);
ft->bindings.instance_counter = index;
index = 0;
- for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->h_render; ++k) {
+ for (FontRenderIndex_T k = 0; k < (FontRenderIndex_T)ft->n_render; ++k) {
+ if ((ft->unused_frs & (1llu << k)) != 0) continue;
fr = &ft->renders[k];
FontType_Inner_CalcTransforms(ft, fr, &fibis[index]);
index += fr->n_glyphs;
@@ -525,13 +552,14 @@ void FontType_Deserialize(std::istream &stream) {
}
FontType* FontType_Get(FontTypeIndex idx) {
- assert(idx < ftd.h_ft);
+ assert((ftd.unused_fts & (1llu << FontTypeIndex_T(idx))) == 0);
return &ftd.arr_ft[static_cast<FontTypeIndex_T>(idx)];
}
FontType* FontType_GetByTitle(const pk_cstr title) {
assert(title.val != nullptr);
- for (FontTypeIndex_T i = 0; i < static_cast<FontTypeIndex_T>(ftd.h_ft); ++i) {
+ for (FontTypeIndex_T i = 0; i < (FontTypeIndex_T)ftd.n_ft; ++i) {
+ if ((ftd.unused_fts & (1llu << i)) != 0) continue;
if (ftd.arr_ft[i].title.val == title.val)
return &ftd.arr_ft[i];
if (strcmp(ftd.arr_ft[i].title.val, title.val) == 0)
@@ -540,28 +568,40 @@ FontType* FontType_GetByTitle(const pk_cstr title) {
return nullptr;
}
-FontType* FontType_GetFonts(FontTypeIndex &count) {
- count = ftd.h_ft;
+FontType* FontType_GetFonts(uint64_t &idx_unused) {
+ idx_unused = ftd.unused_fts;
return ftd.arr_ft;
}
FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeMSDFSettings *msdf_settings, FontTypeSpacing *spacing) {
VkResult vkResult;
- pk_arr arr_vert_mem_reqs;
- memset(&arr_vert_mem_reqs, 0, sizeof(pk_arr));
- arr_vert_mem_reqs.alignment = alignof(VkMemoryRequirements);
- arr_vert_mem_reqs.stride = sizeof(VkMemoryRequirements);
constexpr VkDeviceSize startingGlyphCount = 4;
+ const Asset *fontTexture = nullptr;
+ const Asset *glyphs = nullptr;
+ FontTypeIndex idx{0};
+ FontTypeIndex_T idx_t;
+ FontType *ft;
+ uint16_t u;
+
assert(fontTextureHandle != AssetHandle_MAX);
assert(glyphsHandle != AssetHandle_MAX);
assert(msdf_settings != nullptr);
assert(spacing != nullptr);
- const Asset *fontTexture = AM_Get(fontTextureHandle);
- FontTypeIndex idx = ftd.h_ft;
- ftd.h_ft += FontTypeIndex{1};
- if (ftd.h_ft >= ftd.n_ft) {
- ftd.n_ft += FontTypeIndex{5};
+ for (u = 0; u < (FontTypeIndex_T)ftd.n_ft; ++u) {
+ if ((ftd.unused_fts & (1llu << u)) != 0) {
+ idx_t = u;
+ idx = FontTypeIndex{idx_t};
+ ftd.unused_fts &= ~(1llu << idx_t);
+ break;
+ }
+ }
+
+ if (idx >= ftd.n_ft) {
+ if (idx_t >= PKE_FONT_MAX_FONT_TYPES) {
+ throw "[font.cpp] out of font type slots";
+ }
+ ftd.n_ft = FontTypeIndex{8};
FontType *arr = pk_new_arr<FontType>((FontTypeIndex_T)ftd.n_ft);
if (idx > FontTypeIndex{0}) {
memcpy(arr, ftd.arr_ft, sizeof(FontType) * (FontTypeIndex_T)idx);
@@ -570,18 +610,20 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle
ftd.arr_ft = arr;
}
- FontTypeIndex_T idx_t = (FontTypeIndex_T)idx;
- FontType *ft = &ftd.arr_ft[idx_t];
+ fontTexture = AM_Get(fontTextureHandle);
+
+ idx_t = (FontTypeIndex_T)idx;
+ ft = &ftd.arr_ft[idx_t];
ft->title = title;
ft->fontTextureAssetHandle = fontTextureHandle;
ft->glyphDetailsAssetHandle = glyphsHandle;
ft->renders = pk_new_arr<FontRender>(startingGlyphCount);
- ft->h_render = FontRenderIndex{0};
ft->n_render = FontRenderIndex{startingGlyphCount};
+ ft->unused_frs = 0xFFFFFFFFFFFFFFFF;
ft->msdf_settings = *msdf_settings;
ft->spacing = *spacing;
- const Asset *glyphs = AM_Get(glyphsHandle);
+ glyphs = AM_Get(glyphsHandle);
ft->n_glyphs = glyphs->size / sizeof(FontGlyphChar);
ft->glyphs = (FontGlyphChar*)glyphs->ptr;
@@ -708,11 +750,14 @@ FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle
}
void FontType_Unload(FontTypeIndex idx) {
+ assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)idx)) == 0);
+
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx];
// TODO specific bucket
if (ft->renders != nullptr) {
- for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->h_render; ++i) {
+ for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) {
+ if ((ft->unused_frs & (1llu << i)) != 0) continue;
if (ft->renders[i].glyph_indices != nullptr) {
pk_delete_arr<uint32_t>(ft->renders[i].glyph_indices, ft->renders[i].n_glyphs);
}
@@ -793,7 +838,8 @@ void FontType_Unload(FontTypeIndex idx) {
ft->title.val = nullptr;
ft->title.length = 0;
}
- ECS_MarkForRemoval(ft);
+ ftd.unused_fts |= (1llu << (FontTypeIndex_T)idx);
+ new (ft) FontType{};
}
void FontType_cstr_to_unicode(const FontType &ft, pk_arr_t<uint32_t> &arr, const pk_cstr &str) {
@@ -843,12 +889,22 @@ FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr &&
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)idx_ft];
FontRender *fr;
uint32_t i, count;
- FontRenderIndex idx_fr = ft->h_render;
- ft->h_render += FontRenderIndex{1};
+ FontRenderIndex idx_fr = FontRenderIndex{0};
- if (ft->h_render >= ft->n_render) {
+ for (i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) {
+ if ((ft->unused_frs & (1llu << i)) != 0) {
+ ft->unused_frs &= ~(1llu << i);
+ idx_fr = FontRenderIndex{0};
+ break;
+ }
+ }
+
+ if (idx_fr >= ft->n_render) {
+ if (idx_fr >= FontRenderIndex{PKE_FONT_MAX_FONT_RENDERS}) {
+ throw "[font.cpp] out of FontRender slots";
+ }
FontRenderIndex_T old_count{static_cast<FontRenderIndex_T>(ft->n_render)};
- ft->n_render += FontRenderIndex{5};
+ ft->n_render += FontRenderIndex{8};
FontRender *arr = pk_new_arr<FontRender>((FontRenderIndex_T)ft->n_render);
memcpy(arr, ft->renders, sizeof(FontRender) * old_count);
pk_delete_arr<FontRender>(ft->renders, old_count);
@@ -890,11 +946,11 @@ FontRenderHandle FontType_AddStringRender(FontTypeIndex idx_ft, const pk_cstr &&
}
FontRender *FontType_GetFontRender(FontRenderHandle frh) {
- if (frh.index_ft >= ftd.h_ft) {
+ if ((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) != 0) {
return nullptr;
}
FontType *ft = &ftd.arr_ft[static_cast<FontTypeIndex_T>(frh.index_ft)];
- if (frh.index_fr >= ft->h_render) {
+ if ((ft->unused_frs & (1llu << (FontRenderIndex_T)frh.index_fr)) != 0) {
return nullptr;
}
return &ft->renders[static_cast<FontRenderIndex_T>(frh.index_fr)];
@@ -902,18 +958,18 @@ FontRender *FontType_GetFontRender(FontRenderHandle frh) {
void FontType_UpdateStringRender(FontRenderHandle frh, FontRenderSettings *settings) {
assert(settings != nullptr);
- assert((FontTypeIndex_T)ftd.h_ft > (FontTypeIndex_T)frh.index_ft);
+ assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) == 0);
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)frh.index_ft];
- assert((FontRenderIndex_T)ft->h_render > (FontRenderIndex_T)frh.index_fr);
+ assert((ft->unused_frs & (1llu << (FontTypeIndex_T)frh.index_fr)) == 0);
ft->gr.should_update_instance_buffer = true;
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);
+ assert((ftd.unused_fts & (1llu << (FontTypeIndex_T)frh.index_ft)) == 0);
FontType &ft = ftd.arr_ft[static_cast<FontTypeIndex_T>(frh.index_ft)];
- assert(frh.index_fr < ft.h_render);
+ assert((ft.unused_frs & (1llu << (FontTypeIndex_T)frh.index_fr)) == 0);
FontRender &fr = ft.renders[static_cast<FontRenderIndex_T>(frh.index_fr)];
pk_cstr old_str = fr.text;
if (window == NULL) {
@@ -941,25 +997,10 @@ void FontType_UpdateStringRenderText(FontRenderHandle frh, pk_cstr &&cstr) {
void FontType_RemoveStringRender(FontRenderHandle handle) {
FontRender *fr;
- uint32_t buffer_start_index;
FontType *ft = &ftd.arr_ft[(FontTypeIndex_T)handle.index_ft];
// hack, but works
ft->gr.should_update_instance_buffer = true;
fr = &ft->renders[(FontRenderIndex_T)handle.index_fr];
- ft->bindings.instance_counter -= fr->n_glyphs;
- buffer_start_index = fr->buffer_start_index;
- fr->n_glyphs = 0;
- for (FontRenderIndex_T i = (FontRenderIndex_T)handle.index_fr + 1; FontRenderIndex{i} < ft->h_render; ++i) {
- fr = &ft->renders[i];
- fr->buffer_start_index = buffer_start_index;
- buffer_start_index += fr->n_glyphs;
- }
- if (fr->text.reserved > 0) {
- // 2025-04-16 - JCB
- // not passing a specific bucket because pk_cstr doesn't store it.
- // font.cpp assumes the user has already cloned the string if necessary - only assigns the value.
- pk_delete_arr<char>(fr->text.val, fr->text.reserved);
- }
ECS_MarkForRemoval(fr);
}
diff --git a/src/font.hpp b/src/font.hpp
index 912327e..75035b8 100644
--- a/src/font.hpp
+++ b/src/font.hpp
@@ -7,6 +7,9 @@
#include "vendor-glm-include.hpp"
+#define PKE_FONT_MAX_FONT_TYPES 64
+#define PKE_FONT_MAX_FONT_RENDERS 64
+
TypeSafeInt_H(FontTypeIndex, uint16_t, 0xFFFF);
TypeSafeInt_H(FontRenderIndex, uint16_t, 0xFFFF);
@@ -65,12 +68,12 @@ struct FontRenderSettings {
FONT_RENDER_SURFACE_AREA_TYPE_FLAG surface_area_type_flags; // TODO
};
struct FontRender : public Entity_Base {
- uint32_t *glyph_indices;
- FontRenderHandle fr_handle;
- uint32_t n_glyphs;
- uint32_t buffer_start_index;
- FontRenderSettings settings;
- pk_cstr text;
+ uint32_t *glyph_indices = nullptr;
+ FontRenderHandle fr_handle = FontRenderHandle_MAX;
+ uint32_t n_glyphs = 0;
+ uint32_t buffer_start_index = 0;
+ FontRenderSettings settings{};
+ pk_cstr text{};
};
struct FontTypeMSDFSettings {
float minimum_scale;
@@ -94,7 +97,7 @@ struct FontType : public Entity_Base {
glm::vec2 atlas_size;
uint32_t n_glyphs;
FontRenderIndex n_render = FontRenderIndex{0};
- FontRenderIndex h_render = FontRenderIndex{0};
+ uint64_t unused_frs;
FontTypeIndex index_ft = FontTypeIndex{0};
struct FontTypeMSDFSettings msdf_settings;
struct FontTypeSpacing spacing;
@@ -127,9 +130,8 @@ void FontType_Serialize(std::ostream &stream, FontType *ft);
void FontType_Deserialize(std::istream &stream);
FontType* FontType_Get(FontTypeIndex idx);
FontType* FontType_GetByTitle(const pk_cstr title);
-FontType* FontType_GetFonts(FontTypeIndex &count);
+FontType* FontType_GetFonts(uint64_t &idx_unused);
FontTypeIndex FontType_RegisterFont(pk_cstr title, AssetHandle fontTextureHandle, AssetHandle glyphsHandle, FontTypeMSDFSettings *msdf_settings, FontTypeSpacing *spacing);
-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);
diff --git a/src/game.cpp b/src/game.cpp
index 448bf3d..ef3f2fb 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -104,11 +104,13 @@ void Game_Tick(double delta) {
*/
ECS_Tick_Early(delta);
- EntityType_Tick(delta);
- ECS_Tick(delta);
pke_input_tick(delta);
+
+ EntityType_Tick(delta);
+ pke_level_tick(delta);
pke_ui_tick(delta);
- FontType_Tick(delta);
+ pke_scene_tick(delta);
+ PkeCamera_Tick(delta);
for (long i = 0; i < LoadedPkePlugins.next; ++i) {
if (LoadedPkePlugins[i].OnTick != nullptr) {
@@ -120,7 +122,8 @@ void Game_Tick(double delta) {
reinterpret_cast<void(*)(double delta)>(pkeSettings.rt.activeLevel->pke_cb_tick.func)(delta);
}
- PkeCamera_Tick(delta);
+ FontType_Tick(delta);
+ ECS_Tick(delta);
pke_audio_tick(delta);
@@ -146,9 +149,9 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
CreateWindow(windowProps);
EntityType_Init();
pke_input_init();
+ FontType_Init();
pke_ui_init();
pke_ui_init_bindings();
- FontType_Init();
PkeProject_Load(pkeSettings.args.projectPath);
if (pkeSettings.args.pluginPath != nullptr) {
PkePlugin_Load(pkeSettings.args.pluginPath);
@@ -288,8 +291,8 @@ GAME_SHUTDOWN:
}
PkePlugin_Teardown();
EntityType_Teardown();
- FontType_Teardown();
pke_ui_teardown();
+ FontType_Teardown();
pke_input_teardown();
pke_scene_master_teardown();
pke_level_teardown();
diff --git a/src/level.cpp b/src/level.cpp
index 120ef57..27e7722 100644
--- a/src/level.cpp
+++ b/src/level.cpp
@@ -4,6 +4,7 @@
#include "ecs.hpp"
#include "pk.h"
#include "scene.hpp"
+#include "static-ui.hpp"
struct level_mstr {
pk_membucket *bkt;
@@ -98,6 +99,25 @@ struct pk_bkt_arr *pke_level_get_levels() {
return &level_mstr.bc;
}
+void pke_level_tick(double delta) {
+ (void)delta;
+ pk_iter_t<pke_level> iter;
+ bool b;
+
+ b = pk_bkt_arr_iter_begin(&level_mstr.bc, &iter);
+ while (b == true) {
+ if (iter->isMarkedForRemoval) {
+ pk_arr_reset(&iter->scene_instances);
+ pk_arr_reset(&iter->cameras);
+ pk_arr_reset(&iter->root_ui_boxes);
+ pk_arr_reset(&iter->input_handles);
+ pk_bkt_arr_free_handle(&level_mstr.bc, iter->levelHandle);
+ new (&*iter) pke_level{};
+ }
+ b = pk_bkt_arr_iter_increment(&level_mstr.bc, &iter);
+ }
+}
+
void pke_level_teardown(pke_level *level) {
uint32_t u;
assert(level != nullptr);
@@ -106,10 +126,10 @@ void pke_level_teardown(pke_level *level) {
}
ECS_MarkForRemoval(level);
for (u = 0; u < level->scene_instances.next; ++u) {
- pke_scene_remove(level->scene_instances[u].scene_handle);
+ ECS_MarkForRemoval(pke_scene_get_by_handle(level->scene_instances[u].scene_handle));
}
for (u = 0; u < level->cameras.next; ++u) {
- PkeCamera_Destroy(level->cameras[u]->camHandle);
+ ECS_MarkForRemoval(level->cameras[u]);
}
for (u = 0; u < level->input_handles.next; ++u) {
pke_input_deactivate_set(level->input_handles[u]);
@@ -124,11 +144,6 @@ void pke_level_teardown(pke_level *level) {
if (level->bkt != nullptr) {
pk_mem_bucket_destroy(level->bkt);
}
- pk_arr_reset(&level->scene_instances);
- pk_arr_reset(&level->cameras);
- pk_arr_reset(&level->root_ui_boxes);
- pk_arr_reset(&level->input_handles);
- pk_bkt_arr_free_handle(&level_mstr.bc, level->levelHandle);
}
void pke_level_register_camera(pke_level *level, PkeCamera *camera) {
diff --git a/src/level.hpp b/src/level.hpp
index e9cb0c5..b85a608 100644
--- a/src/level.hpp
+++ b/src/level.hpp
@@ -10,6 +10,7 @@ pke_level *pke_level_create(const char *levelName, pk_uuid level_uuid, pk_uuid e
pke_level *pke_level_get(LevelHandle handle);
pke_level *pke_level_get_by_name(const char *levelName);
struct pk_bkt_arr *pke_level_get_levels();
+void pke_level_tick(double delta);
void pke_level_teardown(pke_level *level);
diff --git a/src/physics.cpp b/src/physics.cpp
index 34cfbed..fe0385c 100644
--- a/src/physics.cpp
+++ b/src/physics.cpp
@@ -22,10 +22,11 @@ struct AllocedData {
};
pk_arr_t<AllocedData> bulletAllocs{};
+btHashedOverlappingPairCache *overlappingPairCache = nullptr;
btDefaultCollisionConfiguration *btConfiguration = nullptr;
btCollisionDispatcher *btDispatcher = nullptr;
-btBroadphaseInterface *btBroadphase = nullptr;
-btConstraintSolver *btSolver = nullptr;
+btDbvtBroadphase *btBroadphase = nullptr;
+btSequentialImpulseConstraintSolver *btSolver = nullptr;
struct EntityCollision {
CompInstance *a, *b;
@@ -111,7 +112,7 @@ void Physics_Init() {
btBroadphase = pk_new<btDbvtBroadphase>(MemBkt_Bullet);
#if 1
- btHashedOverlappingPairCache *overlappingPairCache = pk_new<btHashedOverlappingPairCache>(MemBkt_Bullet);
+ overlappingPairCache = pk_new<btHashedOverlappingPairCache>(MemBkt_Bullet);
overlappingPairCache->setOverlapFilterCallback(&collisionHandlerStruct);
new (btBroadphase) btDbvtBroadphase(overlappingPairCache);
#else
@@ -136,7 +137,22 @@ int32_t Physics_Tick(double delta) {
void Physics_Teardown() {
pk_arr_reset(&collisionsThisTick);
- pk_delete<btDiscreteDynamicsWorld>(BtDynamicsWorld, MemBkt_Bullet);
+ if (BtDynamicsWorld != nullptr)
+ pk_delete<btDiscreteDynamicsWorld>(BtDynamicsWorld, MemBkt_Bullet);
+ if (overlappingPairCache != nullptr)
+ pk_delete<btHashedOverlappingPairCache>(overlappingPairCache, MemBkt_Bullet);
+ if (btConfiguration != nullptr)
+ pk_delete<btDefaultCollisionConfiguration>(btConfiguration, MemBkt_Bullet);
+ if (btSolver != nullptr)
+ pk_delete<btSequentialImpulseConstraintSolver>(btSolver, MemBkt_Bullet);
+ if (btDispatcher != nullptr)
+ pk_delete<btCollisionDispatcher>(btDispatcher, MemBkt_Bullet);
+ if (btBroadphase != nullptr)
+ pk_delete<btDbvtBroadphase>(btBroadphase, MemBkt_Bullet);
+ btConfiguration = nullptr;
+ btSolver = nullptr;
+ btBroadphase = nullptr;
+ btDispatcher = nullptr;
BtDynamicsWorld = nullptr;
// TODO should we manually delete each bullet alloc?
// or just drop?
diff --git a/src/project.cpp b/src/project.cpp
index 62525ef..e1c3333 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -452,10 +452,11 @@ void PkeProject_Save(const char *filePath) {
b = pk_bkt_arr_iter_increment(bkt_arr_ent_types, &iter_ent_type);
}
- FontTypeIndex font_count;
- FontType *fonts = FontType_GetFonts(font_count);
- for (FontTypeIndex b = FontTypeIndex{0}; b < font_count; ++b) {
- FontType *ft = &fonts[(FontTypeIndex_T)b];
+ uint64_t idx_unused;
+ FontType *fonts = FontType_GetFonts(idx_unused);
+ for (uint64_t u = 0; u < PKE_FONT_MAX_FONT_TYPES; ++u) {
+ if ((idx_unused & (1llu << u)) != 0) continue;
+ FontType *ft = &fonts[(FontTypeIndex_T)u];
if (ft->title.val == nullptr) continue;
if (PK_HAS_FLAG(ft->entity_flags, ENTITY_FLAG_DO_NOT_SERIALIZE)) continue;
stream << PKE_PROJ_FILE_OBJ_FONT << std::endl;
diff --git a/src/scene.cpp b/src/scene.cpp
index ecc0fc8..4d5cc76 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -86,15 +86,19 @@ pk_bkt_arr *pke_scene_get_scenes() {
return &scene_mstr.bc;
}
-void pke_scene_remove(SceneHandle handle) {
- pke_scene *scn = &scene_mstr.bc[handle];
- assert(scn != nullptr && "[pke_scene_remove] Failed to find scene by requested SceneHandle");
- ECS_MarkForRemoval(scn);
- if (scn->file_path.reserved > 0) {
- pk_delete_arr<char>(scn->file_path.val, scn->file_path.reserved);
+void pke_scene_tick(double delta) {
+ (void)delta;
+ pk_iter_t<pke_scene> iter;
+ bool b;
+ b = pk_bkt_arr_iter_begin(&scene_mstr.bc, &iter);
+ while (b == true) {
+ if (iter->isMarkedForRemoval == true) {
+ if (iter->file_path.reserved > 0) {
+ pk_delete_arr<char>(iter->file_path.val, iter->file_path.reserved);
+ }
+ pk_bkt_arr_free_handle(&scene_mstr.bc, iter->scene_handle);
+ new (&*iter) pke_scene{};
+ }
+ b = pk_bkt_arr_iter_increment(&scene_mstr.bc, &iter);
}
- scn->file_path = {};
- scn->name[0] = '\0';
- scn->scene_handle = SceneHandle_MAX;
- pk_bkt_arr_free_handle(&scene_mstr.bc, handle);
}
diff --git a/src/scene.hpp b/src/scene.hpp
index 70b5f06..e61b8ba 100644
--- a/src/scene.hpp
+++ b/src/scene.hpp
@@ -11,6 +11,6 @@ struct pke_scene *pke_scene_create(const char *scene_name);
struct pke_scene *pke_scene_get_by_handle(SceneHandle scene_handle);
struct pke_scene *pke_scene_get_by_name(const char *scene_name);
pk_bkt_arr *pke_scene_get_scenes();
-void pke_scene_remove(SceneHandle handle);
+void pke_scene_tick(double delta);
#endif /* PKE_SCENE_HPP */
diff --git a/src/serialization.cpp b/src/serialization.cpp
index 63123fe..dbf9646 100644
--- a/src/serialization.cpp
+++ b/src/serialization.cpp
@@ -80,11 +80,13 @@ void pke_serialize_scene(srlztn_serialize_helper *h) {
pke_serialize_input_set(h, &sets[i]);
}
- FontTypeIndex font_type_count;
- FontType *fonts = FontType_GetFonts(font_type_count);
- for (FontTypeIndex_T b = 0; b < (FontTypeIndex_T)font_type_count; ++b) {
+ uint64_t idx_unused;
+ FontType *fonts = FontType_GetFonts(idx_unused);
+ for (FontTypeIndex_T b = 0; b < PKE_FONT_MAX_FONT_TYPES; ++b) {
+ if ((idx_unused & (1llu << b)) != 0) continue;
FontType *ft = &fonts[b];
- for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->h_render; ++i) {
+ for (FontRenderIndex_T i = 0; i < (FontRenderIndex_T)ft->n_render; ++i) {
+ if ((ft->unused_frs & (1llu << i)) != 0) continue;
pke_serialize_font_render(h, &ft->renders[i]);
}
}
diff --git a/src/static-ui.cpp b/src/static-ui.cpp
index b4bdc5c..c8200b0 100644
--- a/src/static-ui.cpp
+++ b/src/static-ui.cpp
@@ -52,9 +52,10 @@ struct pke_ui_master {
const pke_input_event *mouse_middle = nullptr;
pke_ui_box *deepest_pressed = nullptr;
} state;
+ pk_arr_t<pke_ui_box*> boxes_to_delete{};
} pke_ui_master;
-void pke_ui_teardown_box_recursive(pke_ui_box *box);
+void pke_ui_teardown_box_recursive(pke_ui_box *box, uint8_t depth);
// typedef void(*pke_box_search)(pke_ui_box &box);
typedef std::function<void(pke_ui_box &box)> pke_box_iterate ;
@@ -554,6 +555,12 @@ void pke_ui_tick(double delta) {
(void)delta;
pke_ui_box_count_T i, ii;
uint32_t u;
+
+ for (u = 0; u < pke_ui_master.boxes_to_delete.next; ++u) {
+ pk_delete<pke_ui_box>(pke_ui_master.boxes_to_delete[u], pke_ui_master.bkt);
+ }
+ pk_arr_clear(&pke_ui_master.boxes_to_delete);
+
if (pke_ui_master.h_root_boxes == 0) return;
pke_ui_master.state.mouse_left = pke_input_query_by_action_name(ui_ux_mouse_left);
@@ -576,19 +583,17 @@ void pke_ui_tick(double delta) {
// Leaving this as-is for the time being because you can control the
// visibility of child boxes with flags and don't need to completely remove them.
if (box->isMarkedForRemoval == true) {
- pke_ui_teardown_box_recursive(box);
+ pke_ui_teardown_box_recursive(box, 0);
for (ii = 0; i + ii + 1 < pke_ui_master.r_root_boxes; ++ii) {
pke_ui_master.root_boxes[i + ii] = pke_ui_master.root_boxes[i + ii + 1];
}
pke_ui_master.h_root_boxes -= 1;
i -= 1;
pke_ui_master.should_update_buffer = true;
- goto skip_calc;
+ continue;
}
pke_ui_calc_px(arr, tmp_txtr_arr, nullptr, box);
pke_ui_recalc_sizes_recursive(arr, tmp_txtr_arr, box);
-skip_calc:
- continue;
}
for (i = 0; i < tmp_txtr_arr.next; ++i) {
@@ -629,50 +634,80 @@ skip_calc:
}
}
-void pke_ui_teardown_box_recursive(pke_ui_box *box) {
+void pke_ui_teardown_box_recursive(pke_ui_box *box, uint8_t depth) {
+ FontRender *fr;
+ pke_ui_graphics_bindings_texture *bindings = nullptr;
for (pke_ui_box_count_T i = 0; i < box->internal.h_children; ++i) {
- pke_ui_teardown_box_recursive(box->internal.children[i]);
+ pke_ui_teardown_box_recursive(box->internal.children[i], depth + 1);
}
if (box->internal.children != nullptr) {
pk_delete_arr<pke_ui_box *>(box->internal.children, box->internal.r_children, pke_ui_master.bkt);
}
if (box->type_data != nullptr) {
- if (box->type == PKE_UI_BOX_TYPE_BUTTON_IMAGE && box->type_data->button_image.gr_binds_bkt_arr_handle != pk_bkt_arr_handle_MAX) {
-
- pke_ui_graphics_bindings_texture *bindings = &pke_ui_master.bindings_texture[box->type_data->button_image.gr_binds_bkt_arr_handle];
-
- // reminder that we are not passing the flag on the pool to manually manage descriptor sets, so all we need to do is destroy the pool
- if (bindings->descriptor_pool != VK_NULL_HANDLE) {
- pkvk_queue_vk_descriptor_pool_destroy(bindings->descriptor_pool);
- }
- if (bindings->descriptor_sets != nullptr) {
- pk_delete_arr(bindings->descriptor_sets, prevSwapchainLength, MemBkt_Vulkan);
- }
-
- if (bindings->image_view!= VK_NULL_HANDLE) {
- pkvk_queue_vk_image_view_destroy(bindings->image_view);
- }
- if (bindings->image!= VK_NULL_HANDLE) {
- pkvk_queue_vk_image_destroy(bindings->image);
- }
- if (bindings->image_memory != VK_NULL_HANDLE) {
- pkvk_queue_vk_memory_free(bindings->image_memory);
- }
-
- bindings->descriptor_sets = nullptr;
- bindings->descriptor_pool = VK_NULL_HANDLE;
- pk_bkt_arr_free_handle(&pke_ui_master.bindings_texture, box->type_data->button_image.gr_binds_bkt_arr_handle);
- bindings = nullptr;
+ switch (box->type) {
+ case PKE_UI_BOX_TYPE_TEXT:
+ // 2025-09-16 JCB
+ // If correctly parented, this is unnecessary, but serialization does
+ // not construct text boxes in this way.
+ // Handle to avoid memory leaks.
+ fr = FontType_GetFontRender(box->type_data->text.font_render_handle);
+ if (fr != nullptr && fr->parentHandle != box->handle) {
+ FontType_RemoveStringRender(box->type_data->text.font_render_handle);
+ }
+ break;
+ case PKE_UI_BOX_TYPE_BUTTON_TEXT:
+ fr = FontType_GetFontRender(box->type_data->button_text.font_render_handle);
+ if (fr != nullptr && fr->parentHandle != box->handle) {
+ FontType_RemoveStringRender(box->type_data->button_text.font_render_handle);
+ }
+ break;
+ case PKE_UI_BOX_TYPE_BUTTON_IMAGE:
+ if (box->type_data->button_image.gr_binds_bkt_arr_handle != pk_bkt_arr_handle_MAX) {
+ bindings = &pke_ui_master.bindings_texture[box->type_data->button_image.gr_binds_bkt_arr_handle];
+ // reminder that we are not passing the flag on the pool to manually manage descriptor sets, so all we need to do is destroy the pool
+ if (bindings->descriptor_pool != VK_NULL_HANDLE) {
+ pkvk_queue_vk_descriptor_pool_destroy(bindings->descriptor_pool);
+ }
+ if (bindings->descriptor_sets != nullptr) {
+ pk_delete_arr(bindings->descriptor_sets, prevSwapchainLength, MemBkt_Vulkan);
+ }
+ if (bindings->image_view!= VK_NULL_HANDLE) {
+ pkvk_queue_vk_image_view_destroy(bindings->image_view);
+ }
+ if (bindings->image!= VK_NULL_HANDLE) {
+ pkvk_queue_vk_image_destroy(bindings->image);
+ }
+ if (bindings->image_memory != VK_NULL_HANDLE) {
+ pkvk_queue_vk_memory_free(bindings->image_memory);
+ }
+ bindings->descriptor_sets = nullptr;
+ bindings->descriptor_pool = VK_NULL_HANDLE;
+ pk_bkt_arr_free_handle(&pke_ui_master.bindings_texture, box->type_data->button_image.gr_binds_bkt_arr_handle);
+ bindings = nullptr;
+ }
+ break;
+ case PKE_UI_BOX_TYPE_INPUT_TEXT:
+ // TODO
+ break;
+ case PKE_UI_BOX_TYPE_INPUT_MULTILINE_TEXT:
+ // TODO
+ break;
+ default:
+ fprintf(stderr, "[%s][pke_ui_teardown_box_recursive] unknown box type: %hhu", __FILE__, static_cast<PKE_UI_BOX_TYPE_T>(box->type));
}
pk_delete<pke_ui_box_type_data>(box->type_data, pke_ui_master.bkt);
+ box->type_data = nullptr;
+ }
+ pk_arr_append_t<pke_ui_box*>(&pke_ui_master.boxes_to_delete, box);
+ if (depth != 0) {
+ ECS_MarkForRemoval(box);
}
- pk_delete<pke_ui_box>(box, pke_ui_master.bkt);
pke_ui_master.should_update_buffer = true;
}
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]);
+ pke_ui_teardown_box_recursive(pke_ui_master.root_boxes[i], 0);
}
pk_delete_arr<pke_ui_box *>(pke_ui_master.root_boxes, pke_ui_master.r_root_boxes, pke_ui_master.bkt);
pke_ui_master.bindings_texture.~texture_binding_bkt_arr();
@@ -720,6 +755,7 @@ void pke_ui_teardown() {
vkFreeMemory(vkDevice, pke_ui_master.bindings.deviceMemoryVert, vkAllocator);
pke_ui_master.bindings.deviceMemoryVert = VK_NULL_HANDLE;
+ pk_arr_reset(&pke_ui_master.boxes_to_delete);
pke_input_unregister_set(pke_ui_master.input_action_set_handle);
}
diff --git a/src/thread-pool.cpp b/src/thread-pool.cpp
index f9ff155..d040fa4 100644
--- a/src/thread-pool.cpp
+++ b/src/thread-pool.cpp
@@ -74,6 +74,9 @@ void inline PkeThreads_Reset_Inner(ThreadPool &tp) {
tp.mutex.lock();
tp.maxJobQueueCount = 0;
tp.completedCount = 0;
+ for (uint32_t i = 0; i < tp.threads.next; ++i) {
+ pk_delete<std::thread>(tp.threads[i]);
+ }
pk_arr_clear(&tp.jobQueue);
pk_arr_clear(&tp.threads);
tp.mutex.unlock();
@@ -208,6 +211,13 @@ void PkeThreads_Teardown(ThreadPoolHandle handle) {
PkeThreads_Shutdown_Inner(*tp);
PkeThreads_JoinAll_Inner(*tp);
PkeThreads_Reset_Inner(*tp);
+
+ for (uint32_t i = 0; i < tp->threads.next; ++i) {
+ if (tp->threads[i] != nullptr) {
+ pk_delete<std::thread>(tp->threads[i]);
+ }
+ }
+
pk_arr_reset(&tp->jobQueue);
pk_arr_reset(&tp->threads);
tp->jobQueue.bkt = CAFE_BABE(struct pk_membucket);
diff --git a/src/window.cpp b/src/window.cpp
index 6655488..d3a7234 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -3728,11 +3728,11 @@ void RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
// 2d - font glyphs
- FontTypeIndex count;
- FontType *fts = FontType_GetFonts(count);
- for (FontTypeIndex i = FontTypeIndex{0}; i < count; ++i)
- {
- FontType *ft = &fts[(FontTypeIndex_T)i];
+ uint64_t idx_unused;
+ FontType *fts = FontType_GetFonts(idx_unused);
+ for (uint32_t u = 0; u < 64; ++u) {
+ if ((idx_unused & (1llu << u)) != 0) continue;
+ FontType *ft = &fts[(FontTypeIndex_T)u];
if (ft->bindings.instance_counter == 0)
continue;
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pkePipelines.pipelines.named.font_glyph);
diff --git a/tests/pke-test-asset-manager.cpp b/tests/pke-test-asset-manager.cpp
index 180d134..55a368f 100644
--- a/tests/pke-test-asset-manager.cpp
+++ b/tests/pke-test-asset-manager.cpp
@@ -6,7 +6,11 @@
#include "font.hpp"
#include "thread-pool.hpp"
+static pk_membucket *bkt;
+
void pke_test_asset_manager_spinup() {
+ bkt = pk_mem_bucket_create("pke_test_asset_manager", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ pk_mem_bucket_set_client_mem_bucket(bkt);
pk_ev_init(nullptr);
PkeThreads_Init();
AM_Init();
@@ -20,6 +24,9 @@ void pke_test_asset_manager_teardown() {
AM_Teardown();
PkeThreads_Teardown();
pk_ev_teardown();
+ pk_mem_bucket_destroy(bkt);
+ pk_mem_bucket_set_client_mem_bucket(nullptr);
+ bkt = nullptr;
};
int pke_test_asset_manager_001() {
diff --git a/tests/pke-test-dummy.cpp b/tests/pke-test-dummy.cpp
index e8c34ba..914f3cf 100644
--- a/tests/pke-test-dummy.cpp
+++ b/tests/pke-test-dummy.cpp
@@ -11,8 +11,12 @@
#include "static-ui.hpp"
#include "thread-pool.hpp"
+static pk_membucket *bkt;
+
int pke_test_dummy_001() {
- pk_ev_init(nullptr);
+ bkt = pk_mem_bucket_create("pke_test_dummy", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ pk_mem_bucket_set_client_mem_bucket(bkt);
+ pk_ev_init(bkt);
Physics_Init();
PkeThreads_Init();
AM_Init();
@@ -40,6 +44,9 @@ int pke_test_dummy_001() {
PkeThreads_Teardown();
Physics_Teardown();
pk_ev_teardown();
+ pk_mem_bucket_destroy(bkt);
+ pk_mem_bucket_set_client_mem_bucket(nullptr);
+ bkt = nullptr;
return 0;
}
diff --git a/tests/pke-test-load-unload.cpp b/tests/pke-test-load-unload.cpp
new file mode 100644
index 0000000..f714538
--- /dev/null
+++ b/tests/pke-test-load-unload.cpp
@@ -0,0 +1,303 @@
+
+#include "pke-test-load-unload.h"
+
+#include "asset-manager.hpp"
+#include "audio.hpp"
+#include "camera.hpp"
+#include "ecs.hpp"
+#include "entities.hpp"
+#include "game-settings.hpp"
+#include "game.hpp"
+#include "level.hpp"
+#include "physics.hpp"
+#include "pk.h"
+#include "player-input.hpp"
+#include "scene.hpp"
+#include "static-ui.hpp"
+#include "thread-pool.hpp"
+
+#include "pk.h"
+
+extern pk_arr_t<Entity_Base*> entitiesMarkedForRemoval;
+extern pk_arr_t<EntityHandle> entitiesYetToBeRemoved;
+
+static pk_membucket *bkt;
+static pke_level *level_01;
+
+void print_entities_marked_for_removal() {
+ bool b;
+ pk_iter_t<Entity_Base*> iter{};
+ fprintf(stdout, "marked for removal BEGIN\n");
+ b = pk_arr_iter_begin(&entitiesMarkedForRemoval, &iter);
+ while (b == true) {
+ fprintf(stdout, "0x%.2X 0x%.2X\n", (*iter)->handle.b, (*iter)->handle.i);
+ b = pk_arr_iter_increment(&entitiesMarkedForRemoval, &iter);
+ }
+ fprintf(stdout, "marked for removal END\n\n");
+}
+
+void print_entities_yet_to_be_removed() {
+ bool b;
+ pk_iter_t<EntityHandle> iter{};
+ fprintf(stdout, "yet to be removed BEGIN\n");
+ b = pk_arr_iter_begin(&entitiesYetToBeRemoved, &iter);
+ while (b == true) {
+ fprintf(stdout, "0x%.2X 0x%.2X\n", iter->b, iter->i);
+ b = pk_arr_iter_increment(&entitiesYetToBeRemoved, &iter);
+ }
+ fprintf(stdout, "yet to be removed END\n\n");
+}
+
+int pke_test_load_unload_do_thing_001(int iteration) {
+ uint64_t err_index = iteration << 16;
+
+ // fprintf(stdout, "begin\n");
+
+ pkeSettings.rt.activeLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed);
+ assert(pkeSettings.rt.activeLevel->isMarkedForRemoval == false);
+
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ // fprintf(stdout, "tick 1\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+
+ level_01 = pke_level_create("load_unload_01", pk_uuid_zed, pk_uuid_zed);
+ assert(level_01->isMarkedForRemoval == false);
+ pkeSettings.rt.nextLevel = level_01;
+
+ /* JCB
+ * Double tick so that the level can get flushed out.
+ * We need to do this so the first few asserts get a clean starting point.
+ * This *IS* expected behavior
+ */
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ // fprintf(stdout, "tick 2\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 1, err_index);
+ // fprintf(stdout, "tick 3\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+
+ return 0;
+}
+
+int pke_test_load_unload_do_thing_002(int iteration) {
+ uint64_t err_index = iteration << 16;
+
+ // fprintf(stdout, "begin\n");
+
+ pkeSettings.rt.activeLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed);
+ assert(pkeSettings.rt.activeLevel->isMarkedForRemoval == false);
+
+ // 1
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ // fprintf(stdout, "tick 1\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+
+ level_01 = pke_level_create("load_unload_01", pk_uuid_zed, pk_uuid_zed);
+ assert(level_01->isMarkedForRemoval == false);
+ pkeSettings.rt.nextLevel = level_01;
+ pke_ui_box *bx = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT);
+ FontRenderSettings frs_01{};
+ bx->type_data->text.font_render_handle = FontType_AddStringRender(FontTypeIndex{0}, std::move(cstring_to_pk_cstr("one")), &frs_01, bx);
+ bx->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_STATIC;
+ pke_level_register_root_ui_box(level_01, bx);
+
+ // 11
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ // fprintf(stdout, "tick 2\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 1, err_index);
+ // fprintf(stdout, "tick 3\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+
+ pkeSettings.rt.nextLevel = pke_level_create("load_unload_faux", pk_uuid_zed, pk_uuid_zed);
+
+ // 26
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ // fprintf(stdout, "tick 4\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 3, err_index);
+ // fprintf(stdout, "tick 5\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+ // fprintf(stdout, "tick 6\n");
+ Game_Tick(double(1.0 / 120.0));
+ // print_entities_marked_for_removal();
+ // print_entities_yet_to_be_removed();
+ PKE_TEST_ASSERT(pkeSettings.rt.activeLevel != NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.nextLevel == NULL, err_index);
+ PKE_TEST_ASSERT(pkeSettings.rt.previousLevel == NULL, err_index);
+ PKE_TEST_ASSERT(entitiesMarkedForRemoval.next == 0, err_index);
+ PKE_TEST_ASSERT(entitiesYetToBeRemoved.next == 0, err_index);
+
+ return 0;
+}
+
+void pke_test_load_unload_init() {
+ bkt = pk_mem_bucket_create("pke_test_load_unload", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ pk_mem_bucket_set_client_mem_bucket(bkt);
+ pkeSettings.mem_bkt.game = bkt;
+ pkeSettings.mem_bkt.game_transient = pk_mem_bucket_create("pke_test_load_unload_transient", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_TRANSIENT);
+ pk_ev_init(bkt);
+ Physics_Init();
+ PkeThreads_Init();
+ AM_Init();
+ ECS_Init();
+ pke_audio_init();
+ pke_input_init();
+ pke_ui_init();
+ PkeCamera_Init();
+ FontType_Init();
+ pke_scene_master_init();
+ pke_level_init();
+ EntityType_Init();
+}
+
+void pke_test_load_unload_teardown() {
+ EntityType_Teardown();
+ pke_level_teardown();
+ pke_scene_master_teardown();
+ FontType_Teardown();
+ PkeCamera_Teardown();
+ pke_ui_teardown();
+ pke_input_teardown();
+ pke_audio_teardown();
+ ECS_Teardown();
+ AM_Teardown();
+ PkeThreads_Teardown();
+ Physics_Teardown();
+ pk_ev_teardown();
+ pk_mem_bucket_destroy(pkeSettings.mem_bkt.game_transient);
+ pk_mem_bucket_destroy(bkt);
+ pk_mem_bucket_set_client_mem_bucket(nullptr);
+ bkt = nullptr;
+ pkeSettings.mem_bkt.game = nullptr;
+ pkeSettings.mem_bkt.game_transient = nullptr;
+ pkeSettings.rt.activeLevel = nullptr;
+ pkeSettings.rt.nextLevel = nullptr;
+ pkeSettings.rt.previousLevel = nullptr;
+}
+
+int pke_test_load_unload_001() {
+ int i, k;
+ for (i = 0; i < 255; ++i) {
+ if (k = pke_test_load_unload_do_thing_001(i), k != 0){
+ return k;
+ }
+ }
+ return 0;
+}
+
+int pke_test_load_unload_002() {
+ int i, k;
+ for (i = 0; i < 255; ++i) {
+ if (k = pke_test_load_unload_do_thing_002(i), k != 0){
+ return k;
+ }
+ }
+ return 0;
+}
+
+struct pke_test_group *
+pke_test_load_unload_get_group()
+{
+ static const uint64_t test_count = 2;
+ static struct pke_test tests[test_count] = {
+ {
+ .title = "test 001",
+ .func = pke_test_load_unload_001,
+ .expected_result = 0,
+ },
+ {
+ .title = "test 002",
+ .func = pke_test_load_unload_002,
+ .expected_result = 0,
+ },
+ };
+ static struct pke_test_group group{};
+ group.title = "load-unload";
+ group.group_setup = nullptr;
+ group.group_teardown = nullptr;
+ group.test_setup = pke_test_load_unload_init;
+ group.test_teardown = pke_test_load_unload_teardown;
+ group.n_tests = test_count;
+ group.tests = &tests[0];
+ return &group;
+}
+
diff --git a/tests/pke-test-load-unload.h b/tests/pke-test-load-unload.h
new file mode 100644
index 0000000..be28f0f
--- /dev/null
+++ b/tests/pke-test-load-unload.h
@@ -0,0 +1,16 @@
+#ifndef PKE_PKE_TEST_LOAD_UNLOAD_H
+#define PKE_PKE_TEST_LOAD_UNLOAD_H
+
+#include "pke-test-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct pke_test_group *pke_test_load_unload_get_group();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PKE_PKE_TEST_LOAD_UNLOAD_H */
diff --git a/tests/pke-test-serialization.cpp b/tests/pke-test-serialization.cpp
index 374d77e..de483f7 100644
--- a/tests/pke-test-serialization.cpp
+++ b/tests/pke-test-serialization.cpp
@@ -18,7 +18,7 @@
#include <cstring>
#include <sstream>
-pk_membucket *bkt = nullptr;
+static pk_membucket *bkt = nullptr;
const char *test_level_name = "srlztn_test_level";
pke_level *test_level = nullptr;
FontType *ft;
@@ -48,6 +48,8 @@ const pk_uuid uuid_n[] = {
void pke_test_serialization_spinup() {
// pk_funcinstr_init();
+ bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ pk_mem_bucket_set_client_mem_bucket(bkt);
pkeSettings.isSimulationPaused = true;
pk_ev_init(nullptr);
PkeThreads_Init();
@@ -58,8 +60,8 @@ void pke_test_serialization_spinup() {
PkeCamera_Init();
pke_scene_master_init();
pke_input_init();
- pke_ui_init();
FontType_Init();
+ pke_ui_init();
test_level = pke_level_create(test_level_name, pk_uuid_zed, pk_uuid_zed);
// pk_funcinstr_teardown();
};
@@ -68,8 +70,8 @@ void pke_test_serialization_teardown() {
// pk_funcinstr_init();
pke_level_teardown(test_level);
test_level = nullptr;
- FontType_Teardown();
pke_ui_teardown();
+ FontType_Teardown();
pke_input_teardown();
pke_scene_master_teardown();
PkeCamera_Teardown();
@@ -79,6 +81,8 @@ void pke_test_serialization_teardown() {
AM_Teardown();
PkeThreads_Teardown();
pk_ev_teardown();
+ pk_mem_bucket_destroy(bkt);
+ pk_mem_bucket_set_client_mem_bucket(nullptr);
bkt = nullptr;
// pk_funcinstr_teardown();
};
@@ -142,7 +146,6 @@ int pke_test_serialization_001() {
srlztn_serialize_helper *h;
std::stringstream ss;
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_serialize_init(bkt);
glm::vec3 pos = glm::vec3(0,1,2);
@@ -171,10 +174,8 @@ int pke_test_serialization_001() {
pke_serialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
pk_funcinstr_teardown();
return 0;
}
@@ -184,7 +185,6 @@ int pke_test_deserialization_101() {
srlztn_deserialize_helper *h;
std::stringstream ss(test_001_str);
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_deserialize_init(test_level, bkt);
pke_deserialize_scene_from_stream(ss, h);
@@ -214,10 +214,8 @@ int pke_test_deserialization_101() {
pke_deserialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -255,7 +253,6 @@ int pke_test_serialization_002() {
pke_kve *kve = nullptr;
std::stringstream ss;
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_serialize_init(bkt);
// reminder that 'targeting' moves and rotates the camera, so we shouldn't see these values in the output
@@ -313,10 +310,8 @@ int pke_test_serialization_002() {
pke_serialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -327,7 +322,6 @@ int pke_test_deserialization_102() {
srlztn_deserialize_helper *h;
std::stringstream ss(test_002_str);
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_deserialize_init(test_level, bkt);
pke_deserialize_scene_from_stream(ss, h);
@@ -385,10 +379,8 @@ int pke_test_deserialization_102() {
pke_deserialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -433,10 +425,9 @@ int pke_test_serialization_003() {
pke_kve *kve = nullptr;
std::stringstream ss;
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_serialize_init(bkt);
- FontTypeIndex fti;
+ uint64_t idx_unused;
FontRenderSettings frs;
frs.char_scale = 1.0;
frs.char_spacing_scale = 1.0;
@@ -444,7 +435,7 @@ int pke_test_serialization_003() {
frs.surface_area_size = glm::ivec2(250, 250);
frs.surface_area_pos = glm::ivec2(0, 0);
frs.surface_area_type_flags = FONT_RENDER_SURFACE_AREA_TYPE_FLAGS_FLUID;
- FontRenderHandle fr_handle = FontType_AddStringRender(FontType_GetFonts(fti)[0].index_ft, std::move(cstring_to_pk_cstr("asdf")), &frs, nullptr, uuid_n[1]);
+ FontRenderHandle fr_handle = FontType_AddStringRender(FontType_GetFonts(idx_unused)[0].index_ft, std::move(cstring_to_pk_cstr("asdf")), &frs, nullptr, uuid_n[1]);
pke_ui_box *ui_box = pke_ui_box_new_root(PKE_UI_BOX_TYPE_TEXT, uuid_n[2]);
ui_box->flags |= PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC;
@@ -491,10 +482,8 @@ int pke_test_serialization_003() {
pke_serialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -505,7 +494,6 @@ int pke_test_deserialization_103() {
srlztn_deserialize_helper *h;
std::stringstream ss(test_003_str);
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_deserialize_init(test_level, bkt);
pke_deserialize_scene_from_stream(ss, h);
@@ -539,16 +527,15 @@ int pke_test_deserialization_103() {
pke_deserialize_scene(h);
- FontTypeIndex fti = FontTypeIndex{0};
- FontType *fonts = FontType_GetFonts(fti);
+ uint64_t idx_unused;
+ FontType *fonts = FontType_GetFonts(idx_unused);
// 66
- PKE_TEST_ASSERT(fti > FontTypeIndex{0}, err_index);
PKE_TEST_ASSERT(fonts != nullptr, err_index);
- PKE_TEST_ASSERT(fonts->h_render > FontRenderIndex{0}, err_index);
+ PKE_TEST_ASSERT(idx_unused != 0xFFFFFFFFFFFFFFFF, err_index);
PKE_TEST_ASSERT(fonts->n_render > FontRenderIndex{0}, err_index);
FontRender *fr = &fonts[0].renders[0];
- // 70
+ // 69
PKE_TEST_ASSERT(fr->settings.char_scale == 1.f, err_index);
PKE_TEST_ASSERT(fr->settings.line_height_scale == 1.f, err_index);
PKE_TEST_ASSERT(fr->settings.char_spacing_scale == 1.f, err_index);
@@ -560,7 +547,7 @@ int pke_test_deserialization_103() {
PKE_TEST_ASSERT(fr->settings.color_foreground == glm::vec4(0.4, 0.9, 0.5, 0.8), err_index);
PKE_TEST_ASSERT(fr->settings.color_background == glm::vec4(0.0, 0.0, 0.0, 0.0), err_index);
- // 78
+ // 77
PKE_TEST_ASSERT(fr->uuid == uuid_n[1], err_index);
PKE_TEST_ASSERT(fr->text.val != nullptr, err_index);
PKE_TEST_ASSERT(fr->text.val[0] == 'a', err_index);
@@ -569,7 +556,7 @@ int pke_test_deserialization_103() {
PKE_TEST_ASSERT(fr->text.val[3] == 'f', err_index);
PKE_TEST_ASSERT(fr->text.val[4] == '\0', err_index);
- // 85
+ // 84
pke_ui_box_count_T count;
pke_ui_box **boxes = pke_ui_get_root_boxes(&count);
pke_ui_box *box = boxes[0];
@@ -582,10 +569,8 @@ int pke_test_deserialization_103() {
pke_deserialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -622,7 +607,6 @@ int pke_test_serialization_004() {
pke_kve *kve = nullptr;
std::stringstream ss;
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_serialize_init(bkt);
pke_ui_box *ui_box_p = pke_ui_box_new_root(PKE_UI_BOX_TYPE_STANDARD, uuid_n[2]);
@@ -670,10 +654,8 @@ int pke_test_serialization_004() {
pke_serialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
@@ -684,7 +666,6 @@ int pke_test_deserialization_104() {
pke_kve *kve = nullptr;
std::stringstream ss(test_004_str);
try {
- bkt = pk_mem_bucket_create("pke_test_serialization", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
h = pke_deserialize_init(test_level, bkt);
pke_deserialize_scene_from_stream(ss, h);
@@ -750,10 +731,8 @@ int pke_test_deserialization_104() {
pke_deserialize_teardown(h);
} catch (const std::exception &ex) {
- pk_mem_bucket_destroy(bkt);
throw;
}
- pk_mem_bucket_destroy(bkt);
return 0;
}
diff --git a/tests/pke-test-static-ui.cpp b/tests/pke-test-static-ui.cpp
index ca696fc..c102aba 100644
--- a/tests/pke-test-static-ui.cpp
+++ b/tests/pke-test-static-ui.cpp
@@ -8,6 +8,7 @@
#include "window.hpp"
#include "vendor-glm-include.hpp"
#include <limits>
+
struct pke_ui_box_instance_buffer_item {
glm::mat4 pos_scale;
glm::vec2 px_scale;
@@ -18,10 +19,15 @@ struct pke_ui_flex_params {
float px_per_unit;
float unit_total;
};
+
#define PKE_TEST_EXPOSE
#include "static-ui.hpp"
+static pk_membucket *bkt;
+
void pke_test_static_ui_setup() {
+ bkt = pk_mem_bucket_create("pke_test_static_ui", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
+ pk_mem_bucket_set_client_mem_bucket(bkt);
Extent.width = 1920;
Extent.height = 1080;
pk_ev_init(nullptr);
@@ -35,6 +41,9 @@ void pke_test_static_ui_teardown() {
ECS_Teardown();
pk_ev_teardown();
pke_input_teardown();
+ pk_mem_bucket_destroy(bkt);
+ pk_mem_bucket_set_client_mem_bucket(nullptr);
+ bkt = nullptr;
}
// test static
diff --git a/tests/pke-test.cpp b/tests/pke-test.cpp
index 97694b2..4c6f560 100644
--- a/tests/pke-test.cpp
+++ b/tests/pke-test.cpp
@@ -1,12 +1,13 @@
#include "./pke-test-types.h"
-#include "./pke-test-stubs.h"
-#include "./pke-test-audio.h"
#include "./pke-test-asset-manager.h"
+#include "./pke-test-audio.h"
#include "./pke-test-dummy.h"
+#include "./pke-test-load-unload.h"
#include "./pke-test-serialization.h"
#include "./pke-test-static-ui.h"
+#include "./pke-test-stubs.h"
#include "pk.h"
#include "unistd.h"
@@ -42,6 +43,7 @@ int main(int argc, char *argv[])
pke_test_static_ui_get_group,
pke_test_serialization_get_group,
pke_test_asset_manager_get_group,
+ pke_test_load_unload_get_group,
// pke_test_audio_get_group,
NULL,
};
@@ -55,9 +57,6 @@ int main(int argc, char *argv[])
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) {
- struct pk_membucket *bkt = pk_mem_bucket_create("pke-test-bucket", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_NONE);
- pk_mem_bucket_set_client_mem_bucket(bkt);
- fprintf(stdout, "[pke-test]:[%s]:[%s] Begin.\n", group->title, group->tests[k].title);
pke_test_stub_init_vulkan();
if (group->test_setup != NULL) (group->test_setup)();
lj.expected_exit = 0;
@@ -76,7 +75,6 @@ int main(int argc, char *argv[])
}
if (group->test_teardown != NULL) (group->test_teardown)();
pke_test_stub_teardown_vulkan();
- pk_mem_bucket_destroy(bkt);
}
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);