diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-21 20:54:14 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-21 21:40:21 -0400 |
| commit | 677a3cbec2f7908ee0897b97d508a6bd66a0a344 (patch) | |
| tree | fc88b21dd61dbb10dd8b5c8aef73702d15514f00 /src | |
| parent | cae76dd98e301a4560bb46ecb59b5952dff04149 (diff) | |
pke: first-pass level is a collection of scenes
Diffstat (limited to 'src')
| -rw-r--r-- | src/arg-handler.cpp | 6 | ||||
| -rw-r--r-- | src/bucketed-array.hpp | 10 | ||||
| -rw-r--r-- | src/components.hpp | 4 | ||||
| -rw-r--r-- | src/ecs.cpp | 4 | ||||
| -rw-r--r-- | src/entities.cpp | 3 | ||||
| -rw-r--r-- | src/game-settings.hpp | 4 | ||||
| -rw-r--r-- | src/game.cpp | 57 | ||||
| -rw-r--r-- | src/game.hpp | 3 | ||||
| -rw-r--r-- | src/level-types.hpp | 19 | ||||
| -rw-r--r-- | src/level.cpp | 109 | ||||
| -rw-r--r-- | src/level.hpp | 11 | ||||
| -rw-r--r-- | src/scene-types.hpp | 18 | ||||
| -rw-r--r-- | src/scene.cpp | 96 | ||||
| -rw-r--r-- | src/scene.hpp | 20 |
14 files changed, 279 insertions, 85 deletions
diff --git a/src/arg-handler.cpp b/src/arg-handler.cpp index 24695fe..f192584 100644 --- a/src/arg-handler.cpp +++ b/src/arg-handler.cpp @@ -9,6 +9,7 @@ void PkeArgs_Parse(int argc, char *argv[]) { while (1) { static struct option long_options[] = { + {"level", required_argument, 0, 'l'}, {"plugin", required_argument, 0, 'p'}, {"project", required_argument, 0, 'r'}, {"scene", required_argument, 0, 's'}, @@ -24,6 +25,9 @@ void PkeArgs_Parse(int argc, char *argv[]) { switch (c) { case 0: break; + case 'l': + pkeSettings.args.levelName = optarg; + break; case 'p': pkeSettings.args.pluginPath = optarg; break; @@ -32,8 +36,6 @@ void PkeArgs_Parse(int argc, char *argv[]) { break; case 's': pkeSettings.args.sceneName = optarg; - pkeSettings.rt.shouldLoadScene = true; - pkeSettings.rt.sceneName = pkeSettings.args.sceneName; break; default: fprintf(stderr, "Unused parameter: %c\n", c); diff --git a/src/bucketed-array.hpp b/src/bucketed-array.hpp index fb24712..150fa66 100644 --- a/src/bucketed-array.hpp +++ b/src/bucketed-array.hpp @@ -14,9 +14,19 @@ struct BucketContainer { CT limits; CT pkeHandle; T* buckets[BKT_CNT]; + T& operator[](CT) const; }; template<typename T, typename CT, pk_handle_item_index_T BKT_CNT> +T& +BucketContainer<T, CT, BKT_CNT>::operator[](CT handle) const { + assert(handle.bucketIndex < this->limits.bucketIndex); + assert(handle.itemIndex < this->limits.itemIndex); + assert(handle.bucketIndex != this->pkeHandle.bucketIndex || handle.itemIndex < this->pkeHandle.itemIndex); + return this->buckets[handle.bucketIndex][handle.itemIndex]; +} + +template<typename T, typename CT, pk_handle_item_index_T BKT_CNT> void Buckets_Init(BucketContainer<T, CT, BKT_CNT> &bktContainer, size_t maxItemCount = BucketContainerDefaultItemCount) { bktContainer.limits.bucketIndex = BKT_CNT; bktContainer.limits.itemIndex = maxItemCount; diff --git a/src/components.hpp b/src/components.hpp index b587fcc..326b0e6 100644 --- a/src/components.hpp +++ b/src/components.hpp @@ -16,10 +16,14 @@ const uint32_t ECS_UNSET_VAL_32 = 0xFFFFFFFF; struct EntityHandle : public pk_handle { }; struct GrBindsHandle : public pk_handle { }; struct InstanceHandle : public pk_handle { }; +struct SceneHandle : public pk_handle { }; +struct LevelHandle : public pk_handle { }; constexpr EntityHandle EntityHandle_MAX = EntityHandle{ pk_handle_MAX_constexpr }; constexpr GrBindsHandle GrBindsHandle_MAX = GrBindsHandle{ pk_handle_MAX_constexpr }; constexpr InstanceHandle InstanceHandle_MAX = InstanceHandle{ pk_handle_MAX_constexpr }; +constexpr SceneHandle SceneHandle_MAX = SceneHandle{ pk_handle_MAX_constexpr }; +constexpr LevelHandle LevelHandle_MAX = LevelHandle{ pk_handle_MAX_constexpr }; struct Entity_Base { EntityHandle handle = EntityHandle_MAX; diff --git a/src/ecs.cpp b/src/ecs.cpp index 3ab8a80..4174bd0 100644 --- a/src/ecs.cpp +++ b/src/ecs.cpp @@ -83,8 +83,8 @@ EntityHandle ECS_CreateEntity(Entity_Base *entity, Entity_Base *parentEntity) { } Entity_Base *ECS_GetEntity(EntityHandle handle) { - pk_handle_validate(handle, ecs.bc.entityPtrs.pkeHandle, ecs.bc.entityPtrs.limits.itemIndex); - return ecs.bc.entityPtrs.buckets[handle.bucketIndex][handle.itemIndex]; + if (pk_handle_validate(handle, ecs.bc.entityPtrs.pkeHandle, ecs.bc.entityPtrs.limits.itemIndex) != PK_HANDLE_VALIDATION_VALID) return nullptr; + return ecs.bc.entityPtrs[handle]; } void ECS_MarkForRemoval(Entity_Base *entity) { diff --git a/src/entities.cpp b/src/entities.cpp index 1abe632..2ec6c60 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -108,6 +108,9 @@ EntityType *EntityType_FindByTypeCode(const char *typeCode) { EntityType *EntityType_FindByEntityHandle_Inner(EntityHandle handle) { if (handle == EntityHandle_MAX) return nullptr; + if (handle.bucketIndex > EntityType_BC.limits.bucketIndex) return nullptr; + if (handle.itemIndex > EntityType_BC.limits.itemIndex) return nullptr; + if (handle.bucketIndex == EntityType_BC.pkeHandle.bucketIndex && handle.itemIndex >= EntityType_BC.pkeHandle.bucketIndex) return nullptr; for (pk_handle_bucket_index_T b = 0; b <= EntityType_BC.pkeHandle.bucketIndex; ++b) { auto &bkt = EntityType_BC.buckets[b]; long itemCount = EntityType_BC.pkeHandle.bucketIndex == b ? EntityType_BC.pkeHandle.itemIndex : EntityType_BC.limits.itemIndex; diff --git a/src/game-settings.hpp b/src/game-settings.hpp index 65f4242..ba078b9 100644 --- a/src/game-settings.hpp +++ b/src/game-settings.hpp @@ -34,6 +34,7 @@ struct GameSettings { struct pk_membucket *bkt = nullptr; } mem; struct engineArgs { + const char *levelName = nullptr; const char *pluginPath = nullptr; const char *projectPath = nullptr; const char *sceneName = nullptr; @@ -45,9 +46,6 @@ struct GameSettings { LevelHandle nextLevel = LevelHandle_MAX; // level to unload LevelHandle previousLevel = LevelHandle_MAX; - const char *sceneName = nullptr; - bool shouldLoadScene = false; - bool shouldSaveScene = false; bool was_framebuffer_resized = false; } rt; }; diff --git a/src/game.cpp b/src/game.cpp index 3c39018..2edea8c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -17,6 +17,7 @@ #include "player-input.hpp" #include "plugins.hpp" #include "project.hpp" +#include "scene.hpp" #include "static-ui.hpp" #include "thread-pool.hpp" #include "window.hpp" @@ -162,7 +163,7 @@ bool FindFirstInstanceHandle(void *handle, void *mapping) { InstMapping *inst_mapping = reinterpret_cast<InstMapping *>(mapping); return inst_mapping->origHandle == *reinterpret_cast<InstanceHandle *>(handle); } -void DeserializeCamera(PkeLevel *level, std::istream &stream) { +void DeserializeCamera(pke_scene *scene, std::istream &stream) { PkeCamera cam{}; InstanceHandle instanceHandle = InstanceHandle_MAX; InstanceHandle targetInstanceHandle = InstanceHandle_MAX; @@ -191,7 +192,7 @@ void DeserializeCamera(PkeLevel *level, std::istream &stream) { rCam.view = cam.view; rCam.isPrimary = cam.isPrimary; rCam.phys.targetInstHandle = targetInstanceHandle; - PkeLevel_RegisterCamera(level->levelHandle, rCam.camHandle); + pke_scene_register_camera(scene->scene_handle, rCam.camHandle); if (targetInstanceIndex > -1) { PkeCamera_TargetInstance(rCam.camHandle, ECS_GetInstance(loadFileInstanceMappings[targetInstanceIndex].newInstHandle)); } @@ -476,21 +477,27 @@ void Game_SaveSceneFile(const char *sceneFilePath) { } } -void Game_LoadSceneFile(PkeLevel *level, const char *sceneFilePath) { +void Game_LoadSceneFile(const char *sceneFilePath) { std::ifstream f(sceneFilePath); if (!f.is_open()) { - fprintf(stderr, "Failed to load requested scene file: %s\n", sceneFilePath); + fprintf(stderr, "Failed to load requested scene file: '%s'\n", sceneFilePath); return; } + // TODO scene name is in the file? + pke_scene *scn = pke_scene_get_by_name(sceneFilePath); + if (scn == nullptr) { + scn = pke_scene_create(sceneFilePath); + } + memset(readLine, '\0', readLineLength); while (f.getline(readLine, readLineLength)) { if (strcmp(PKE_FILE_OBJ_INSTANCE, readLine) == 0) { - DeserializeInstance(level, f); + DeserializeInstance(scn, f); continue; } if (strcmp(PKE_FILE_OBJ_CAMERA, readLine) == 0) { - DeserializeCamera(level, f); + DeserializeCamera(scn, f); continue; } } @@ -539,17 +546,18 @@ void Game_RecordImGui() { void Game_Tick(double delta) { pk_bucket_reset(pkeSettings.mem.bkt); - // TODO this should be removed in favor of storing the scene details inside a level definition - if (pkeSettings.rt.shouldLoadScene && pkeSettings.rt.sceneName) { - pkeSettings.rt.shouldLoadScene = false; - if (pkeSettings.rt.activeLevel != LevelHandle_MAX) { - pkeSettings.rt.previousLevel = pkeSettings.rt.activeLevel; - } - pkeSettings.rt.nextLevel = PkeLevel_Create(pkeSettings.rt.sceneName); - } if (pkeSettings.rt.nextLevel != LevelHandle_MAX) { // TODO async this - Game_LoadSceneFile(PkeLevel_Get(pkeSettings.rt.nextLevel), pkeSettings.rt.sceneName); + PkeLevel *lvl = PkeLevel_Get(pkeSettings.rt.activeLevel); + for (uint32_t i = 0; i < lvl->scene_instances.next; ++i) { + // TODO can't instantiate a scene that hasn't been loaded yet + /* + struct pke_scene *scene = pke_scene_get_by_handle(lvl->scene_instances[i].scene_handle); + if (scene != nullptr) { + Game_LoadSceneFile(scene->name); + } + */ + } pkeSettings.rt.activeLevel = pkeSettings.rt.nextLevel; pkeSettings.rt.nextLevel = LevelHandle_MAX; } @@ -593,6 +601,7 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { Physics_Init(); PkeCamera_Init(); PkeLevel_Init(); + pke_scene_master_init(); Game_Init(); CreateWindow(windowProps); EntityType_Init(); @@ -610,6 +619,20 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { } } + // + // at this point, everything is loaded or initialized. + // + + // if we were passed only a scene name, create a faux level. + if (!pkeSettings.args.levelName && pkeSettings.args.sceneName) { + pkeSettings.rt.nextLevel = PkeLevel_Create("faux-level")->levelHandle; + PkeLevel *lvl = PkeLevel_Get(pkeSettings.rt.nextLevel); + scene_instance si{}; + si.scene_handle = pke_scene_get_by_name(pkeSettings.args.sceneName)->scene_handle; + pk_arr_append_t(&lvl->scene_instances, si); + } + + // TODO remove me: temp stuff for testing pk_cstr test_text = cstring_to_pk_cstr("012\n3456789\tThe quick\r\nbrown fox jumped over the lazy dog."); // pk_cstr test_text = cstring_to_pk_cstr("%+-*0123456789$"); // pk_cstr test_text = cstring_to_pk_cstr("$#"); @@ -634,6 +657,7 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { FontType_AddStringRender(FontTypeIndex{1}, pk_cstr_to_pk_str(&test_text2), &fr_set); } + // TODO remove me: temp stuff for testing pke_ui_box *ui_box = pke_ui_box_new_root(); ui_box->flags = PKE_UI_BOX_FLAG_POSITION_TYPE_DYNAMIC; ui_box->pos_top_left_x = 0.1; @@ -641,6 +665,7 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { ui_box->max_width = 0.8; ui_box->max_height = 0.8; + // TODO remove me: temp stuff for testing 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 = 20; @@ -747,6 +772,8 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) { FontType_Teardown(); pke_ui_teardown(); PkeInput_Teardown(); + pke_scene_master_teardown(); + PkeLevel_Teardown(); PkeCamera_Teardown(); Physics_Teardown(); ECS_Teardown(); diff --git a/src/game.hpp b/src/game.hpp index 95d010c..8476ff0 100644 --- a/src/game.hpp +++ b/src/game.hpp @@ -1,7 +1,6 @@ #ifndef PKE_GAME_HPP #define PKE_GAME_HPP -#include "level-types.hpp" #include "window-types.hpp" void Game_Main(PKEWindowProperties windowProps, const char *executablePath); @@ -10,6 +9,6 @@ void Game_Tick(double delta); void Game_Teardown(); void Game_RecordImGui(); void Game_SaveSceneFile(const char *); -void Game_LoadSceneFile(PkeLevel *level, const char *); +void Game_LoadSceneFile(const char *); #endif /* PKE_GAME_HPP */ diff --git a/src/level-types.hpp b/src/level-types.hpp index 4de0f76..75bc6eb 100644 --- a/src/level-types.hpp +++ b/src/level-types.hpp @@ -1,19 +1,26 @@ #ifndef PKE_LEVEL_TYPES_HPP #define PKE_LEVEL_TYPES_HPP -#include "pk.h" -#include "camera.hpp" #include "components.hpp" +#include "vendor-glm-include.hpp" +#include "pk.h" -TypeSafeInt_constexpr(LevelHandle, uint16_t, 0xFFFF); +struct scene_instance { + glm::vec3 pos; // TODO + glm::vec3 rot; // TODO + glm::vec3 scale; // TODO + SceneHandle scene_handle; +}; -struct LvlCamArr : public pk_arr_t<CameraHandle>{}; +const uint8_t LEVEL_NAME_MAX_LEN = 16; +#define pke_level_name_printf_format "%16s" struct PkeLevel : public Entity_Base { + char *file_path = nullptr; struct pk_membucket *bkt = nullptr; - char name[16] = {'\0'}; + char name[LEVEL_NAME_MAX_LEN] = {'\0'}; LevelHandle levelHandle = LevelHandle_MAX; - LvlCamArr cameras; + pk_arr_t<scene_instance> scene_instances; }; #endif /* PKE_LEVEL_TYPES_HPP */ diff --git a/src/level.cpp b/src/level.cpp index 047363b..57faf80 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -1,87 +1,98 @@ #include "level.hpp" -#include "camera.hpp" +#include "bucketed-array.hpp" #include "ecs.hpp" #include "pk.h" -LevelHandle nextHandle = LevelHandle{0}; -long levelCount = 0; -constexpr long LEVEL_NAME_LENGTH = 16; -PkeLevel LEVELS[MAX_LEVEL_COUNT]; +struct level_mstr { + BucketContainer<PkeLevel, LevelHandle> bc; +} level_mstr; +void PkeLevel_Init() { + Buckets_Init(level_mstr.bc); +} + +void PkeLevel_Teardown() { + Buckets_Destroy(level_mstr.bc); +} + +/* PkeLevel *PkeLevel_Get_Inner(LevelHandle handle) { - for (long i = 0; i < MAX_LEVEL_COUNT; ++i) { - if (LEVELS[i].levelHandle == handle) { - return &LEVELS[i]; - } + if ( || handle.itemIndex >= level_mstr.bc.limits.itemIndex || (handle.bucketIndex == handle.bucketIndex) { } - return nullptr; + return &level_mstr.bc.buckets[handle.bucketIndex][handle.itemIndex]; } +*/ -void PkeLevel_Init() { - for (long i = 0; i < MAX_LEVEL_COUNT; ++i) { - new (&LEVELS[i]) PkeLevel{}; - pk_arr_reset(&LEVELS[i].cameras); +PkeLevel *PkeLevel_Create(const char *levelName) { + NULL_CHAR_ARR(safe_name, LEVEL_NAME_MAX_LEN + 1); + + size_t len = strlen(levelName); + size_t start = len <= (LEVEL_NAME_MAX_LEN - 1) ? 0 : len - (LEVEL_NAME_MAX_LEN - 1); + sprintf(safe_name, pke_level_name_printf_format, levelName + start); + + PkeLevel *lvl = PkeLevel_GetByName(levelName); + if (lvl != nullptr) { + fprintf(stderr, "[PkeLevel_Create] Failed to create new level: name already exists."); + return nullptr; } -} -LevelHandle PkeLevel_Create(const char *levelName) { - assert(levelCount < MAX_LEVEL_COUNT && "only MAX_LEVEL_COUNT levels can be loaded at once"); - levelCount += 1; + LevelHandle level_handle = Buckets_NewHandle(level_mstr.bc); + if (level_handle == LevelHandle_MAX) { + fprintf(stderr, "[PkeLevel_Create] Failed to create new level handle from BucketContainer"); + return nullptr; + } - PkeLevel *lvl = PkeLevel_Get_Inner(LevelHandle_MAX); - assert(lvl != nullptr && "max level count not reached, but failed to find a valid level slot"); + lvl = &level_mstr.bc[level_handle]; ECS_CreateEntity(lvl); if (lvl->bkt == nullptr) { lvl->bkt = pk_bucket_create(levelName, PK_DEFAULT_BUCKET_SIZE, false); } - lvl->levelHandle = nextHandle; - ++nextHandle; - auto len = strlen(levelName); - auto start = len <= (LEVEL_NAME_LENGTH - 1) ? 0 : len - (LEVEL_NAME_LENGTH - 1); - strncpy(lvl->name, levelName + start, LEVEL_NAME_LENGTH); - return lvl->levelHandle; + return lvl; } PkeLevel *PkeLevel_Get(LevelHandle handle) { - return PkeLevel_Get_Inner(handle); + return &level_mstr.bc[handle]; } -LevelHandle PkeLevel_GetHandle(const char *levelName) { - char safeName[LEVEL_NAME_LENGTH]; +PkeLevel *PkeLevel_GetByName(const char *levelName) { + NULL_CHAR_ARR(safe_name, LEVEL_NAME_MAX_LEN + 1); auto len = strlen(levelName); - auto start = len <= (LEVEL_NAME_LENGTH - 1) ? 0 : len - (LEVEL_NAME_LENGTH - 1); - strncpy(safeName, levelName + start, LEVEL_NAME_LENGTH); - for (long i = 0; i < MAX_LEVEL_COUNT; ++i) { - if (LEVELS[i].levelHandle != LevelHandle_MAX) { - if (strcmp(safeName, LEVELS[i].name)) { - return LEVELS[i].levelHandle; + auto start = len <= (LEVEL_NAME_MAX_LEN - 1) ? 0 : len - (LEVEL_NAME_MAX_LEN - 1); + sprintf(safe_name, pke_level_name_printf_format, levelName + start); + + pk_handle_bucket_index_T b; + pk_handle_item_index_T i, ii; + for (b = 0; b < level_mstr.bc.pkeHandle.bucketIndex; ++b) { + ii = level_mstr.bc.pkeHandle.bucketIndex == b ? level_mstr.bc.pkeHandle.itemIndex : level_mstr.bc.limits.itemIndex; + for (i = 0; i < ii; ++i) { + if (memcmp(safe_name, level_mstr.bc.buckets[b][i].name, LEVEL_NAME_MAX_LEN) == 0) { + return &level_mstr.bc.buckets[b][i]; } } } - return LevelHandle_MAX; + return nullptr; +} + +pk_handle_bucket_index_T pke_level_get_bucket_count() { + return level_mstr.bc.pkeHandle.bucketIndex + 1; } -void PkeLevel_RegisterCamera(LevelHandle levelHandle, CameraHandle cameraHandle) { - assert(levelHandle != LevelHandle_MAX); - assert(cameraHandle != CameraHandle_MAX); - PkeLevel *lvl = PkeLevel_Get_Inner(levelHandle); - assert(lvl != nullptr && "Failed to find level by requested LevelHandle"); - pk_arr_append(&lvl->cameras, &cameraHandle); +struct PkeLevel *pke_level_get_levels(pk_handle_bucket_index_T bucket_index, pk_handle_item_index_T *item_count) { + assert(bucket_index <= level_mstr.bc.pkeHandle.bucketIndex); + assert(item_count != nullptr); + *item_count = bucket_index == level_mstr.bc.pkeHandle.bucketIndex ? level_mstr.bc.pkeHandle.itemIndex : level_mstr.bc.limits.itemIndex; + return level_mstr.bc.buckets[bucket_index]; } void PkeLevel_Remove(LevelHandle handle) { - PkeLevel *lvl = PkeLevel_Get_Inner(handle); - assert(lvl != nullptr && "Failed to find level to remove by requested LevelHandle"); - levelCount -= 1; + PkeLevel *lvl = &level_mstr.bc[handle]; + assert(lvl == nullptr && "Failed to find level to remove by requested LevelHandle"); + // TODO mark bucket slot as open ECS_MarkForRemoval(lvl); - for (long i = 0; i < lvl->cameras.next; ++i) { - PkeCamera_Destroy(lvl->cameras[i]); - } - pk_arr_reset(&lvl->cameras); pk_bucket_reset(lvl->bkt); lvl->levelHandle = LevelHandle_MAX; } diff --git a/src/level.hpp b/src/level.hpp index 58cdcd3..1a07914 100644 --- a/src/level.hpp +++ b/src/level.hpp @@ -3,14 +3,13 @@ #include "level-types.hpp" -constexpr long MAX_LEVEL_COUNT = 16; -extern PkeLevel LEVELS[]; - void PkeLevel_Init(); -LevelHandle PkeLevel_Create(const char *levelName); +void PkeLevel_Teardown(); +PkeLevel *PkeLevel_Create(const char *levelName); PkeLevel *PkeLevel_Get(LevelHandle handle); -LevelHandle PkeLevel_GetHandle(const char *levelName); -void PkeLevel_RegisterCamera(LevelHandle levelHandle, CameraHandle cameraHandle); +PkeLevel *PkeLevel_GetByName(const char *levelName); +pk_handle_bucket_index_T pke_level_get_bucket_count(); +struct PkeLevel *pke_level_get_levels(pk_handle_bucket_index_T bucket_index, pk_handle_item_index_T *item_count); void PkeLevel_Remove(LevelHandle handle); #endif /* PKE_LEVEL_HPP */ diff --git a/src/scene-types.hpp b/src/scene-types.hpp new file mode 100644 index 0000000..655c621 --- /dev/null +++ b/src/scene-types.hpp @@ -0,0 +1,18 @@ +#ifndef PKE_SCENE_TYPES_HPP +#define PKE_SCENE_TYPES_HPP + +#include "pk.h" +#include "components.hpp" +#include "camera.hpp" + +const uint8_t SCENE_NAME_MAX_LEN = 16; +#define pke_scene_name_printf_format "%16s" + +struct pke_scene : public Entity_Base { + pk_str file_path = {}; + char name[SCENE_NAME_MAX_LEN] = {'\0'}; + SceneHandle scene_handle = SceneHandle_MAX; + pk_arr_t<CameraHandle> cameras; +}; + +#endif /* PKE_SCENE_TYPES_HPP */ diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 0000000..0e5a22c --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,96 @@ + +#include "scene.hpp" +#include "bucketed-array.hpp" +#include "ecs.hpp" +#include <cstring> + +struct pke_scene_master { + BucketContainer<pke_scene, SceneHandle> bc; +} scene_mstr; + +void pke_scene_master_init() { + Buckets_Init(scene_mstr.bc); +} + +void pke_scene_master_teardown() { + Buckets_Destroy(scene_mstr.bc); +} + +pke_scene *pke_scene_create(const char *scene_name) { + struct pke_scene *scene = pke_scene_get_by_name(scene_name); + if (scene != nullptr) { + fprintf(stderr, "[pke_scene_create] failed to create scene: pke_scene::name already in use."); + return nullptr; + } + SceneHandle scene_handle = Buckets_NewHandle(scene_mstr.bc); + if (scene_handle == SceneHandle_MAX) { + fprintf(stderr, "[pke_scene_create] failed to get new scene handle from BucketContainer."); + return nullptr; + } + scene = &scene_mstr.bc.buckets[scene_handle.bucketIndex][scene_handle.itemIndex]; + ECS_CreateEntity(scene); + + scene->scene_handle = scene_handle; + size_t offset = (strlen(scene_name) > SCENE_NAME_MAX_LEN ? strlen(scene_name) - SCENE_NAME_MAX_LEN : 0); + for (int i = 0; i < SCENE_NAME_MAX_LEN; ++i) { + scene->name[i] = scene_name[i + offset]; + } + return scene; +} + +struct pke_scene *pke_scene_get_by_handle(SceneHandle scene_handle) { + return &scene_mstr.bc.buckets[scene_handle.bucketIndex][scene_handle.itemIndex]; +} + +struct pke_scene *pke_scene_get_by_name(const char *scene_name) { + assert(scene_name != nullptr); + NULL_CHAR_ARR(safe_name, SCENE_NAME_MAX_LEN + 1); + strncpy(safe_name, scene_name, SCENE_NAME_MAX_LEN + 1); + pk_handle_bucket_index_T b; + pk_handle_item_index_T i, ii; + for (b = 0; b < scene_mstr.bc.pkeHandle.bucketIndex + 1; ++b) { + ii = scene_mstr.bc.pkeHandle.bucketIndex == b ? scene_mstr.bc.pkeHandle.itemIndex : scene_mstr.bc.limits.itemIndex; + for (i = 0; i < ii; ++i) { + if (memcmp(safe_name, scene_mstr.bc.buckets[b][i].name, PK_MIN(strlen(safe_name), SCENE_NAME_MAX_LEN)) == 0) { + return &scene_mstr.bc.buckets[b][i]; + } + } + } + return nullptr; +} + +pk_handle_bucket_index_T pke_scene_get_bucket_count() { + return scene_mstr.bc.pkeHandle.bucketIndex + 1; +} + +struct pke_scene *pke_scene_get_scenes(pk_handle_bucket_index_T bucket_index, pk_handle_item_index_T *item_count) { + assert(bucket_index <= scene_mstr.bc.pkeHandle.bucketIndex); + assert(item_count != nullptr); + *item_count = bucket_index == scene_mstr.bc.pkeHandle.bucketIndex ? scene_mstr.bc.pkeHandle.itemIndex : scene_mstr.bc.limits.itemIndex; + return scene_mstr.bc.buckets[bucket_index]; +} + +void pke_scene_remove(SceneHandle handle) { + pke_scene *scn = pke_scene_get_by_handle(handle); + assert(scn != nullptr && "[pke_scene_remove] Failed to find scene by requested SceneHandle"); + // TODO mark bucket slot as open + ECS_MarkForRemoval(scn); + for (long i = 0; i < scn->cameras.next; ++i) { + PkeCamera_Destroy(scn->cameras[i]); + } + if (scn->file_path.reserved > 0) { + pk_delete<char>(scn->file_path.val, scn->file_path.reserved); + } + scn->file_path = {}; + scn->name[0] = '\0'; + scn->scene_handle = SceneHandle_MAX; + pk_arr_reset(&scn->cameras); +} + +void pke_scene_register_camera(SceneHandle scene_handle, CameraHandle cameraHandle) { + assert(scene_handle != SceneHandle_MAX); + assert(cameraHandle != CameraHandle_MAX); + pke_scene *scene = pke_scene_get_by_handle(scene_handle); + assert(scene != nullptr && "Failed to find scene by requested SceneHandle"); + pk_arr_append(&scene->cameras, &cameraHandle); +} diff --git a/src/scene.hpp b/src/scene.hpp new file mode 100644 index 0000000..46d406c --- /dev/null +++ b/src/scene.hpp @@ -0,0 +1,20 @@ +#ifndef PKE_SCENE_HPP +#define PKE_SCENE_HPP + +#include "pk.h" +#include "scene-types.hpp" +#include "camera.hpp" + +void pke_scene_master_init(); +void pke_scene_master_teardown(); + +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_handle_bucket_index_T pke_scene_get_bucket_count(); +struct pke_scene *pke_scene_get_scenes(pk_handle_bucket_index_T bucket_index, pk_handle_item_index_T *item_count); +void pke_scene_remove(SceneHandle handle); + +void pke_scene_register_camera(SceneHandle scene_handle, CameraHandle cameraHandle); + +#endif /* PKE_SCENE_HPP */ |
