summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile30
-rw-r--r--editor/editor-io.cpp77
-rw-r--r--editor/editor-io.hpp10
-rw-r--r--editor/editor-types.cpp4
-rw-r--r--editor/editor-types.hpp16
-rw-r--r--editor/editor.cpp17
-rw-r--r--src/game.cpp537
-rw-r--r--src/game.hpp2
-rw-r--r--src/project-settings.hpp2
-rw-r--r--src/project.cpp3
-rw-r--r--src/project.hpp2
-rw-r--r--src/serialization-camera.cpp153
-rw-r--r--src/serialization-camera.hpp11
-rw-r--r--src/serialization-component.cpp256
-rw-r--r--src/serialization-component.hpp15
-rw-r--r--src/serialization.cpp102
-rw-r--r--src/serialization.hpp71
17 files changed, 754 insertions, 554 deletions
diff --git a/Makefile b/Makefile
index 6334b18..5153ec4 100644
--- a/Makefile
+++ b/Makefile
@@ -183,6 +183,9 @@ $(DIR_BIN)/libpke.a: $(DIR_OBJ)/plugins.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/project-settings.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/project.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/scene.o
+$(DIR_BIN)/libpke.a: $(DIR_OBJ)/serialization.o
+$(DIR_BIN)/libpke.a: $(DIR_OBJ)/serialization-camera.o
+$(DIR_BIN)/libpke.a: $(DIR_OBJ)/serialization-component.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-cube.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-plane.o
$(DIR_BIN)/libpke.a: $(DIR_OBJ)/static-ui.o
@@ -217,6 +220,9 @@ $(DIR_DBG)/libpke.a: $(DIR_OBJ)/plugins.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/project-settings.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/project.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/scene.so
+$(DIR_DBG)/libpke.a: $(DIR_OBJ)/serialization.so
+$(DIR_DBG)/libpke.a: $(DIR_OBJ)/serialization-camera.so
+$(DIR_DBG)/libpke.a: $(DIR_OBJ)/serialization-component.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-cube.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-plane.so
$(DIR_DBG)/libpke.a: $(DIR_OBJ)/static-ui.so
@@ -230,6 +236,22 @@ $(DIR_DBG)/libpke.a:
ar rc $@ $(filter %.so,$^)
ranlib $@
+$(DIR_BIN)/libpke-editor.a: $(DIR_OBJ)/editor-main.o
+$(DIR_BIN)/libpke-editor.a: $(DIR_OBJ)/editor-types.o
+$(DIR_BIN)/libpke-editor.a: $(DIR_OBJ)/editor-io.o
+$(DIR_BIN)/libpke-editor.a: $(DIR_OBJ)/editor.o
+$(DIR_BIN)/libpke-editor.a:
+ ar rc $@ $(filter %.o,$^)
+ ranlib $@
+
+$(DIR_DBG)/libpke-editor.a: $(DIR_OBJ)/editor-main.so
+$(DIR_DBG)/libpke-editor.a: $(DIR_OBJ)/editor-types.so
+$(DIR_DBG)/libpke-editor.a: $(DIR_OBJ)/editor-io.so
+$(DIR_DBG)/libpke-editor.a: $(DIR_OBJ)/editor.so
+$(DIR_DBG)/libpke-editor.a:
+ ar rc $@ $(filter %.so,$^)
+ ranlib $@
+
$(DIR_BIN)/libpke-example.a: $(DIR_OBJ)/example.o
ar rc $@ $(filter %.o,$^)
ranlib $@
@@ -246,12 +268,12 @@ $(DIR_DBG)/libpke-test.a: $(DIR_OBJ)/pke-test-dummy.so
$(DIR_DBG)/libpke-test.a: $(DIR_OBJ)/pke-test-static-ui.so
ar rcs $@ $(filter %.so,$^)
-$(DIR_BIN)/pke-editor: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a
-$(DIR_BIN)/pke-editor: $(DIR_OBJ)/editor-main.o $(DIR_OBJ)/editor.o
+$(DIR_BIN)/pke-editor: $(DIR_BIN)/libpke-editor.a $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a
+$(DIR_BIN)/pke-editor:
$(CXX) -v -std=c++23 $(INCS) $^ /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a /home/pikum/build/msdfgen/dbg/msdfgen.a $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
-$(DIR_DBG)/pke-editor: $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a
-$(DIR_DBG)/pke-editor: $(DIR_OBJ)/editor-main.so $(DIR_OBJ)/editor.so
+$(DIR_DBG)/pke-editor: $(DIR_DBG)/libpke-editor.a $(DIR_DBG)/libpke.a $(DIR_DBG)/libImgui.a $(DIR_DBG)/libBullet3.a
+$(DIR_DBG)/pke-editor:
$(CXX) -v -std=c++23 $(INCS) $^ /home/pikum/build/msdf-atlas-gen/dbg/msdf-atlas-gen.a /home/pikum/build/msdfgen/dbg/msdfgen.a $(LDFLAGS) $(CXXFLAGS) -g -O0 -o $@
$(DIR_BIN)/pke-runtime: $(DIR_BIN)/libpke.a $(DIR_BIN)/libImgui.a $(DIR_BIN)/libBullet3.a
diff --git a/editor/editor-io.cpp b/editor/editor-io.cpp
new file mode 100644
index 0000000..1a80d2d
--- /dev/null
+++ b/editor/editor-io.cpp
@@ -0,0 +1,77 @@
+
+#include "editor-io.hpp"
+
+#include "game-settings.hpp"
+#include "scene.hpp"
+#include "serialization.hpp"
+
+#include <fstream>
+
+void pke_editor_scene_save(const char *file_path) {
+ std::ostringstream stream{};
+ srlztn_serialize_helper *helper = pke_serialize_init(pkeSettings.mem.bkt);
+ bool failed = false;
+
+ try {
+ pke_serialize_file_scene(helper);
+ } 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(file_path);
+ if (!f.is_open()) {
+ failed = true;
+ } else {
+ f << stream.str();
+ }
+ f.flush();
+ f.close();
+ }
+
+ if (failed) {
+ NULL_CHAR_ARR(errFileName, 256);
+ strncpy(errFileName, file_path, 256);
+ strncpy(errFileName + strlen(file_path), ".err", 256 - strlen(file_path));
+ std::ofstream errF(file_path);
+ 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", file_path, errFileName);
+ } else {
+ fprintf(stderr, "Failed to save scene file '%s' and also failed to write failed output\n", file_path);
+ }
+ }
+ pke_serialize_teardown(helper);
+}
+
+void pke_editor_scene_load(const char *file_path) {
+ std::ifstream f(file_path);
+ if (!f.is_open()) {
+ fprintf(stderr, "Failed to load requested scene file: '%s'\n", file_path);
+ return;
+ }
+ srlztn_deserialize_helper *helper = pke_deserialize_init(pkeSettings.mem.bkt);
+ // TODO scene name is in the file?
+ helper->scene = pke_scene_get_by_name(file_path);
+ if (helper->scene == nullptr) {
+ helper->scene = pke_scene_create(file_path);
+ }
+
+ pke_deserialize_file_scene(helper);
+
+ pke_deserialize_teardown(helper);
+
+ f.close();
+}
+
+void pke_editor_project_save(const char *file_path) {
+}
+
+void pke_editor_project_load(const char *file_path) {
+}
diff --git a/editor/editor-io.hpp b/editor/editor-io.hpp
new file mode 100644
index 0000000..07e9354
--- /dev/null
+++ b/editor/editor-io.hpp
@@ -0,0 +1,10 @@
+#ifndef PKE_EDITOR_EDITOR_IO_HPP
+#define PKE_EDITOR_EDITOR_IO_HPP
+
+void pke_editor_scene_save(const char *file_path);
+void pke_editor_scene_load(const char *file_path);
+
+void pke_editor_project_save(const char *file_path);
+void pke_editor_project_load(const char *file_path);
+
+#endif /* PKE_EDITOR_EDITOR_IO_HPP */
diff --git a/editor/editor-types.cpp b/editor/editor-types.cpp
new file mode 100644
index 0000000..b9d278a
--- /dev/null
+++ b/editor/editor-types.cpp
@@ -0,0 +1,4 @@
+
+#include "editor-types.hpp"
+
+struct editor_master editor_mstr;
diff --git a/editor/editor-types.hpp b/editor/editor-types.hpp
new file mode 100644
index 0000000..ff8239b
--- /dev/null
+++ b/editor/editor-types.hpp
@@ -0,0 +1,16 @@
+#ifndef PKE_EDITOR_EDITOR_TYPES_HPP
+#define PKE_EDITOR_EDITOR_TYPES_HPP
+
+#include "scene-types.hpp"
+#include "pk.h"
+
+// TODO editor state (scene vs level)
+struct editor_master {
+ pke_scene *active_scene;
+ pk_str target_scene_path;
+ bool shouldLoadScene = false;
+ bool shouldSaveScene = false;
+};
+extern struct editor_master editor_mstr;
+
+#endif /* PKE_EDITOR_EDITOR_TYPES_HPP */
diff --git a/editor/editor.cpp b/editor/editor.cpp
index af05781..48e5cc1 100644
--- a/editor/editor.cpp
+++ b/editor/editor.cpp
@@ -1,5 +1,7 @@
#include "editor.hpp"
+#include "editor-io.hpp"
+#include "editor-types.hpp"
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
#include "asset-manager.hpp"
@@ -16,6 +18,7 @@
#include "msdfgen.h"
#include "player-input.hpp"
#include "plugins.hpp"
+#include "project-settings.hpp"
#include "project.hpp"
#include "scene.hpp"
#include "static-ui.hpp"
@@ -54,14 +57,6 @@ const char* const dbgCtrl_ClearSelection = "debug-clear-selection";
const char* const dbgCtrl_DeleteSelectedItem = "debug-delete-selected-item";
const char* const dbgCtrl_ImGui_Toggle = "debug-imgui-toggle";
-// TODO editor state (scene vs level)
-struct editor_master {
- pke_scene *active_scene;
- pk_str target_scene_path;
- bool shouldLoadScene = false;
- bool shouldSaveScene = false;
-} editor_mstr;
-
ThreadPoolHandle threadPoolHandle = ThreadPoolHandle_MAX;
InputActionSetHandle debugControlsHandle = InputActionSetHandle_MAX;
@@ -194,7 +189,7 @@ void PkeEditor_Tick(double delta) {
} else {
sprintf(file_path, "%.16s", editor_mstr.active_scene->name);
}
- Game_SaveSceneFile(file_path);
+ pke_editor_scene_save(file_path);
shouldRebuildProjectDir = true;
}
if (editor_mstr.target_scene_path.val != nullptr) {
@@ -202,7 +197,7 @@ void PkeEditor_Tick(double delta) {
pke_scene_remove(editor_mstr.active_scene->scene_handle);
}
ActiveCamera = &NullCamera;
- Game_LoadSceneFile(editor_mstr.target_scene_path.val);
+ pke_editor_scene_load(editor_mstr.target_scene_path.val);
std::filesystem::path p(editor_mstr.target_scene_path.val);
editor_mstr.active_scene = pke_scene_get_by_name(p.stem().c_str());
if (editor_mstr.active_scene) {
@@ -318,7 +313,7 @@ void PkeEditor_Tick(double delta) {
// reinterpret_cast<void(*)()>(et->createInstanceCallback.func)();
fprintf(stderr, "[%s] Attempted to call EntityType::createInstanceCallback without a function signature", __FILE__);
} else {
- EntityType_CreateGenericInstance(et, PkeLevel_Get(pkeSettings.rt.activeLevel), nullptr);
+ EntityType_CreateGenericInstance(et, editor_mstr.active_scene, nullptr);
}
}
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 */