diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2024-01-18 22:37:02 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2024-01-18 22:37:02 -0500 |
| commit | 1b48d1382d2d57a822201f34743a51813798b348 (patch) | |
| tree | 612672a4be654b38f3b44580f85e4f0637952512 /src/game.cpp | |
| parent | 2e680ebd77236f7b62b9ded1b083c86f9e13b1c8 (diff) | |
camera checkpoint - large refactor for attempting to let physics own camera position
Diffstat (limited to 'src/game.cpp')
| -rw-r--r-- | src/game.cpp | 276 |
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"); |
