diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-04-02 20:46:41 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-04-02 20:46:41 -0400 |
| commit | a02c7589c6c9e902c59a632aa650635336fe648c (patch) | |
| tree | 8ec4800ff9f9effbd9141e02131123448679bc93 /src | |
| parent | fad302f7db146a78900f9b21dbbcd97761093c1b (diff) | |
pke: checkpoint: major serialization refactor
Diffstat (limited to 'src')
| -rw-r--r-- | src/game.cpp | 537 | ||||
| -rw-r--r-- | src/game.hpp | 2 | ||||
| -rw-r--r-- | src/project-settings.hpp | 2 | ||||
| -rw-r--r-- | src/project.cpp | 3 | ||||
| -rw-r--r-- | src/project.hpp | 2 | ||||
| -rw-r--r-- | src/serialization-camera.cpp | 153 | ||||
| -rw-r--r-- | src/serialization-camera.hpp | 11 | ||||
| -rw-r--r-- | src/serialization-component.cpp | 256 | ||||
| -rw-r--r-- | src/serialization-component.hpp | 15 | ||||
| -rw-r--r-- | src/serialization.cpp | 102 | ||||
| -rw-r--r-- | src/serialization.hpp | 71 |
11 files changed, 615 insertions, 539 deletions
diff --git a/src/game.cpp b/src/game.cpp index f7b539b..5e5e1b0 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2,6 +2,7 @@ #include "game.hpp" #include "camera.hpp" +#include "serialization-component.hpp" #include "components.hpp" #include "ecs.hpp" #include "entities.hpp" @@ -13,11 +14,13 @@ #include "imgui.h" #include "level-types.hpp" #include "level.hpp" +#include "math-helpers.hpp" #include "physics.hpp" #include "player-input.hpp" #include "plugins.hpp" #include "project.hpp" #include "scene.hpp" +#include "serialization.hpp" #include "static-ui.hpp" #include "thread-pool.hpp" #include "window.hpp" @@ -27,544 +30,10 @@ #include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h> #include <GLFW/glfw3.h> #include <cstring> -#include <iomanip> -#include <ostream> -#include <fstream> #include <thread> -const long readLineLength = 128; -char readLine[readLineLength]; -struct InstMapping { - InstanceHandle origHandle = InstanceHandle_MAX; - EntityHandle newEntHandle; - InstanceHandle newInstHandle; - InstPos newInstance{}; -}; -pk_arr_t<InstMapping> loadFileInstanceMappings{}; - const char *levelName = "demo-level"; -const char *PKE_FILE_BEGIN = ":PKFB:"; -const char *PKE_FILE_END = ":PKFE:"; -const char *PKE_FILE_VERSION = ":0:"; -const char *PKE_FILE_OBJ_END = ""; -const char *PKE_FILE_OBJ_INSTANCE = "Instance:"; -const char *PKE_FILE_OBJ_CAMERA = "Camera:"; - -const char *PKE_FILE_INSTANCE_HANDLE = "Inst::InstHandle: "; -const char *PKE_FILE_INSTANCE_ENTITY_HANDLE = "EntityHandle: "; -const char *PKE_FILE_INSTANCE_ENTITY_TYPE_CODE = "EntityTypeCode: "; -const char *PKE_FILE_INSTANCE_UUID = "UUID: "; -const char *PKE_FILE_INSTANCE_POS_POS = "InstPos::Pos: "; -const char *PKE_FILE_INSTANCE_POS_ROT = "InstPos::Rot: "; -const char *PKE_FILE_INSTANCE_POS_SCALE = "InstPos::Scale: "; -const char *PKE_FILE_INSTANCE_PHYSICS_MASS = "InstPos::Mass: "; -const char *PKE_FILE_INSTANCE_PHYSICS_COLLISION_LAYER = "InstPos::CollisionLayer: "; -const char *PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK = "InstPos::CollisionMask: "; -const char *PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE = "Inst::CollisionCallbackSignature: "; - -const char PKE_FILE_INSTANCE_SPECIAL_ENTITY_TYPE_CODE_CAMERA = 'C'; - -const char *PKE_FILE_CAMERA_POS = "Cam::Pos: "; -const char *PKE_FILE_CAMERA_ROT = "Cam::Rot: "; -const char *PKE_FILE_CAMERA_TARGET = "Cam::Target: "; -const char *PKE_FILE_CAMERA_TYPE = "Cam::Type: "; -const char *PKE_FILE_CAMERA_UUID = "Cam::UUID: "; -const char *PKE_FILE_CAMERA_ORIENTATION = "Cam::Orientation: "; -const char *PKE_FILE_CAMERA_INSTANCE_HANDLE = "Cam::InstanceHandle: "; -const char *PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE = "Cam::TargetInstanceHandle: "; -const char *PKE_FILE_CAMERA_IS_PRIMARY = "Cam::IsPrimary: "; - -void SerializeCamera(std::ostream &stream, const PkeCamera &cam) { - NULL_CHAR_ARR(handleStr, 23); - PkeCamera c{}; - if (cam.uuid != pk_uuid_zed && cam.uuid != pk_uuid_max) { - stream << PKE_FILE_CAMERA_UUID << cam.uuid << std::endl; - } - if (cam.type != c.type) { - stream << PKE_FILE_CAMERA_TYPE << int(static_cast<PkeCameraType_T>(cam.type)) << std::endl; - } - if (cam.view != c.view) { - stream << PKE_FILE_CAMERA_ORIENTATION << int(static_cast<PkeCameraView_T>(cam.view)) << std::endl; - } - if (cam.phys.instHandle != InstanceHandle_MAX) { - snprintf(handleStr, 22, "0x%08X 0x%08X", cam.phys.instHandle.bucketIndex, cam.phys.instHandle.itemIndex); - stream << PKE_FILE_CAMERA_INSTANCE_HANDLE << handleStr << std::endl; - } - if (cam.phys.targetInstHandle != InstanceHandle_MAX) { - snprintf(handleStr, 22, "0x%08X 0x%08X", cam.phys.targetInstHandle.bucketIndex, cam.phys.targetInstHandle.itemIndex); - stream << PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE << handleStr << std::endl; - } - if (cam.isPrimary != c.isPrimary) { - stream << PKE_FILE_CAMERA_IS_PRIMARY << cam.isPrimary << std::endl; - } - - CompInstance &comp = *ECS_GetInstance(cam.phys.instHandle); - InstPos baseInst{}; - baseInst.posRot = btTransform{}; - baseInst.posRot.setIdentity(); - baseInst.scale = btVector3(1, 1, 1); - btTransform trans; - comp.bt.motionState->getWorldTransform(trans); - btVector3 scale = comp.bt.rigidBody->getCollisionShape()->getLocalScaling(); - if (trans != baseInst.posRot) { - btVector3 pos = trans.getOrigin(); - btQuaternion rot = trans.getRotation(); - stream << PKE_FILE_INSTANCE_POS_POS << "[" - << std::setw(10) << pos[0] << "," - << std::setw(10) << pos[1] << "," - << std::setw(10) << pos[2] << "]" << std::endl - << PKE_FILE_INSTANCE_POS_ROT << "[" - << std::setw(10) << rot[0] << "," - << std::setw(10) << rot[1] << "," - << std::setw(10) << rot[2] << "," - << std::setw(10) << rot[3] << "]" << std::endl; - } - if (scale != baseInst.scale) - stream << PKE_FILE_INSTANCE_POS_SCALE << "[" - << std::setw(10) << scale[0] << "," - << std::setw(10) << scale[1] << "," - << std::setw(10) << scale[2] << "]" << std::endl; -} - -void SerializeInstance(std::ostream &stream, const CompInstance &comp) { - NULL_CHAR_ARR(handleStr, 23); - EntityType *et = nullptr; - if (comp.grBindsHandle != GrBindsHandle_MAX) { - et = EntityType_FindByEntityHandle(ECS_GetGrBinds(comp.grBindsHandle)->entHandle); - } - CompInstance c{}; - InstPos baseInst{}; - baseInst.posRot = btTransform{}; - baseInst.posRot.setIdentity(); - baseInst.scale = btVector3(1, 1, 1); - baseInst.mass = 1; - if (comp.entHandle != InstanceHandle_MAX) { - snprintf(handleStr, 22, "0x%08X 0x%08X", comp.entHandle.bucketIndex, comp.entHandle.itemIndex); - stream << PKE_FILE_INSTANCE_ENTITY_HANDLE << handleStr << std::endl; - } - if (comp.instanceHandle != InstanceHandle_MAX) { - snprintf(handleStr, 22, "0x%08X 0x%08X", comp.instanceHandle.bucketIndex, comp.instanceHandle.itemIndex); - stream << PKE_FILE_INSTANCE_HANDLE << handleStr << std::endl; - } - if (comp.uuid != pk_uuid_zed && comp.uuid != pk_uuid_max) { - stream << PKE_FILE_INSTANCE_UUID << comp.uuid << std::endl; - } - if (et != nullptr) { - stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << et->entityTypeCode.val << std::endl; - } else if (PkeCamera_Get(comp.entHandle)) { - stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << PKE_FILE_INSTANCE_SPECIAL_ENTITY_TYPE_CODE_CAMERA << std::endl; - } - - btTransform trans; - comp.bt.motionState->getWorldTransform(trans); - btVector3 scale = comp.bt.rigidBody->getCollisionShape()->getLocalScaling(); - btScalar mass = comp.bt.rigidBody->getMass(); - PhysicsCollision collisionLayer{static_cast<PhysicsCollision_T>(comp.bt.rigidBody->getBroadphaseProxy()->m_collisionFilterGroup)}; - PhysicsCollision collisionMask{static_cast<PhysicsCollision_T>(comp.bt.rigidBody->getBroadphaseProxy()->m_collisionFilterMask)}; - if (trans != baseInst.posRot) { - btVector3 pos = trans.getOrigin(); - btQuaternion rot = trans.getRotation(); - stream << PKE_FILE_INSTANCE_POS_POS << "[" - << std::setw(10) << pos[0] << "," - << std::setw(10) << pos[1] << "," - << std::setw(10) << pos[2] << "]" << std::endl - << PKE_FILE_INSTANCE_POS_ROT << "[" - << std::setw(10) << rot[0] << "," - << std::setw(10) << rot[1] << "," - << std::setw(10) << rot[2] << "," - << std::setw(10) << rot[3] << "]" << std::endl; - } - if (scale != baseInst.scale) - stream << PKE_FILE_INSTANCE_POS_SCALE << "[" - << std::setw(10) << scale[0] << "," - << std::setw(10) << scale[1] << "," - << std::setw(10) << scale[2] << "]" << std::endl; - if (mass != baseInst.mass) { - stream << PKE_FILE_INSTANCE_PHYSICS_MASS << mass << std::endl; - } - if (collisionLayer != c.physicsLayer) { - stream << PKE_FILE_INSTANCE_PHYSICS_COLLISION_LAYER << static_cast<PhysicsCollision_T>(collisionLayer) << std::endl; - } - if (collisionMask != c.physicsMask) { - stream << PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK << static_cast<PhysicsCollision_T>(collisionMask) << std::endl; - } - if (comp.collisionCallback.name[0] != '\0') { - stream << PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE << comp.collisionCallback.name << std::endl; - } -} - -bool FindFirstInstanceHandle(void *handle, void *mapping) { - InstMapping *inst_mapping = reinterpret_cast<InstMapping *>(mapping); - return inst_mapping->origHandle == *reinterpret_cast<InstanceHandle *>(handle); -} -void DeserializeCamera(pke_scene *scene, std::istream &stream) { - PkeCamera cam{}; - InstanceHandle instanceHandle = InstanceHandle_MAX; - InstanceHandle targetInstanceHandle = InstanceHandle_MAX; - while (stream.getline(readLine, readLineLength)) { - if (strcmp(readLine, PKE_FILE_OBJ_END) == 0) { - - int64_t instanceIndex = -1, targetInstanceIndex = -1; - - instanceIndex = pk_arr_find_first_index(&loadFileInstanceMappings, &instanceHandle, FindFirstInstanceHandle); - - if (targetInstanceHandle != InstanceHandle_MAX) { - targetInstanceIndex = pk_arr_find_first_index(&loadFileInstanceMappings, &targetInstanceHandle, FindFirstInstanceHandle); - } - - InstPos instPos; - if (instanceIndex == -1) { - instPos.mass = 1.f; - instPos.posRot.setIdentity(); - instPos.scale = btVector3(1.f, 1.f, 1.f); - fprintf(stdout, "[DeserializeCamera] Failed to find instance mapping. Is this an outdated parse?\n"); - } else { - instPos = loadFileInstanceMappings[instanceIndex].newInstance; - } - auto &rCam = PkeCamera_Register(cam.uuid, instPos); - rCam.type = cam.type; - rCam.view = cam.view; - rCam.isPrimary = cam.isPrimary; - rCam.phys.targetInstHandle = targetInstanceHandle; - pke_scene_register_camera(scene->scene_handle, rCam.camHandle); - if (targetInstanceIndex > -1) { - PkeCamera_TargetInstance(rCam.camHandle, ECS_GetInstance(loadFileInstanceMappings[targetInstanceIndex].newInstHandle)); - } - if (rCam.isPrimary == true) { - ActiveCamera = &rCam; - } - return; - } - if (strncmp(readLine, PKE_FILE_CAMERA_UUID, strlen(PKE_FILE_CAMERA_TYPE)) == 0) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_UUID); - (readLine + prefixLen) >> cam.uuid; - continue; - } - if (strncmp(readLine, PKE_FILE_CAMERA_TYPE, strlen(PKE_FILE_CAMERA_TYPE)) == 0) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_TYPE); - PkeCameraType_T handle_t; - STR2NUM_ERROR result = str2num(handle_t, readLine + prefixLen); - assert(result == STR2NUM_ERROR::SUCCESS); - cam.type = PkeCameraType{handle_t}; - continue; - } - if (strncmp(readLine, PKE_FILE_CAMERA_ORIENTATION, strlen(PKE_FILE_CAMERA_ORIENTATION)) == 0) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_ORIENTATION); - PkeCameraView_T handle_t; - STR2NUM_ERROR result = str2num(handle_t, readLine + prefixLen); - assert(result == STR2NUM_ERROR::SUCCESS); - cam.view = PkeCameraView{handle_t}; - continue; - } - if (strstr(readLine, PKE_FILE_CAMERA_INSTANCE_HANDLE)) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_INSTANCE_HANDLE); - readLine[prefixLen + 10] = '\0'; - STR2NUM_ERROR result1 = str2num(instanceHandle.bucketIndex, readLine + prefixLen); - STR2NUM_ERROR result2 = str2num(instanceHandle.itemIndex, readLine + prefixLen + 11); - assert(result1 == STR2NUM_ERROR::SUCCESS); - assert(result2 == STR2NUM_ERROR::SUCCESS); - // TODO add to global list - continue; - } - if (strstr(readLine, PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE)) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE); - readLine[prefixLen + 10] = '\0'; - STR2NUM_ERROR result1 = str2num(targetInstanceHandle.bucketIndex, readLine + prefixLen); - STR2NUM_ERROR result2 = str2num(targetInstanceHandle.itemIndex, readLine + prefixLen + 11); - assert(result1 == STR2NUM_ERROR::SUCCESS); - assert(result2 == STR2NUM_ERROR::SUCCESS); - // TODO find and set - continue; - } - if (strncmp(readLine, PKE_FILE_CAMERA_IS_PRIMARY, strlen(PKE_FILE_CAMERA_IS_PRIMARY)) == 0) { - uint64_t prefixLen = strlen(PKE_FILE_CAMERA_IS_PRIMARY); - uint8_t isPrimary; - STR2NUM_ERROR result = str2num(isPrimary, readLine + prefixLen); - assert(result == STR2NUM_ERROR::SUCCESS); - cam.isPrimary = bool(isPrimary); - continue; - } - } -} - -void DeserializeInstance(Entity_Base *parentEntity, std::istream &stream) { - CompInstance comp{}; - InstMapping mapping { - .origHandle = InstanceHandle_MAX, - .newEntHandle = EntityHandle_MAX, - .newInstHandle = InstanceHandle_MAX, - .newInstance = { - .posRot = {}, - .scale = btVector3(1.f, 1.f, 1.f), - .mass = 1.f, - }, - }; - mapping.newInstance.posRot.setIdentity(); - comp.collisionCallback.name[0] = '\0'; - NULL_CHAR_ARR(entTypeCode, 21); - while (stream.getline(readLine, readLineLength)) { - if (strstr(PKE_FILE_OBJ_END, readLine)) { - EntityType *etPtr = nullptr; - Entity_Base *entity = nullptr; - bool skipEntCreate = false; - if (strlen(entTypeCode) > 1) { - etPtr = EntityType_FindByTypeCode(entTypeCode); - if (etPtr == nullptr) { - fprintf(stdout, "[Game::DeserializeInstance] Unknown EntityTypeCode: \"%s\"\n", entTypeCode); - break; - } - } else if (strlen(entTypeCode) == 1) { - // handle internally - if (entTypeCode[0] == PKE_FILE_INSTANCE_SPECIAL_ENTITY_TYPE_CODE_CAMERA) { - skipEntCreate = true; - } - } else { - fprintf(stdout, "[Game::DeserializeInstance] Failed to create instance from save file. No EntTypeCode present.\n"); - break; - } - - if (skipEntCreate == false) { - if (etPtr != nullptr && etPtr->createInstanceCallback.func != nullptr) { - /* TODO 2025-03-27 JCB - * We have not yet defined what the appropriate callback signature - * for creating an entity instance is. - * What should be passed as arguments? What would need to be passed - * that couldn't be accessed globally? - * Consider changing this callback to trigger after creating a - * generic instance, rather than *creating* it. - */ - // typedef Entity_Base *CreateInst(); - // entity = reinterpret_cast<CreateInst*>(etPtr->createInstanceCallback.func)(); - fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback and we have not yet defined a valid function signature", __FILE__); - } else { - entity = EntityType_CreateGenericInstance(etPtr, parentEntity, &comp, &mapping.newInstance); - fprintf(stdout ,"[Game::DeserializeInstance] Debug: entTypeCode '%s' does not have a registered callback func to handle instance creation.\n", entTypeCode); - } - mapping.newEntHandle = entity->handle; - } - if (mapping.newEntHandle != EntityHandle_MAX) { - // TODO this is messy - pk_arr_t<CompInstance *> instances{}; - ECS_GetInstances(entity, instances); - assert(instances.next > 0); - mapping.newInstHandle = instances[0]->instanceHandle; - } - pk_arr_append(&loadFileInstanceMappings, &mapping); - break; - } - if (strstr(readLine, PKE_FILE_INSTANCE_ENTITY_HANDLE)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_ENTITY_HANDLE); - readLine[prefixLen + 10] = '\0'; - STR2NUM_ERROR result1 = str2num(comp.entHandle.bucketIndex, readLine + prefixLen); - STR2NUM_ERROR result2 = str2num(comp.entHandle.itemIndex, readLine + prefixLen + 11); - assert(result1 == STR2NUM_ERROR::SUCCESS); - assert(result2 == STR2NUM_ERROR::SUCCESS); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_HANDLE)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_HANDLE); - readLine[prefixLen + 10] = '\0'; - STR2NUM_ERROR result1 = str2num(mapping.origHandle.bucketIndex, readLine + prefixLen); - STR2NUM_ERROR result2 = str2num(mapping.origHandle.itemIndex, readLine + prefixLen + 11); - assert(result1 == STR2NUM_ERROR::SUCCESS); - assert(result2 == STR2NUM_ERROR::SUCCESS); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_UUID)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_UUID); - (readLine + prefixLen) >> comp.uuid ; - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_ENTITY_TYPE_CODE)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_ENTITY_TYPE_CODE); - strncpy(entTypeCode, readLine + prefixLen, 21); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_POS_POS)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_POS_POS); - char *startingChar = strchr(readLine + prefixLen, '[') + 1; - assert(startingChar != nullptr); - char *pEnd = nullptr; - long index = 0; - btVector3 pos; - do { - assert(index < 3); - STR2NUM_ERROR result = str2num(pos[index], startingChar, pEnd); - assert(result == STR2NUM_ERROR::SUCCESS); - startingChar = pEnd + 1; - ++index; - } while (*pEnd != ']'); - mapping.newInstance.posRot.setOrigin(pos); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_POS_ROT)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_POS_ROT); - char *startingChar = strchr(readLine + prefixLen, '[') + 1; - assert(startingChar != nullptr); - char *pEnd = nullptr; - long index = 0; - btQuaternion rot; - do { - assert(index < 4); - STR2NUM_ERROR result = str2num(rot[index], startingChar, pEnd); - assert(result == STR2NUM_ERROR::SUCCESS); - startingChar = pEnd + 1; - ++index; - } while (*pEnd != ']'); - mapping.newInstance.posRot.setRotation(rot); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_POS_SCALE)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_POS_SCALE); - char *startingChar = strchr(readLine + prefixLen, '[') + 1; - assert(startingChar != nullptr); - char *pEnd = nullptr; - long index = 0; - do { - assert(index < 3); - STR2NUM_ERROR result = str2num(mapping.newInstance.scale[index], startingChar, pEnd); - assert(result == STR2NUM_ERROR::SUCCESS); - startingChar = pEnd + 1; - ++index; - } while (*pEnd != ']'); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_PHYSICS_MASS)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_PHYSICS_MASS); - STR2NUM_ERROR result = str2num(mapping.newInstance.mass, readLine + prefixLen); - assert(result == STR2NUM_ERROR::SUCCESS); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_PHYSICS_COLLISION_LAYER)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_PHYSICS_COLLISION_LAYER); - PhysicsCollision_T val = static_cast<PhysicsCollision_T>(comp.physicsLayer); - STR2NUM_ERROR result = str2num(val, readLine + prefixLen); - comp.physicsLayer = PhysicsCollision{val}; - assert(result == STR2NUM_ERROR::SUCCESS); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_PHYSICS_COLLISION_MASK); - PhysicsCollision_T val = static_cast<PhysicsCollision_T>(comp.physicsMask); - STR2NUM_ERROR result = str2num(val, readLine + prefixLen); - comp.physicsMask = PhysicsCollision{val}; - assert(result == STR2NUM_ERROR::SUCCESS); - continue; - } - if (strstr(readLine, PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE)) { - uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_COLLISION_CALLBACK_SIGNATURE); - strncpy(comp.collisionCallback.name, readLine + prefixLen, 16); - continue; - } - } -} - -void Game_SaveSceneFile(const char *sceneFilePath) { - std::ostringstream stream{}; - bool failed = false; - - try { - stream << PKE_FILE_BEGIN << std::endl; - stream << PKE_FILE_VERSION << std::endl; - stream << "" << std::endl; - - pk_handle_bucket_index_T instanceBucketCount = ECS_GetInstances_BucketCount(); - for (pk_handle_bucket_index_T b = 0; b < instanceBucketCount; ++b) { - pk_handle_item_index_T count; - auto *instances = ECS_GetInstances(b, count); - for (pk_handle_item_index_T i = 0; i < count; ++i) { - const auto &instance = instances[i]; - if (instance.entHandle == EntityHandle_MAX) - continue; - if (instance.flags & COMPONENT_INSTANCE_FLAG_DO_NOT_SERIALIZE) { - continue; - } - stream << PKE_FILE_OBJ_INSTANCE << std::endl; - SerializeInstance(stream, instance); - stream << PKE_FILE_OBJ_END << std::endl; - } - } - - pk_handle_bucket_index_T cameraBucketCount = PkeCamera_GetBucketCount(); - for (pk_handle_bucket_index_T b = 0; b < cameraBucketCount; ++b) { - pk_handle_item_index_T count; - auto *cameras = PkeCamera_GetCameras(b, count); - for (pk_handle_item_index_T i = 0; i < count; ++i) { - const auto &cam = cameras[i]; - if (cam.handle == CameraHandle_MAX) - continue; - stream << PKE_FILE_OBJ_CAMERA << std::endl; - SerializeCamera(stream, cam); - stream << PKE_FILE_OBJ_END << std::endl; - } - } - - stream << PKE_FILE_END << std::endl; - } catch (std::exception &e) { - fprintf(stderr, "[%s][Game_SaveSceneFile] Failed to serialize scene file: %s\n", __FILE__, e.what()); - failed = false; - } catch (...) { - fprintf(stderr, "[%s][Game_SaveSceneFile] Failed to serialize scene file, uncaught exception.\n", __FILE__); - failed = false; - } - - if (failed == false) { - std::ofstream f(sceneFilePath); - if (!f.is_open()) { - failed = true; - } else { - f << stream.str(); - } - f.flush(); - f.close(); - } - - if (failed) { - NULL_CHAR_ARR(errFileName, 256); - strncpy(errFileName, sceneFilePath, 256); - strncpy(errFileName + strlen(sceneFilePath), ".err", 256 - strlen(sceneFilePath)); - std::ofstream errF(sceneFilePath); - if (errF.is_open()) { - errF << stream.str(); - errF.flush(); - errF.close(); - fprintf(stderr, "Failed to save scene file '%s', partial output saved to '%s'\n", sceneFilePath, errFileName); - } else { - fprintf(stderr, "Failed to save scene file '%s' and also failed to write failed output\n", 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); - 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(scn, f); - continue; - } - if (strcmp(PKE_FILE_OBJ_CAMERA, readLine) == 0) { - DeserializeCamera(scn, f); - continue; - } - } - - f.close(); - pk_arr_clear(&loadFileInstanceMappings); -} - const int64_t consoleBufferCount = 30; const int64_t consoleLineLength = 128; char consoleBuffer[consoleBufferCount][consoleLineLength]; diff --git a/src/game.hpp b/src/game.hpp index 8476ff0..b879364 100644 --- a/src/game.hpp +++ b/src/game.hpp @@ -8,7 +8,5 @@ void Game_Init(); void Game_Tick(double delta); void Game_Teardown(); void Game_RecordImGui(); -void Game_SaveSceneFile(const char *); -void Game_LoadSceneFile(const char *); #endif /* PKE_GAME_HPP */ diff --git a/src/project-settings.hpp b/src/project-settings.hpp index c1873c4..9154ed1 100644 --- a/src/project-settings.hpp +++ b/src/project-settings.hpp @@ -4,6 +4,8 @@ #include "dynamic-array.hpp" #include "pk.h" +const char* const PKE_PROJ_DEFAULT_FILENAME = "project.pptf"; + struct PkeProjectSettings { const char *defaultSceneName = "default"; DynArray<pk_str> scenes{16}; diff --git a/src/project.cpp b/src/project.cpp index c94451f..a27daba 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -5,6 +5,7 @@ #include "entities.hpp" #include "helpers.hpp" #include "font.hpp" +#include "project-settings.hpp" #include <fstream> #include <ostream> @@ -413,7 +414,7 @@ void PkeProject_Save(const char *filePath) { } stream << PKE_PROJ_FILE_END << std::endl; - } catch (std::exception e) { + } catch (std::exception &e) { fprintf(stderr, "[%s][PkeProject_Save] Failed to serialize project file: %s\n", __FILE__, e.what()); failed = false; } catch (...) { diff --git a/src/project.hpp b/src/project.hpp index ba678db..c1a321e 100644 --- a/src/project.hpp +++ b/src/project.hpp @@ -1,8 +1,6 @@ #ifndef PKE_PROJECT_HPP #define PKE_PROJECT_HPP -const char* const PKE_PROJ_DEFAULT_FILENAME = "project.pptf"; - void PkeProject_Load(const char *filePath = nullptr); void PkeProject_Save(const char *filePath = nullptr); diff --git a/src/serialization-camera.cpp b/src/serialization-camera.cpp new file mode 100644 index 0000000..abf404b --- /dev/null +++ b/src/serialization-camera.cpp @@ -0,0 +1,153 @@ + +#include "serialization-camera.hpp" + +#include "serialization-component.hpp" +#include "ecs.hpp" +#include "math-helpers.hpp" +#include "scene.hpp" + +#include <BulletCollision/CollisionShapes/btCollisionShape.h> + +#include "vendor-glm-include.hpp" + +void pke_serialize_camera(srlztn_serialize_helper *h, const PkeCamera *cam) { + NULL_CHAR_ARR(handleStr, 23); + PkeCamera c{}; + if (cam->uuid != pk_uuid_zed && cam->uuid != pk_uuid_max) { + h->o << SRLZTN_CAMERA_UUID << cam->uuid << std::endl; + } + if (cam->type != c.type) { + h->o << SRLZTN_CAMERA_TYPE << int(static_cast<PkeCameraType_T>(cam->type)) << std::endl; + } + if (cam->view != c.view) { + h->o << SRLZTN_CAMERA_ORIENTATION << int(static_cast<PkeCameraView_T>(cam->view)) << std::endl; + } + if (cam->phys.instHandle != InstanceHandle_MAX) { + snprintf(handleStr, 22, "0x%08X 0x%08X", cam->phys.instHandle.bucketIndex, cam->phys.instHandle.itemIndex); + h->o << SRLZTN_CAMERA_INSTANCE_HANDLE << handleStr << std::endl; + } + if (cam->phys.targetInstHandle != InstanceHandle_MAX) { + snprintf(handleStr, 22, "0x%08X 0x%08X", cam->phys.targetInstHandle.bucketIndex, cam->phys.targetInstHandle.itemIndex); + h->o << SRLZTN_CAMERA_TARGET_INSTANCE_UUID << handleStr << std::endl; + } + if (cam->isPrimary != c.isPrimary) { + h->o << SRLZTN_CAMERA_IS_PRIMARY << cam->isPrimary << std::endl; + } + + CompInstance &comp = *ECS_GetInstance(cam->phys.instHandle); + InstPos baseInst{}; + baseInst.posRot = btTransform{}; + baseInst.posRot.setIdentity(); + baseInst.scale = btVector3(1, 1, 1); + btTransform trans; + comp.bt.motionState->getWorldTransform(trans); + btVector3 scale = comp.bt.rigidBody->getCollisionShape()->getLocalScaling(); + btVector3 pos = trans.getOrigin(); + btQuaternion rot = trans.getRotation(); + + glm::vec3 glm_pos; + glm::quat quat_rot; + glm::vec3 glm_scale; + BulletToGlm(pos, glm_pos); + BulletToGlm(rot, quat_rot); + BulletToGlm(scale, glm_scale); + pke_serialize_inst_pos(h, glm_pos, quat_rot, glm_scale); +} + +bool FindFirstInstanceHandle(void *handle, void *mapping) { + srlztn_instance_mapping *inst_mapping = reinterpret_cast<srlztn_instance_mapping *>(mapping); + return inst_mapping->serialized_uuid == *reinterpret_cast<pk_uuid *>(handle); +} +void pke_deserialize_camera(srlztn_deserialize_helper *h) { + PK_STN_RES stn_res; + PkeCamera cam{}; + InstPos instPos; + InstanceHandle instanceHandle = InstanceHandle_MAX; + pk_uuid target_uuid = pk_uuid_zed; + glm::vec3 pos; + glm::quat quat_rot; + glm::vec3 scale; + instPos.mass = 1; + instPos.posRot.setIdentity(); + instPos.scale = btVector3(1, 1, 1); + while (h->i.getline(h->read_line, h->read_line_len)) { + if (strcmp(h->read_line, SRLZTN_OBJ_END) == 0) { + + int64_t targetInstanceIndex = -1; + + if (target_uuid != pk_uuid_zed) { + targetInstanceIndex = pk_arr_find_first_index(&h->mapping, &target_uuid, FindFirstInstanceHandle); + } + + btVector3 bt_pos; + btQuaternion bt_rot; + GlmToBullet(pos, bt_pos); + GlmToBullet(scale, instPos.scale); + GlmToBullet(quat_rot, bt_rot); + instPos.posRot.setOrigin(bt_pos); + instPos.posRot.setRotation(bt_rot); + auto &rCam = PkeCamera_Register(cam.uuid, instPos); + rCam.type = cam.type; + rCam.view = cam.view; + rCam.isPrimary = cam.isPrimary; + pke_scene_register_camera(h->scene->scene_handle, rCam.camHandle); + if (targetInstanceIndex > -1) { + PkeCamera_TargetInstance(rCam.camHandle, h->mapping[targetInstanceIndex].created_instance); + } + if (rCam.isPrimary == true) { + ActiveCamera = &rCam; + } + return; + } + if (pke_deserialize_inst_pos(h, pos, quat_rot, scale)) { + continue; + } + if (strncmp(h->read_line, SRLZTN_CAMERA_UUID, strlen(SRLZTN_CAMERA_TYPE)) == 0) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_UUID); + (h->read_line + prefixLen) >> cam.uuid; + continue; + } + if (strncmp(h->read_line, SRLZTN_CAMERA_TYPE, strlen(SRLZTN_CAMERA_TYPE)) == 0) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_TYPE); + stn_res = pk_stn(&cam.type, h->read_line + prefixLen); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing camera type from: '%s'", __FILE__, stn_res, h->read_line); + } + continue; + } + if (strncmp(h->read_line, SRLZTN_CAMERA_ORIENTATION, strlen(SRLZTN_CAMERA_ORIENTATION)) == 0) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_ORIENTATION); + stn_res = pk_stn(&cam.view, h->read_line + prefixLen); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing camera view from: '%s'", __FILE__, stn_res, h->read_line); + } + continue; + } + if (strstr(h->read_line, SRLZTN_CAMERA_INSTANCE_HANDLE)) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_INSTANCE_HANDLE); + h->read_line[prefixLen + 10] = '\0'; + stn_res = pk_stn(&instanceHandle.bucketIndex, h->read_line + prefixLen); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing camera instance handle from: '%s'", __FILE__, stn_res, h->read_line); + } + stn_res = pk_stn(&instanceHandle.itemIndex, h->read_line + prefixLen + 11); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing camera instance handle from: '%s'", __FILE__, stn_res, h->read_line); + } + continue; + } + if (strstr(h->read_line, SRLZTN_CAMERA_TARGET_INSTANCE_UUID)) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_TARGET_INSTANCE_UUID); + (h->read_line + prefixLen) >> cam.uuid; + continue; + } + if (strncmp(h->read_line, SRLZTN_CAMERA_IS_PRIMARY, strlen(SRLZTN_CAMERA_IS_PRIMARY)) == 0) { + uint64_t prefixLen = strlen(SRLZTN_CAMERA_IS_PRIMARY); + stn_res = pk_stn(&cam.isPrimary, h->read_line + prefixLen); + if (stn_res != PK_STN_RES_SUCCESS) { + fprintf(stderr, "[%s] Err '%u' parsing camera primary from: '%s'", __FILE__, stn_res, h->read_line); + } + continue; + } + } +} diff --git a/src/serialization-camera.hpp b/src/serialization-camera.hpp new file mode 100644 index 0000000..778febd --- /dev/null +++ b/src/serialization-camera.hpp @@ -0,0 +1,11 @@ +#ifndef PKE_SERIALIZATION_CAMERA_HPP +#define PKE_SERIALIZATION_CAMERA_HPP + +#include "serialization.hpp" +#include "camera.hpp" + +void pke_serialize_camera(srlztn_serialize_helper *helper, const PkeCamera *cam); + +void pke_deserialize_camera(srlztn_deserialize_helper *helper); + +#endif /* PKE_SERIALIZATION_CAMERA_HPP */ diff --git a/src/serialization-component.cpp b/src/serialization-component.cpp new file mode 100644 index 0000000..34eb758 --- /dev/null +++ b/src/serialization-component.cpp @@ -0,0 +1,256 @@ + +#include "serialization-component.hpp" + +#include "ecs.hpp" +#include "entities.hpp" +#include "serialization.hpp" +#include "math-helpers.hpp" + +#include "BulletCollision/CollisionShapes/btCollisionShape.h" + +#include "pk.h" + +#define SRLZTN_FLOAT_WIDTH 10 + +bool pke_serialize_inst_pos(srlztn_serialize_helper *h, const glm::vec3 pos, const glm::quat quat_rot, const glm::vec3 scale) { + if (pos != glm::vec3(0)) { + h->o << SRLZTN_POSROT_POS << "[" + << std::setw(SRLZTN_FLOAT_WIDTH) << pos[0] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << pos[1] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << pos[2] << "]" << std::endl; + } + if (quat_rot != glm::quat{}) { + h->o << SRLZTN_POSROT_ROT << "[" + << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[0] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[1] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[2] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << quat_rot[3] << "]" << std::endl; + } + if (scale != glm::vec3(1)) { + h->o << SRLZTN_POSROT_SCALE << "[" + << std::setw(SRLZTN_FLOAT_WIDTH) << scale[0] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << scale[1] << "," + << std::setw(SRLZTN_FLOAT_WIDTH) << scale[2] << "]" << std::endl; + } + return true; +} + +bool pke_deserialize_inst_pos(srlztn_deserialize_helper *h, glm::vec3 &pos, glm::quat &quat_rot, glm::vec3 &scale) { + const char *starting_char; + uint64_t prefix_len; + PK_STN_RES stn_res; + if (strstr(h->read_line, SRLZTN_POSROT_POS)) { + prefix_len = strlen(SRLZTN_POSROT_POS); + starting_char = strchr(h->read_line + prefix_len, '[') + 1; + assert(starting_char != nullptr); + char *pEnd = nullptr; + long index = 0; + do { + assert(index < 3); + stn_res = pk_stn_float_e(&pos[index], starting_char, &pEnd); + if (stn_res != PK_STN_RES_SUCCESS) return false; + starting_char = pEnd + 1; + ++index; + } while (*pEnd != ']'); + return true; + } + if (strstr(h->read_line, SRLZTN_POSROT_ROT)) { + prefix_len = strlen(SRLZTN_POSROT_ROT); + starting_char = strchr(h->read_line + prefix_len, '[') + 1; + assert(starting_char != nullptr); + char *pEnd = nullptr; + long index = 0; + do { + assert(index < 4); + stn_res = pk_stn_float_e(&quat_rot[index], starting_char, &pEnd); + if (stn_res != PK_STN_RES_SUCCESS) return false; + starting_char = pEnd + 1; + ++index; + } while (*pEnd != ']'); + return true; + } + if (strstr(h->read_line, SRLZTN_POSROT_SCALE)) { + prefix_len = strlen(SRLZTN_POSROT_SCALE); + starting_char = strchr(h->read_line + prefix_len, '[') + 1; + assert(starting_char != nullptr); + char *pEnd = nullptr; + long index = 0; + do { + assert(index < 3); + stn_res = pk_stn_float_e(&scale[index], starting_char, &pEnd); + if (stn_res != PK_STN_RES_SUCCESS) return false; + starting_char = pEnd + 1; + ++index; + } while (*pEnd != ']'); + return true; + } + return false; +} + +bool pke_serialize_instance(srlztn_serialize_helper *h, const CompInstance *comp) { + NULL_CHAR_ARR(handle_str, 23); + + EntityType *et = nullptr; + if (comp->grBindsHandle != GrBindsHandle_MAX) { + et = EntityType_FindByEntityHandle(ECS_GetGrBinds(comp->grBindsHandle)->entHandle); + } + + CompInstance c{}; + glm::vec3 pos; + glm::quat quat_rot; + glm::vec3 scale; + float mass; + PhysicsCollision collisionLayer; + PhysicsCollision collisionMask; + + { + mass = comp->bt.rigidBody->getMass(); + collisionLayer = PhysicsCollision{static_cast<PhysicsCollision_T>(comp->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterGroup)}; + collisionMask = PhysicsCollision{static_cast<PhysicsCollision_T>(comp->bt.rigidBody->getBroadphaseProxy()->m_collisionFilterMask)}; + + btTransform trans; + comp->bt.motionState->getWorldTransform(trans); + BulletToGlm(trans.getOrigin(), pos); + BulletToGlm(trans.getRotation(), quat_rot); + BulletToGlm(comp->bt.rigidBody->getCollisionShape()->getLocalScaling(), scale); + } + + if (comp->instanceHandle != InstanceHandle_MAX) { + snprintf(handle_str, 22, "0x%08X 0x%08X", comp->instanceHandle.bucketIndex, comp->instanceHandle.itemIndex); + h->o << SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE << handle_str << std::endl; + } + if (comp->entHandle != InstanceHandle_MAX) { + snprintf(handle_str, 22, "0x%08X 0x%08X", comp->entHandle.bucketIndex, comp->entHandle.itemIndex); + h->o << SRLZTN_INSTANCE_COMPONENT_HANDLE << handle_str << std::endl; + } + if (comp->uuid != pk_uuid_zed && comp->uuid != pk_uuid_max) { + h->o << SRLZTN_INSTANCE_COMPONENT_UUID << comp->uuid << std::endl; + } + if (et != nullptr) { + h->o << SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE << et->entityTypeCode.val << std::endl; + } + + pke_serialize_inst_pos(h, pos, quat_rot, scale); + + if (mass != 1) { + h->o << SRLZTN_INSTANCE_COMPONENT_MASS << mass << std::endl; + } + if (collisionLayer != c.physicsLayer) { + h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER << static_cast<PhysicsCollision_T>(collisionLayer) << std::endl; + } + if (collisionMask != c.physicsMask) { + h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK << static_cast<PhysicsCollision_T>(collisionMask) << std::endl; + } + if (comp->collisionCallback.name[0] != '\0') { + h->o << SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE << comp->collisionCallback.name << std::endl; + } + + return true; +} + +bool pke_deserialize_instance(srlztn_deserialize_helper *h) { + uint64_t prefix_len; + PK_STN_RES stn_res; + NULL_CHAR_ARR(handle_str, 21); + EntityType *et_ptr = nullptr; + float mass; + InstPos inst_pos; + CompInstance comp{}; + glm::vec3 pos; + glm::quat quat_rot; + glm::vec3 scale; + comp.collisionCallback.name[0] = '\0'; + while (h->i.getline(h->read_line, h->read_line_len)) { + if (strstr(SRLZTN_OBJ_END, h->read_line)) { + if (et_ptr == nullptr) { + fprintf(stdout, "[Game::DeserializeInstance] Unknown EntityTypeCode, skipping instance.\n"); + break; + } + btVector3 bt_pos; + btQuaternion bt_quat; + GlmToBullet(pos, bt_pos); + GlmToBullet(quat_rot, bt_quat); + GlmToBullet(scale, inst_pos.scale); + inst_pos.mass = mass; + inst_pos.posRot.setIdentity(); + inst_pos.posRot.setOrigin(bt_pos); + inst_pos.posRot.setRotation(bt_quat); + if (et_ptr->createInstanceCallback.func != nullptr) { + /* TODO 2025-03-27 JCB + * We have not yet defined what the appropriate callback signature + * for creating an entity instance is. + * What should be passed as arguments? What would need to be passed + * that couldn't be accessed globally? + * Consider changing this callback to trigger after creating a + * generic instance, rather than *creating* it. + * Also consider just requiring a generic instance for any given + * EntityType. + */ + // typedef Entity_Base *CreateInst(); + // entity = reinterpret_cast<CreateInst*>(et_ptr->createInstanceCallback.func)(); + fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback and we have not yet defined a valid function signature", __FILE__); + } else { + EntityType_CreateGenericInstance(et_ptr, h->scene, &comp, &inst_pos); + // fprintf(stdout ,"[Game::DeserializeInstance] Debug: entTypeCode '%s' does not have a registered callback func to handle instance creation.\n", entTypeCode); + } + return true; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE); + sprintf(handle_str, "%.10s%c%s", h->read_line + prefix_len, '\0', h->read_line + prefix_len + 10); + stn_res = pk_stn(&comp.entHandle.bucketIndex, handle_str, 16); + if (stn_res != PK_STN_RES_SUCCESS) return false; + stn_res = pk_stn(&comp.entHandle.itemIndex, handle_str + 11, 16); + if (stn_res != PK_STN_RES_SUCCESS) return false; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_HANDLE)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_HANDLE); + sprintf(handle_str, "%.10s%c%s", h->read_line + prefix_len, '\0', h->read_line + prefix_len + 10); + stn_res = pk_stn(&comp.instanceHandle.bucketIndex, handle_str, 16); + if (stn_res != PK_STN_RES_SUCCESS) return false; + stn_res = pk_stn(&comp.instanceHandle.itemIndex, handle_str + 11, 16); + if (stn_res != PK_STN_RES_SUCCESS) return false; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_UUID)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_UUID); + (h->read_line + prefix_len) >> comp.uuid ; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE); + if (strlen(h->read_line + prefix_len) > 1) { + et_ptr = EntityType_FindByTypeCode(h->read_line + prefix_len); + } + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_MASS)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_MASS); + stn_res = pk_stn(&mass, h->read_line + prefix_len); + if (stn_res != PK_STN_RES_SUCCESS) return false; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER); + stn_res = pk_stn(&comp.physicsLayer, h->read_line + prefix_len, 10); + if (stn_res != PK_STN_RES_SUCCESS) return false; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK); + stn_res = pk_stn(&comp.physicsMask, h->read_line + prefix_len, 10); + if (stn_res != PK_STN_RES_SUCCESS) return false; + continue; + } + if (strstr(h->read_line, SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE)) { + prefix_len = strlen(SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE); + strncpy(comp.collisionCallback.name, h->read_line + prefix_len, 16); + continue; + } + if (pke_deserialize_inst_pos(h, pos, quat_rot, scale)) { + continue; + } + } + return false; +} diff --git a/src/serialization-component.hpp b/src/serialization-component.hpp new file mode 100644 index 0000000..a01d235 --- /dev/null +++ b/src/serialization-component.hpp @@ -0,0 +1,15 @@ +#ifndef PKE_SERIALIZATION_COMPONENT_HPP +#define PKE_SERIALIZATION_COMPONENT_HPP + +#include "components.hpp" +#include "serialization.hpp" + +#include "vendor-glm-include.hpp" + +bool pke_serialize_inst_pos(srlztn_serialize_helper *h, const glm::vec3 pos, const glm::quat quat_rot, const glm::vec3 scale); +bool pke_deserialize_inst_pos(srlztn_deserialize_helper *h, glm::vec3 &pos, glm::quat &quat_rot, glm::vec3 &scale); + +bool pke_serialize_instance(srlztn_serialize_helper *h, const CompInstance *comp); +bool pke_deserialize_instance(srlztn_deserialize_helper *h); + +#endif /* PKE_SERIALIZATION_COMPONENT_HPP */ diff --git a/src/serialization.cpp b/src/serialization.cpp new file mode 100644 index 0000000..d7dd312 --- /dev/null +++ b/src/serialization.cpp @@ -0,0 +1,102 @@ + +#include "serialization.hpp" +#include "serialization-component.hpp" +#include "serialization-camera.hpp" +#include "camera.hpp" +#include "ecs.hpp" + +srlztn_serialize_helper *pke_serialize_init(pk_membucket *bkt) { + srlztn_serialize_helper *helper = pk_new<srlztn_serialize_helper>(bkt); + // TODO custom allocator + helper->o = {}; + helper->bkt = bkt; + return helper; +} + +srlztn_deserialize_helper *pke_deserialize_init(pk_membucket *bkt) { + srlztn_deserialize_helper *helper = pk_new<srlztn_deserialize_helper>(bkt); + helper->bkt = bkt; + helper->read_line = nullptr; + // TODO custom allocator + helper->i = {}; + helper->mapping = {bkt}; + return helper; +} + +void pke_serialize_teardown(srlztn_serialize_helper *helper) { + (void)helper; +} + +void pke_deserialize_teardown(srlztn_deserialize_helper *helper) { + (void)helper; +} + +void pke_serialize_file_project(srlztn_serialize_helper *h) { + (void)h; +} + +void pke_deserialize_file_project(srlztn_deserialize_helper *h) { + (void)h; +} + +void pke_serialize_file_scene(srlztn_serialize_helper *h) { + h->o << SRLZTN_FILE_BEGIN << std::endl; + h->o << SRLZTN_FILE_VERSION << std::endl; + h->o << "" << std::endl; + + pk_handle_bucket_index_T instanceBucketCount = ECS_GetInstances_BucketCount(); + for (pk_handle_bucket_index_T b = 0; b < instanceBucketCount; ++b) { + pk_handle_item_index_T count; + auto *instances = ECS_GetInstances(b, count); + for (pk_handle_item_index_T i = 0; i < count; ++i) { + const auto &instance = instances[i]; + if (instance.entHandle == EntityHandle_MAX) + continue; + if (instance.flags & COMPONENT_INSTANCE_FLAG_DO_NOT_SERIALIZE) { + continue; + } + h->o << SRLZTN_OBJ_INSTANCE << std::endl; + pke_serialize_instance(h, &instance); + h->o << SRLZTN_OBJ_END << std::endl; + } + } + + pk_handle_bucket_index_T cameraBucketCount = PkeCamera_GetBucketCount(); + for (pk_handle_bucket_index_T b = 0; b < cameraBucketCount; ++b) { + pk_handle_item_index_T count; + auto *cameras = PkeCamera_GetCameras(b, count); + for (pk_handle_item_index_T i = 0; i < count; ++i) { + const auto &cam = cameras[i]; + if (cam.handle == CameraHandle_MAX) + continue; + h->o << SRLZTN_OBJ_CAMERA << std::endl; + pke_serialize_camera(h, &cam); + h->o << SRLZTN_OBJ_END << std::endl; + } + } + + h->o << SRLZTN_FILE_END << std::endl; +} +void pke_deserialize_file_scene(srlztn_deserialize_helper *h) { + h->read_line = pk_new<char>(h->read_line_len, h->bkt); + memset(h->read_line, '\0', h->read_line_len); + + while (h->i.getline(h->read_line, h->read_line_len)) { + if (strcmp(SRLZTN_OBJ_INSTANCE, h->read_line) == 0) { + pke_deserialize_instance(h); + continue; + } + if (strcmp(SRLZTN_OBJ_CAMERA, h->read_line) == 0) { + pke_deserialize_camera(h); + continue; + } + } +} + +void pke_serialize_file_level(srlztn_serialize_helper *h) { + (void)h; +} +void pke_deserialize_file_level(srlztn_deserialize_helper *h) { + (void)h; +} + diff --git a/src/serialization.hpp b/src/serialization.hpp new file mode 100644 index 0000000..f4180e4 --- /dev/null +++ b/src/serialization.hpp @@ -0,0 +1,71 @@ +#ifndef PKE_SERIALIZATION_HPP +#define PKE_SERIALIZATION_HPP + +#include "pk.h" +#include "components.hpp" +#include "scene-types.hpp" + +inline const char* const SRLZTN_FILE_BEGIN = ":PKFB:"; +inline const char* const SRLZTN_FILE_END = ":PKFE:"; +inline const char* const SRLZTN_FILE_VERSION = ":0:"; + +inline const char* const SRLZTN_OBJ_END = ""; +inline const char* const SRLZTN_OBJ_INSTANCE = "Instance:"; +inline const char* const SRLZTN_OBJ_CAMERA = "Camera:"; + +inline const char* const SRLZTN_POSROT_POS = "Position: "; +inline const char* const SRLZTN_POSROT_ROT = "Rotation: "; +inline const char* const SRLZTN_POSROT_SCALE = "Scale: "; + +inline const char* const SRLZTN_INSTANCE_COMPONENT_HANDLE = "InstanceHandle: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_ENTITY_HANDLE = "EntityHandle: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_ENTITY_TYPE_CODE = "EntityTypeCode: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_UUID = "UUID: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_MASS = "Mass: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_COLLISION_LAYER = "CollisionLayer: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_COLLISION_MASK = "CollisionMask: "; +inline const char* const SRLZTN_INSTANCE_COMPONENT_COLLISION_CB_SIGNATURE = "CollisionCBSignature: "; + +inline const char* const SRLZTN_CAMERA_TARGET = "Target: "; +inline const char* const SRLZTN_CAMERA_TYPE = "Type: "; +inline const char* const SRLZTN_CAMERA_UUID = "UUID: "; +inline const char* const SRLZTN_CAMERA_ORIENTATION = "Orientation: "; +inline const char* const SRLZTN_CAMERA_INSTANCE_HANDLE = "InstanceHandle: "; +inline const char* const SRLZTN_CAMERA_TARGET_INSTANCE_UUID = "TargetUUID: "; +inline const char* const SRLZTN_CAMERA_IS_PRIMARY = "IsPrimary: "; + +struct srlztn_instance_mapping { + pk_uuid serialized_uuid = pk_uuid_zed; + Entity_Base *created_entity = nullptr; + CompInstance *created_instance = nullptr; +}; + +struct srlztn_serialize_helper { + pk_membucket *bkt; + std::ostringstream o; +}; + +struct srlztn_deserialize_helper { + size_t read_line_len = 256; + pke_scene *scene; + pk_membucket *bkt; + char *read_line; + std::istringstream i; + pk_arr_t<srlztn_instance_mapping> mapping; +}; + +srlztn_serialize_helper *pke_serialize_init(pk_membucket *bkt); +srlztn_deserialize_helper *pke_deserialize_init(pk_membucket *bkt); +void pke_serialize_teardown(srlztn_serialize_helper *helper); +void pke_deserialize_teardown(srlztn_deserialize_helper *helper); + +void pke_serialize_file_project(srlztn_serialize_helper *helper); +void pke_deserialize_file_project(srlztn_deserialize_helper *helper); + +void pke_serialize_file_scene(srlztn_serialize_helper *helper); +void pke_deserialize_file_scene(srlztn_deserialize_helper *helper); + +void pke_serialize_file_level(srlztn_serialize_helper *helper); +void pke_deserialize_file_level(srlztn_deserialize_helper *helper); + +#endif /* PKE_SERIALIZATION_HPP */ |
