summaryrefslogtreecommitdiff
path: root/src/game.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2024-01-18 22:37:02 -0500
committerJonathan Bradley <jcb@pikum.xyz>2024-01-18 22:37:02 -0500
commit1b48d1382d2d57a822201f34743a51813798b348 (patch)
tree612672a4be654b38f3b44580f85e4f0637952512 /src/game.cpp
parent2e680ebd77236f7b62b9ded1b083c86f9e13b1c8 (diff)
camera checkpoint - large refactor for attempting to let physics own camera position
Diffstat (limited to 'src/game.cpp')
-rw-r--r--src/game.cpp276
1 files changed, 147 insertions, 129 deletions
diff --git a/src/game.cpp b/src/game.cpp
index 4390202..565f1ce 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,9 +1,11 @@
#include "game.hpp"
+#include "array.hpp"
#include "camera.hpp"
#include "components.hpp"
#include "dynamic-array.hpp"
+#include "ecs.hpp"
#include "entities.hpp"
#include "game-settings.hpp"
#include "helpers.hpp"
@@ -32,6 +34,13 @@
const long readLineLength = 128;
char readLine[readLineLength];
+struct InstMapping {
+ InstanceHandle origHandle = InstanceHandle_MAX;
+ Entity_Base *newEnt = nullptr;
+ CompInstance *newInst = nullptr;
+ InstPos newInstance{};
+};
+PkeArray<InstMapping> loadFileInstanceMappings{};
const char *levelName = "demo-level";
@@ -42,6 +51,7 @@ 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_POS_POS = "InstPos::Pos: ";
@@ -52,61 +62,64 @@ 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_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::ostringstream &stream, const PkeCamera &cam) {
+ NULL_CHAR_ARR(handleStr, 19);
PkeCamera c{};
- if (cam.pos != c.pos) {
- stream << PKE_FILE_CAMERA_POS << "["
- << std::setw(10) << cam.pos[0] << ","
- << std::setw(10) << cam.pos[1] << ","
- << std::setw(10) << cam.pos[2] << "]" << std::endl;
- }
- if (cam.rot != c.rot) {
- stream << PKE_FILE_CAMERA_ROT << "["
- << std::setw(10) << cam.rot[0] << ","
- << std::setw(10) << cam.rot[1] << ","
- << std::setw(10) << cam.rot[2] << ","
- << std::setw(10) << cam.rot[3] << "]" << std::endl;
- }
- if (cam.target != c.target) {
- stream << PKE_FILE_CAMERA_TARGET << "["
- << std::setw(10) << cam.target[0] << ","
- << std::setw(10) << cam.target[1] << ","
- << std::setw(10) << cam.target[2] << "]" << 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.inst != c.phys.inst && cam.phys.inst != CAFE_BABE(CompInstance)) {
+ snprintf(handleStr, 19, "0x%016lX", cam.phys.inst->instanceHandle.hash);
+ stream << PKE_FILE_CAMERA_INSTANCE_HANDLE << handleStr << std::endl;
+ }
+ if (cam.phys.targetInst != c.phys.targetInst && cam.phys.targetInst != CAFE_BABE(CompInstance)) {
+ snprintf(handleStr, 19, "0x%016lX", cam.phys.targetInst->instanceHandle.hash);
+ 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;
}
}
void SerializeInstance(std::ostringstream &stream, const CompInstance &comp) {
- char handleStr[19] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
- snprintf(handleStr, 19, "0x%016lX", comp.entHandle.hash);
- assert(comp.grBindsHandle != GrBindsHandle_MAX && "instance exists without a GrBinds");
- CompGrBinds *instGrBinds = ECS_GetGrBinds(comp.grBindsHandle);
- EntityType *et = EntityType_FindByEntityHandle(instGrBinds->entHandle);
- assert(et != nullptr && "instance had a GrBinds, but no EntityType could be found");
+ NULL_CHAR_ARR(handleStr, 19);
+ 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 != c.entHandle)
+ if (comp.entHandle != c.entHandle) {
+ snprintf(handleStr, 19, "0x%016lX", comp.entHandle.hash);
stream << PKE_FILE_INSTANCE_ENTITY_HANDLE << handleStr << std::endl;
- stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << et->entityTypeCode << std::endl;
+ }
+ if (comp.entHandle != c.entHandle) {
+ snprintf(handleStr, 19, "0x%016lX", comp.instanceHandle.hash);
+ stream << PKE_FILE_INSTANCE_HANDLE << handleStr << std::endl;
+ }
+ if (et != nullptr) {
+ stream << PKE_FILE_INSTANCE_ENTITY_TYPE_CODE << et->entityTypeCode << 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);
@@ -146,71 +159,46 @@ void SerializeInstance(std::ostringstream &stream, const CompInstance &comp) {
}
}
+bool FindFirstInstanceHandle(const InstMapping &mapping, const InstanceHandle handle) {
+ return mapping.origHandle == handle;
+}
void ParseCamera(PkeLevel *level, std::ifstream &stream) {
PkeCamera cam{};
+ InstanceHandle instanceHandle = InstanceHandle_MAX;
+ InstanceHandle targetInstanceHandle = InstanceHandle_MAX;
while (stream.getline(readLine, readLineLength)) {
if (strcmp(readLine, PKE_FILE_OBJ_END) == 0) {
- InstPos instPos{};
- btVector3 pos;
- btQuaternion quat;
- GlmToBullet(cam.pos, pos);
- GlmToBullet(cam.rot, quat);
- instPos.mass = 1.f;
- instPos.posRot.setOrigin(pos);
- instPos.posRot.setRotation(quat);
+
+ int64_t instanceIndex = -1, targetInstanceIndex = -1;
+
+ instanceIndex = PkeArray_FindFirstIndex<InstMapping, InstanceHandle>(&loadFileInstanceMappings, FindFirstInstanceHandle, instanceHandle);
+
+ if (targetInstanceHandle != InstanceHandle_MAX) {
+ targetInstanceIndex = PkeArray_FindFirstIndex<InstMapping, InstanceHandle>(&loadFileInstanceMappings, FindFirstInstanceHandle, targetInstanceHandle);
+ }
+
+ InstPos instPos;
+ if (instanceIndex == -1) {
+ instPos.mass = 1.f;
+ instPos.posRot.setIdentity();
+ instPos.scale = btVector3(1.f, 1.f, 1.f);
+ fprintf(stdout, "[ParseCamera] Failed to find instance mapping. Is this an outdated parse?");
+ } else {
+ instPos = loadFileInstanceMappings.data[instanceIndex].newInstance;
+ }
auto &rCam = PkeCamera_Register(instPos);
- rCam.target = cam.target;
rCam.type = cam.type;
rCam.view = cam.view;
rCam.isPrimary = cam.isPrimary;
PkeLevel_RegisterCamera(level->levelHandle, rCam.camHandle);
+ if (targetInstanceIndex > -1) {
+ PkeCamera_AttachToInstance(rCam.camHandle, loadFileInstanceMappings.data[targetInstanceIndex].newInst);
+ }
if (rCam.isPrimary == true) {
ActiveCamera = &rCam;
}
return;
}
- if (strncmp(readLine, PKE_FILE_CAMERA_POS, strlen(PKE_FILE_CAMERA_POS)) == 0) {
- uint64_t prefixLen = strlen(PKE_FILE_CAMERA_POS);
- char *startingChar = strchr(readLine + prefixLen, '[') + 1;
- assert(startingChar != nullptr);
- char *pEnd = nullptr;
- long index = 0;
- do {
- assert(index < 3);
- STR2NUM_ERROR result = str2num(cam.pos[index], startingChar, pEnd);
- assert(result == STR2NUM_ERROR::SUCCESS);
- startingChar = pEnd + 1;
- ++index;
- } while (*pEnd != ']');
- }
- if (strncmp(readLine, PKE_FILE_CAMERA_ROT, strlen(PKE_FILE_CAMERA_ROT)) == 0) {
- uint64_t prefixLen = strlen(PKE_FILE_CAMERA_ROT);
- char *startingChar = strchr(readLine + prefixLen, '[') + 1;
- assert(startingChar != nullptr);
- char *pEnd = nullptr;
- long index = 0;
- do {
- assert(index < 4);
- STR2NUM_ERROR result = str2num(cam.rot[index], startingChar, pEnd);
- assert(result == STR2NUM_ERROR::SUCCESS);
- startingChar = pEnd + 1;
- ++index;
- } while (*pEnd != ']');
- }
- if (strncmp(readLine, PKE_FILE_CAMERA_TARGET, strlen(PKE_FILE_CAMERA_TARGET)) == 0) {
- uint64_t prefixLen = strlen(PKE_FILE_CAMERA_TARGET);
- char *startingChar = strchr(readLine + prefixLen, '[') + 1;
- assert(startingChar != nullptr);
- char *pEnd = nullptr;
- long index = 0;
- do {
- assert(index < 3);
- STR2NUM_ERROR result = str2num(cam.target[index], startingChar, pEnd);
- assert(result == STR2NUM_ERROR::SUCCESS);
- startingChar = pEnd + 1;
- ++index;
- } while (*pEnd != ']');
- }
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;
@@ -227,6 +215,18 @@ void ParseCamera(PkeLevel *level, std::ifstream &stream) {
cam.view = PkeCameraView{handle_t};
continue;
}
+ if (strstr(readLine, PKE_FILE_CAMERA_INSTANCE_HANDLE)) {
+ uint64_t prefixLen = strlen(PKE_FILE_CAMERA_INSTANCE_HANDLE);
+ STR2NUM_ERROR result = str2num(instanceHandle.hash, readLine + prefixLen);
+ assert(result == STR2NUM_ERROR::SUCCESS);
+ continue;
+ }
+ if (strstr(readLine, PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE)) {
+ uint64_t prefixLen = strlen(PKE_FILE_CAMERA_TARGET_INSTANCE_HANDLE);
+ STR2NUM_ERROR result = str2num(targetInstanceHandle.hash, readLine + prefixLen);
+ assert(result == STR2NUM_ERROR::SUCCESS);
+ 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;
@@ -240,31 +240,53 @@ void ParseCamera(PkeLevel *level, std::ifstream &stream) {
void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
CompInstance comp{};
- InstPos instPos{};
- instPos.posRot = btTransform{};
- instPos.posRot.setIdentity();
- instPos.scale = btVector3(1, 1, 1);
- instPos.mass = 1.f;
+ InstMapping mapping {
+ .origHandle = InstanceHandle_MAX,
+ .newInstance = {
+ .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)) {
- if (entTypeCode[0] == '\0') {
+ EntityType *etPtr = nullptr;
+ bool skipEntCreate = false;
+ if (strlen(entTypeCode) > 1) {
+ etPtr = EntityType_FindByTypeCode(entTypeCode);
+ if (etPtr == nullptr) {
+ fprintf(stdout, "[Game::ParseInstance] 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::ParseInstance] Failed to create instance from save file. No EntTypeCode present.\n");
break;
}
- auto *etPtr = EntityType_FindByTypeCode(entTypeCode);
- if (etPtr == nullptr) {
- fprintf(stdout, "[Game::ParseInstance] Failed to create instance from save file. Unknown EntityTypeCode: \"%s\"\n", entTypeCode);
- break;
- }
- if (etPtr->createInstanceCallback.func != nullptr) {
- reinterpret_cast<void(*)()>(etPtr->createInstanceCallback.func)();
- } else {
- EntityType_CreateGenericInstance(etPtr, parentEntity, &comp, &instPos);
- fprintf(stdout ,"[Game::ParseInstance] No callback func to create instance.");
+ if (skipEntCreate == false) {
+ if (etPtr != nullptr && etPtr->createInstanceCallback.func != nullptr) {
+ typedef Entity_Base *CreateInst();
+ mapping.newEnt = reinterpret_cast<CreateInst*>(etPtr->createInstanceCallback.func)();
+ } else {
+ mapping.newEnt = EntityType_CreateGenericInstance(etPtr, parentEntity, &comp, &mapping.newInstance);
+ fprintf(stdout ,"[Game::ParseInstance] No callback func to create instance.");
+ }
}
+ if (mapping.newEnt != nullptr) {
+ // TODO this is messy
+ PkeArray<CompInstance *> instances{};
+ ECS_GetInstances(mapping.newEnt, instances);
+ assert(instances.next > 0);
+ mapping.newInst = instances.data[0];
+ }
+ PkeArray_Add(&loadFileInstanceMappings, mapping);
break;
}
if (strstr(readLine, PKE_FILE_INSTANCE_ENTITY_HANDLE)) {
@@ -273,6 +295,12 @@ void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
assert(result == STR2NUM_ERROR::SUCCESS);
continue;
}
+ if (strstr(readLine, PKE_FILE_INSTANCE_HANDLE)) {
+ uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_HANDLE);
+ STR2NUM_ERROR result = str2num(mapping.origHandle.hash, readLine + prefixLen);
+ assert(result == STR2NUM_ERROR::SUCCESS);
+ 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);
@@ -292,7 +320,7 @@ void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
startingChar = pEnd + 1;
++index;
} while (*pEnd != ']');
- instPos.posRot.setOrigin(pos);
+ mapping.newInstance.posRot.setOrigin(pos);
continue;
}
if (strstr(readLine, PKE_FILE_INSTANCE_POS_ROT)) {
@@ -309,7 +337,7 @@ void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
startingChar = pEnd + 1;
++index;
} while (*pEnd != ']');
- instPos.posRot.setRotation(rot);
+ mapping.newInstance.posRot.setRotation(rot);
continue;
}
if (strstr(readLine, PKE_FILE_INSTANCE_POS_SCALE)) {
@@ -320,7 +348,7 @@ void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
long index = 0;
do {
assert(index < 3);
- STR2NUM_ERROR result = str2num(instPos.scale[index], startingChar, pEnd);
+ STR2NUM_ERROR result = str2num(mapping.newInstance.scale[index], startingChar, pEnd);
assert(result == STR2NUM_ERROR::SUCCESS);
startingChar = pEnd + 1;
++index;
@@ -329,7 +357,7 @@ void ParseInstance(Entity_Base *parentEntity, std::ifstream &stream) {
}
if (strstr(readLine, PKE_FILE_INSTANCE_PHYSICS_MASS)) {
uint64_t prefixLen = strlen(PKE_FILE_INSTANCE_PHYSICS_MASS);
- STR2NUM_ERROR result = str2num(instPos.mass, readLine + prefixLen);
+ STR2NUM_ERROR result = str2num(mapping.newInstance.mass, readLine + prefixLen);
assert(result == STR2NUM_ERROR::SUCCESS);
continue;
}
@@ -366,20 +394,6 @@ void Game_SaveSceneFile(const char *sceneFilePath) {
stream << PKE_FILE_VERSION << std::endl;
stream << "" << std::endl;
- int64_t cameraBucketCount = PkeCamera_GetBucketCount();
- for (long b = 0; b < cameraBucketCount; ++b) {
- int64_t count;
- auto *cameras = PkeCamera_GetCameras(b, count);
- for (long 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;
- }
- }
-
int64_t instanceBucketCount = ECS_GetInstances_BucketCount();
for (long b = 0; b < instanceBucketCount; ++b) {
uint64_t count;
@@ -388,23 +402,26 @@ void Game_SaveSceneFile(const char *sceneFilePath) {
const auto &instance = instances[i];
if (instance.entHandle == EntityHandle_MAX)
continue;
- /* 2024-01-16 - JCB - TODO Checking the GRBinds is currently
- * set so that we don't serialize cameras. There's probably
- * a better way to do this - or cameras should be refactored
- * to rely on the instance position?
- * I expect this to become an issue later, but I'm not aware
- * of any use-cases at the moment. Leaving this as-is until
- * we know what those use-cases are so we can write a valid
- * story to handle the task.
- */
- if (instance.grBindsHandle == GrBindsHandle_MAX)
- continue;
stream << PKE_FILE_OBJ_INSTANCE << std::endl;
SerializeInstance(stream, instance);
stream << PKE_FILE_OBJ_END << std::endl;
}
}
+ int64_t cameraBucketCount = PkeCamera_GetBucketCount();
+ for (long b = 0; b < cameraBucketCount; ++b) {
+ int64_t count;
+ auto *cameras = PkeCamera_GetCameras(b, count);
+ for (long 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 (...) {
@@ -448,17 +465,18 @@ void Game_LoadSceneFile(PkeLevel *level, const char *sceneFilePath) {
memset(readLine, '\0', readLineLength);
while (f.getline(readLine, readLineLength)) {
- if (strcmp(PKE_FILE_OBJ_CAMERA, readLine) == 0) {
- ParseCamera(level, f);
- continue;
- }
if (strcmp(PKE_FILE_OBJ_INSTANCE, readLine) == 0) {
ParseInstance(level, f);
continue;
}
+ if (strcmp(PKE_FILE_OBJ_CAMERA, readLine) == 0) {
+ ParseCamera(level, f);
+ continue;
+ }
}
f.close();
+ PkeArray_SoftReset(&loadFileInstanceMappings);
}
const uint64_t consoleBufferCount = 30;
@@ -665,12 +683,12 @@ void Game_Main(PKEWindowProperties windowProps, const char *executablePath) {
Event_Teardown();
EntityType_Teardown();
PkeInput_Teardown();
+ PkeCamera_Teardown();
Physics_Teardown();
ECS_Teardown();
- PkeCamera_Teardown();
+ DestroyWindow();
AM_DebugPrint();
AM_Teardown();
- DestroyWindow();
PkeThreads_Teardown();
Pke_DebugPrint();
fprintf(stdout, "Game_Main Exiting\n");