diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2023-11-29 21:07:06 -0500 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2023-11-29 21:07:06 -0500 |
| commit | 9830bc2425385de6e666251fa9df6318605c639c (patch) | |
| tree | e52494a973ad8957c30cf7dacf92f1fa518105dc /editor | |
| parent | e111f78d519363a3d76237ff0a62dcbd5e53e3d6 (diff) | |
major refactor to decouple the engine and the editor
Diffstat (limited to 'editor')
| -rw-r--r-- | editor/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | editor/editor.cpp | 753 | ||||
| -rw-r--r-- | editor/editor.hpp | 10 | ||||
| -rw-r--r-- | editor/main.cpp | 14 |
4 files changed, 777 insertions, 2 deletions
diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 0b1c228..bd176c4 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2,6 +2,8 @@ project(pke_editor VERSION 0.0) set(PKE_EDITOR_SOURCE_FILES main.cpp + editor.hpp + editor.cpp ) add_executable(pke_editor ${PKE_EDITOR_SOURCE_FILES} diff --git a/editor/editor.cpp b/editor/editor.cpp new file mode 100644 index 0000000..6f887ed --- /dev/null +++ b/editor/editor.cpp @@ -0,0 +1,753 @@ + +#include "editor.hpp" + +#include "thread_pool.hpp" +#include "game.hpp" +#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" +#include "math-helpers.hpp" +#include "camera.hpp" +#include "entities.hpp" +#include "game-settings.hpp" +#include "player-input.hpp" +#include "window.hpp" +#include "vendor/glm_include.hpp" +#include "vendor/tinyfiledialogs//tinyfiledialogs.h" +#include "imgui.h" +#include <future> + +const char *dbgCtrl_CameraLeft = "debug-camera-left"; +const char *dbgCtrl_CameraRight = "debug-camera-right"; +const char *dbgCtrl_CameraForward = "debug-camera-forward"; +const char *dbgCtrl_CameraBack = "debug-camera-back"; +const char *dbgCtrl_CameraUp = "debug-camera-up"; +const char *dbgCtrl_CameraDown = "debug-camera-down"; +const char *dbgCtrl_CameraRotCC = "debug-camera-rot-counter-clockwise"; +const char *dbgCtrl_CameraRotC = "debug-camera-rot-clockwise"; +const char *dbgCtrl_CameraRot = "debug-camera-rot"; +const char *dbgCtrl_UnlockCamera = "debug-camera-unlock"; +const char *dbgCtrl_SelectHovered = "debug-select-hovered"; +const char *dbgCtrl_ClearSelection = "debug-clear-selection"; + +ThreadPoolHandle threadPoolHandle = ThreadPoolHandle_MAX; + +PkeCamera cameraDefault { + .pos = glm::vec3(-40.f, -40.f, -40.f), + .rot = glm::quat(1.f, 0.f, 0.f, 0.f), + .target = glm::vec3(0.f), + .type = PKE_CAMERA_TYPE_PERSPECTIVE, + .orientation = PKE_CAMERA_ORIENTATION_TARGET, + .stale = PKE_CAMERA_STALE_ALL, +}; +PkeCamera cameraDbg { + .pos = glm::vec3(4.f, 4.f, 4.f), + .rot = glm::quat(1.f, 0.f, 0.f, 0.f), + .target = glm::vec3(0.f), + .type = PKE_CAMERA_TYPE_PERSPECTIVE, + .orientation = PKE_CAMERA_ORIENTATION_FREE, + .stale = PKE_CAMERA_STALE_ALL, +}; + +InputActionSetHandle debugControlsHandle = InputActionSetHandle_MAX; +bool shouldSetupEditor = true; +bool shouldDisableEditor = false; +bool shouldLockCamera = false; +bool shouldUnlockCamera = false; + +struct EntityTypeInstanceCreateInfo { + EntityHandle entityTypeEntityHandle; +}; +DynArray<EntityTypeInstanceCreateInfo> entityInstancesToCreate{16}; +EntityHandle selectedEntity = EntityHandle_MAX; +EntityHandle hoveredEntity = EntityHandle_MAX; +bool shouldCreateEntityType = false; +EntityType entityTypeToCreate{}; + +char *sceneName = nullptr; +bool shouldOpenLoadSceneDialog = false; +bool shouldOpenSaveSceneDialog = false; +bool shouldLoadScene = false; +bool shouldSaveScene = false; + +glm::vec3 unproject(glm::vec3 windowCoords) { + double xDevNorm = (2.0f * windowCoords.x) / Extent.width - 1.0f; + double yDevNorm = 1.0f - (2.0f * windowCoords.y) / Extent.height; + yDevNorm *= -1; + glm::vec4 clipCoords(xDevNorm, yDevNorm, windowCoords.z, 1.f); + + glm::vec4 rayEye = glm::inverse(UBO.proj) * clipCoords; + + glm::vec4 worldCoords = glm::inverse(UBO.model) * glm::inverse(UBO.view) * rayEye; + if (std::abs(0.0f - worldCoords.w) > 0.00001f) { + worldCoords *= 1.0f / worldCoords.w; + } + + return glm::vec3(worldCoords); +} + +void PkeEditor_Tick(double delta) { + if (shouldSetupEditor) { + PkeEditor_Setup(); + } + if (shouldDisableEditor) { + PkeEditor_Teardown(); + } + if (shouldOpenLoadSceneDialog) { + shouldOpenLoadSceneDialog = false; + PkeThreads_Enqueue(threadPoolHandle, std::move(std::packaged_task<void()>( [] { + const char * patterns[1] = {"*.pstf"}; + char *selectedScene = tinyfd_openFileDialog(nullptr, nullptr, 1, patterns, "Pke Scene Text File", 0); + if (selectedScene != nullptr) { + sceneName = selectedScene; + shouldLoadScene = true; + } + }))); + } + if (shouldLoadScene && sceneName) { + shouldLoadScene = false; + Game_LoadSceneFile(sceneName); + } + + if (shouldUnlockCamera) { + shouldUnlockCamera = false; + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + cameraDbg.pos = ActiveCamera->pos; + if (ActiveCamera->orientation == cameraDbg.orientation) { + cameraDbg.rot = ActiveCamera->rot; + } else { + cameraDbg.rot = glm::quat(UBO.view); + } + cameraDbg.stale = PKE_CAMERA_STALE_ALL; + ActiveCamera = &cameraDbg; + } + + if (EntitiesToBeRemoved.Has(selectedEntity)) { + selectedEntity = EntityHandle_MAX; + } + if (EntitiesToBeRemoved.Has(hoveredEntity)) { + hoveredEntity = EntityHandle_MAX; + } + + bool imGuiHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow); + + if (selectedEntity != EntityHandle_MAX && !imGuiHovered) { + auto holder = PkeInput_Query(dbgCtrl_ClearSelection); + if (holder.type != InputEventHash{0}) { + const PkeMouseButtonEvent *mbEvent = static_cast<PkeMouseButtonEvent *>(holder.ptr); + if (mbEvent->isPressed) { + selectedEntity = EntityHandle_MAX; + } + } + } + // raycast for hovering + hoveredEntity = EntityHandle_MAX; + if (!imGuiHovered) { + double xMousePos, yMousePos; + glfwGetCursorPos(window, &xMousePos, &yMousePos); + + glm::vec3 fromCoords{unproject(glm::vec3(xMousePos, yMousePos, -1.f))}; + glm::vec3 toCoords{unproject(glm::vec3(xMousePos, yMousePos, 1.f))}; + + btVector3 rayOrigin{}; + btVector3 rayDestination{}; + GlmToBullet(fromCoords, rayOrigin); + GlmToBullet(toCoords, rayDestination); + + btCollisionWorld::ClosestRayResultCallback rayResult{rayOrigin, rayDestination}; + rayResult.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces; + + BtDynamicsWorld->rayTest(rayOrigin, rayDestination, rayResult); + if (rayResult.hasHit()) { + EntityHandle_T hoveredEntity_T{reinterpret_cast<EntityHandle_T>(rayResult.m_collisionObject->getUserPointer())}; + hoveredEntity = EntityHandle{hoveredEntity_T}; + } + } + + if (hoveredEntity != EntityHandle_MAX) { + auto holder = PkeInput_Query(dbgCtrl_SelectHovered); + if (holder.type != InputEventHash{0}) { + const PkeMouseButtonEvent *mbEvent = static_cast<PkeMouseButtonEvent *>(holder.ptr); + if (mbEvent->isPressed) { + selectedEntity = hoveredEntity; + } + } + } + + EntityHandle focusedHandle = selectedEntity != EntityHandle_MAX ? selectedEntity : hoveredEntity; + if (focusedHandle != EntityHandle_MAX) { + const auto *inst = ECS_GetInstance(focusedHandle); + const auto *grBinds = ECS_GetGrBinds(inst->grBindsHandle); + pkeDebugHitbox.instanceBuffer = grBinds->instanceBuffer; + pkeDebugHitbox.instanceStartingIndex = inst->index; + } else { + pkeDebugHitbox.instanceBuffer = VK_NULL_HANDLE; + pkeDebugHitbox.instanceStartingIndex = 0; + } + + if (shouldCreateEntityType) { + assert(entityTypeToCreate.entityHandle == EntityHandle_MAX); + // TODO this needs to be more elegant + int64_t existingEntityTypeIndex = EntityType_FindByTypeCode(entityTypeToCreate.entityTypeCode); + if (existingEntityTypeIndex == -1) { + entityTypeToCreate.entityHandle = ECS_CreateEntity(); + EntityType_Load(entityTypeToCreate); + GlobalEntityTypes.Push(entityTypeToCreate); + } + entityTypeToCreate = EntityType{}; + shouldCreateEntityType = false; + } + while (entityInstancesToCreate.Count() > 0) { + auto createInfo = entityInstancesToCreate.Pop(); + // TODO needs to be more elegant + int64_t etIndex = EntityType_FindByEntityHandle(createInfo.entityTypeEntityHandle); + auto &et = GlobalEntityTypes[etIndex]; + EntityHandle newEntity = ECS_CreateEntity(); + auto &compInst = ECS_CreateInstance(newEntity, createInfo.entityTypeEntityHandle); + + compInst.physicsLayer = et.bt.startingCollisionLayer; + compInst.physicsMask = et.bt.startingCollisionMask; + btVector3 localInertia(0, 0, 0); + et.bt.shape->calculateLocalInertia(et.bt.startingMass, localInertia); + btTransform posRot{}; + posRot.setIdentity(); + compInst.bt.motionState = Pke_New<btDefaultMotionState>(MemBkt_Bullet); + new (compInst.bt.motionState) btDefaultMotionState(posRot); + compInst.bt.rigidBody = Pke_New<btRigidBody>(MemBkt_Bullet); + new (compInst.bt.rigidBody) btRigidBody(et.bt.startingMass, compInst.bt.motionState, et.bt.shape, localInertia); + compInst.bt.rigidBody->setLinearVelocity(btVector3(0,0,0)); + compInst.bt.rigidBody->setAngularVelocity(btVector3(0,0,0)); + compInst.bt.rigidBody->getCollisionShape()->setLocalScaling(btVector3(1, 1, 1)); + BtDynamicsWorld->addRigidBody(compInst.bt.rigidBody); + compInst.bt.rigidBody->getBroadphaseProxy()->m_collisionFilterGroup = static_cast<PhysicsCollision_T>(et.bt.startingCollisionLayer); + compInst.bt.rigidBody->getBroadphaseProxy()->m_collisionFilterMask = static_cast<PhysicsCollision_T>(et.bt.startingCollisionMask); + compInst.bt.rigidBody->setUserPointer(reinterpret_cast<void *>(compInst.entHandle)); + } + + PkeInputEventHolder holder = PkeInput_Query(dbgCtrl_UnlockCamera); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyEsc; + keyEsc = static_cast<PkeKeyEvent *>(holder.ptr); + if (keyEsc->isPressed || keyEsc->pressCount > 0) { + pkeSettings.editorSettings.isUsingDebugCamera = false; + shouldLockCamera = true; + } + } + + if (shouldLockCamera) { + shouldLockCamera = false; + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + cameraDefault.stale = PKE_CAMERA_STALE_ALL; + ActiveCamera = &cameraDefault; + } + + if (pkeSettings.editorSettings.isUsingDebugCamera) { + holder = PkeInput_Query(dbgCtrl_CameraRot); + if (holder.type != InputEventHash{0}) { + const PkeCursorPosEvent *posEvent = static_cast<PkeCursorPosEvent *>(holder.ptr); + if (posEvent->xMotion || posEvent->yMotion) { + glm::vec3 axis1Heading = glm::conjugate(cameraDbg.rot) * glm::vec3(1.f, 0.f, 0.f); + glm::vec3 axis2Heading = glm::conjugate(cameraDbg.rot) * glm::vec3(0.f, 1.f, 0.f); + // glm::vec3 axis1Heading = cameraDbg.rot * glm::vec3(1.f, 0.f, 0.f); + // glm::vec3 axis2Heading = cameraDbg.rot * glm::vec3(0.f, 1.f, 0.f); + glm::quat pitch = glm::angleAxis(float(posEvent->yMotion) * 0.01f, glm::normalize(axis1Heading)); + glm::quat yaw = glm::angleAxis(float(posEvent->xMotion) * 0.01f, glm::normalize(axis2Heading)); + glm::quat rot = cameraDbg.rot * pitch * yaw; + // rot = glm::normalize(rot); + auto eul = glm::eulerAngles(rot); + cameraDbg.rot = glm::quat(eul); + cameraDbg.stale = cameraDbg.stale | PKE_CAMERA_STALE_ROT; + } + } + + double leftCount = 0; + double rightCount = 0; + double forwardCount = 0; + double backCount = 0; + double upCount = 0; + double downCount = 0; + double rotCCCount = 0; + double rotCCount = 0; + + holder = PkeInput_Query(dbgCtrl_CameraLeft); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyLeft; + keyLeft = static_cast<PkeKeyEvent *>(holder.ptr); + leftCount = keyLeft->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraRight); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyRight; + keyRight = static_cast<PkeKeyEvent *>(holder.ptr); + rightCount = keyRight->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraForward); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyForward; + keyForward = static_cast<PkeKeyEvent *>(holder.ptr); + forwardCount = keyForward->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraBack); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyBack; + keyBack = static_cast<PkeKeyEvent *>(holder.ptr); + backCount = keyBack->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraUp); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyUp; + keyUp = static_cast<PkeKeyEvent *>(holder.ptr); + upCount = keyUp->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraDown); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyDown; + keyDown = static_cast<PkeKeyEvent *>(holder.ptr); + downCount = keyDown->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraRotCC); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyRotCC; + keyRotCC = static_cast<PkeKeyEvent *>(holder.ptr); + rotCCCount = keyRotCC->isPressed ? 1 : 0; + } + + holder = PkeInput_Query(dbgCtrl_CameraRotC); + if (holder.type != InputEventHash{0}) { + PkeKeyEvent *keyRotC; + keyRotC = static_cast<PkeKeyEvent *>(holder.ptr); + rotCCount = keyRotC->isPressed ? 1 : 0; + } + + double accelerated = delta * 10.f; + double axis1 = -(leftCount * accelerated) + (rightCount * accelerated); + double axis2 = (forwardCount * accelerated) + -(backCount * accelerated); + double axis3 = -(upCount * accelerated) + (downCount * accelerated); + if (axis1 != 0 || axis2 != 0 || axis3 != 0) { + glm::vec3 axis1Heading = glm::conjugate(cameraDbg.rot) * glm::vec3(-axis1, 0.f, 0.f); + glm::vec3 axis2Heading = glm::conjugate(cameraDbg.rot) * glm::vec3(0.f, 0.f, axis2); + glm::vec3 axis3Heading = glm::conjugate(cameraDbg.rot) * glm::vec3(0.f, axis3, 0.f); + cameraDbg.pos += glm::vec3(axis1Heading + axis2Heading + axis3Heading); + cameraDbg.stale = cameraDbg.stale | PKE_CAMERA_STALE_POS; + } + + double axis4 = -(rotCCCount * delta) + (rotCCount * delta); + if (axis4 != 0.0) { + cameraDbg.rot = glm::quat(glm::vec3(0.f, 0.f, axis4)) * cameraDbg.rot; + cameraDbg.stale = cameraDbg.stale | PKE_CAMERA_STALE_ROT; + } + } + +} + +void RecordImGui_GLM(const char *label, glm::mat4 &mat) { + float min = -1; + float max = 1; + for (long i = 0; i < 4; ++i) { + ImGui::PushID(i); + ImGui::SliderFloat4(label, &mat[i][0], min, max, "%.3f", ImGuiSliderFlags_NoRoundToFormat); + ImGui::PopID(); + } +} + +void RecordImGuiEditorWrapper() { + ImGui::DockSpaceOverViewport(nullptr, ImGuiDockNodeFlags_PassthruCentralNode); + ImGui::BeginMainMenuBar(); + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Exit")) { + glfwSetWindowShouldClose(window, true); + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Debug")) { + ImGui::Checkbox("Show Debug Hitboxes", &pkeSettings.isRenderingDebug); + ImGui::Checkbox("Pause Physics Simulation", &pkeSettings.isSimulationPaused); + if (ImGui::Checkbox("Uncap Framerate", &pkeSettings.graphicsSettings.isFramerateUnlocked)) { + shouldRecreateSwapchain = true; + } + if (ImGui::Checkbox("wait for v-sync", &pkeSettings.graphicsSettings.isWaitingForVsync)) { + shouldRecreateSwapchain = true; + } + // ImGui::Checkbox("Uncap Tickrate", &pkeSettings.isTickrateUnlocked); + if (ImGui::Checkbox("Use Debug Camera", &pkeSettings.editorSettings.isUsingDebugCamera)) { + if (pkeSettings.editorSettings.isUsingDebugCamera) { + shouldUnlockCamera = true; + } else { + shouldLockCamera = true; + } + } + + ImGuiIO &io = ImGui::GetIO(); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); +} + +void RecordImGuiEntityList() { + if (!ImGui::Begin("EntityList", &pkeSettings.editorSettings.isShowingEntityList)) { + ImGui::End(); + return; + } + static ImGuiTableFlags tableFlags{ + ImGuiTableFlags_Borders | + ImGuiTableFlags_RowBg + }; + if (ImGui::BeginTable("Entities", 7, tableFlags)) { + ImGui::TableSetupColumn("Select"); + ImGui::TableSetupColumn("EntityHandle"); + ImGui::TableSetupColumn("ParentEntityHandle"); + ImGui::TableSetupColumn("GrBindsHandle"); + ImGui::TableSetupColumn("InstanceHandle"); + ImGui::TableSetupColumn("IsMarkedForRemoval"); + ImGui::TableSetupColumn("Delete"); + ImGui::TableHeadersRow(); + + uint64_t bucketCount = ECS_GetEntities_BucketCount(); + for (long bucket = 0; bucket < bucketCount; ++bucket) { + uint64_t itemCount = 0; + auto *entities = ECS_GetEntities(bucket, itemCount); + ImGui::PushID(bucket); + for (long row = 0; row < itemCount; row++) { + auto *entity = &entities[row]; + ImGui::PushID(row); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::BeginDisabled(selectedEntity == entity->handle); + if (ImGui::Button("Select")) + selectedEntity = entity->handle; + ImGui::EndDisabled(); + ImGui::TableSetColumnIndex(1); + ImGui::Text("0x%016lX", static_cast<EntityHandle_T>(entity->handle)); + ImGui::TableSetColumnIndex(2); + ImGui::Text("0x%016lX", static_cast<EntityHandle_T>(entity->parentHandle)); + ImGui::TableSetColumnIndex(3); + ImGui::Text("0x%016lX", static_cast<GrBindsHandle_T>(entity->grBindsHandle)); + ImGui::TableSetColumnIndex(4); + ImGui::Text("0x%016lX", static_cast<InstanceHandle_T>(entity->instanceHandle)); + ImGui::TableSetColumnIndex(5); + ImGui::Text("%u", entity->isMarkedForRemoval); + ImGui::TableSetColumnIndex(6); + ImGui::BeginDisabled(selectedEntity != entity->handle); + if (ImGui::Button("Delete")) + ECS_MarkForRemoval(entity->handle); + ImGui::EndDisabled(); + ImGui::PopID(); + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::End(); +} + +void RecordImGuiUBO() { + if (!ImGui::Begin("UBO", &pkeSettings.editorSettings.isShowingUBO)) { + ImGui::End(); + return; + } + ImGui::Text("Model"); + RecordImGui_GLM("UBO-model", UBO.model); + ImGui::Text("View"); + RecordImGui_GLM("UBO-view", UBO.view); + ImGui::Text("Proj"); + RecordImGui_GLM("UBO-proj", UBO.proj); + ImGui::End(); +} + +void RecordImGuiModalCreateEntityType() { + if (ImGui::BeginPopupModal("CreateEntityType", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + static char modelsDir[64]; + static char modelFile[64]; + static char entityTypeCode[32]; + + ImGui::InputText("Models Dir", modelsDir, 63); + ImGui::InputText("Model File", modelFile, 63); + ImGui::InputText("Entity Type Code", entityTypeCode, 31); + ImGui::InputScalar("Starting Instance Count", ImGuiDataType_U32, &entityTypeToCreate.startingInstanceCount); + ImGui::InputScalar("GLTF Import Index - Vertex", ImGuiDataType_S16, &entityTypeToCreate.Importer_GLTF.AccessorIndexVertex); + ImGui::InputScalar("GLTF Import Index - Normal", ImGuiDataType_S16, &entityTypeToCreate.Importer_GLTF.AccessorIndexNormal); + ImGui::InputScalar("GLTF Import Index - UV", ImGuiDataType_S16, &entityTypeToCreate.Importer_GLTF.AccessorIndexUV); + ImGui::InputScalar("GLTF Import Index - Index", ImGuiDataType_S16, &entityTypeToCreate.Importer_GLTF.AccessorIndexIndex); + ImGui::InputFloat("Physics - Mass", &entityTypeToCreate.bt.startingMass); + ImGui::InputScalar("Physics - Collision Layer", ImGuiDataType_U16, &entityTypeToCreate.bt.startingCollisionLayer); + ImGui::InputScalar("Physics - Collision Mask", ImGuiDataType_U16, &entityTypeToCreate.bt.startingCollisionMask); + + ImGui::Separator(); + + if (ImGui::Button("Create")) { + // TODO some type of validation + memset(modelsDir, '\0', 64); + memset(modelFile, '\0', 64); + memset(entityTypeCode, '\0', 32); + // assert(entityTypeToCreate == nullptr || entityTypeToCreate == CAFE_BABE(EntityType)); + // entityTypeToCreate = Pke_New<EntityType>(); + + char *sModelsDir = Pke_New<char>(strlen(modelsDir) + 1); + strncpy(sModelsDir, modelsDir, 63); + entityTypeToCreate.modelsDir = sModelsDir; + + char *sModelFile = Pke_New<char>(strlen(modelFile) + 1); + strncpy(sModelFile, modelFile, 63); + entityTypeToCreate.modelFile = sModelFile; + + char *sEntityTypeCode = Pke_New<char>(strlen(entityTypeCode) + 1); + strncpy(sEntityTypeCode, entityTypeCode, 31); + entityTypeToCreate.entityTypeCode = sEntityTypeCode; + + shouldCreateEntityType = true; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } +} + +void RecordImGui_CompGrBinds(bool readonly, CompGrBinds *component) { + if (component == nullptr) return; + int inputTextFlags = 0; + if (readonly) + inputTextFlags |= ImGuiInputTextFlags_ReadOnly; + + ImGui::Text("CompGRBinds"); + ImGui::Separator(); + + if (ImGui::Button("Create Instance")) { + entityInstancesToCreate.Push({ + .entityTypeEntityHandle = component->entHandle, + }); + } + + if (component->vkPipelineLayout) + ImGui::InputScalar("VkPipelineLayout", ImGuiDataType_U64, &component->vkPipelineLayout, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + if (component->vkDescriptorSets){ + ImGui::InputScalarN("VkPipelineDescriptorSets", ImGuiDataType_U64, &component->vkDescriptorSets, MAX_FRAMES_IN_FLIGHT, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + } + + if (component->vertexBuffer) + ImGui::InputScalar("VkVertexBuffer", ImGuiDataType_U64, &component->vertexBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("VertexFirstBinding", ImGuiDataType_U32, &component->vertexFirstBinding, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("VertexBindingCount", ImGuiDataType_U32, &component->vertexBindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("VertexOffsets", ImGuiDataType_U64, &component->vertexOffsets, nullptr, nullptr, nullptr, inputTextFlags); + + if (component->normalsBuffer) + ImGui::InputScalar("VkNormalBuffer", ImGuiDataType_U64, &component->normalsBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("NormalFirstBinding", ImGuiDataType_U32, &component->normalsFirstBinding, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("NormalBindingCount", ImGuiDataType_U32, &component->normalsBindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("NormalOffsets", ImGuiDataType_U64, &component->normalsOffsets, nullptr, nullptr, nullptr, inputTextFlags); + + if (component->uvBuffer) + ImGui::InputScalar("VkUVBuffer", ImGuiDataType_U64, &component->uvBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("UVFirstBinding", ImGuiDataType_U32, &component->uvFirstBinding, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("UVBindingCount", ImGuiDataType_U32, &component->uvBindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("UVOffsets", ImGuiDataType_U64, &component->uvOffsets, nullptr, nullptr, nullptr, inputTextFlags); + + if (component->indexBuffer) + ImGui::InputScalar("VkIndexBuffer", ImGuiDataType_U64, &component->indexBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("IndexBindingCount", ImGuiDataType_U32, &component->indexBindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("IndexOffsets", ImGuiDataType_U64, &component->indexOffsets, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("IndexCount", ImGuiDataType_U32, &component->indexCount, nullptr, nullptr, nullptr, inputTextFlags); + + if (component->instanceBuffer) + ImGui::InputScalar("VkInstanceBuffer", ImGuiDataType_U64, &component->instanceBuffer, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("InstanceFirstBinding", ImGuiDataType_U32, &component->instanceFirstBinding, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("InstanceBindingCount", ImGuiDataType_U32, &component->instanceBindingCount, nullptr, nullptr, nullptr, inputTextFlags); + ImGui::InputScalar("InstanceOffsets", ImGuiDataType_U64, &component->instanceOffsets, nullptr, nullptr, nullptr, inputTextFlags); + + ImGui::InputScalar("InstanceBufferMaxCount", ImGuiDataType_U32, &component->instanceBufferMaxCount, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("Instance Count", ImGuiDataType_U32, &component->instanceCounter, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly); + + ImGui::Spacing(); +} + +void RecordImGui_CompInstPos(bool readonly, CompInstance *component) { + if (component == nullptr) return; + int inputTextFlags = 0; + if (readonly) + inputTextFlags |= ImGuiInputTextFlags_ReadOnly; + + ImGui::Text("CompInststance + InstPos"); + ImGui::Separator(); + + bool changed = false; + InstPos instPos; + component->bt.motionState->getWorldTransform(instPos.posRot); + instPos.scale = component->bt.rigidBody->getCollisionShape()->getLocalScaling(); + instPos.mass = component->bt.rigidBody->getMass(); + + btVector3 pos = instPos.posRot.getOrigin(); + btQuaternion rot = instPos.posRot.getRotation(); + glm::vec3 eul; + rot.getEulerZYX(eul.z, eul.y, eul.x); + eul = glm::degrees(eul); + + changed = ImGui::InputScalar("Instance Index", ImGuiDataType_U64, &component->index, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly) || changed; + changed = ImGui::InputScalarN("pos", ImGuiDataType_Float, &pos, 3, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputScalarN("rot (eul)", ImGuiDataType_Float, &eul, 3, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputScalarN("scale", ImGuiDataType_Float, &instPos.scale, 3, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputFloat("mass", &instPos.mass, 0.0, 0.0, "%.3f", inputTextFlags) || changed; + + changed = ImGui::InputScalar("Phys - Collision Layer", ImGuiDataType_U16, &component->physicsLayer, nullptr, nullptr, nullptr, inputTextFlags) || changed; + changed = ImGui::InputScalar("Phys - Collision Mask", ImGuiDataType_U16, &component->physicsMask, nullptr, nullptr, nullptr, inputTextFlags) || changed; + + ImGui::InputScalar("Phys - Rigid Body", ImGuiDataType_U64, &component->bt.rigidBody, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + ImGui::InputScalar("Phys - Motion State", ImGuiDataType_U64, &component->bt.motionState, nullptr, nullptr, "0x%016lX", ImGuiInputTextFlags_ReadOnly); + + if (changed) { + instPos.posRot.setOrigin(pos); + eul = glm::radians(eul); + rot.setEulerZYX(eul.z, eul.y, eul.x); + instPos.posRot.setRotation(rot); + auto *broadphase = component->bt.rigidBody->getBroadphaseProxy(); + broadphase->m_collisionFilterGroup = static_cast<PhysicsCollision_T>(component->physicsLayer); + broadphase->m_collisionFilterMask = static_cast<PhysicsCollision_T>(component->physicsMask); + ECS_UpdateInstance(component->entHandle, instPos, true); + } + + ImGui::Spacing(); +} + +void RecordImGuiSceneEditor() { + { + if (!ImGui::Begin("SceneEditorEntityTypes", &pkeSettings.editorSettings.isShowingSceneEditor)) { + ImGui::End(); + return; + } + if (ImGui::Button("Create Entity Type")) { + ImGui::OpenPopup("CreateEntityType"); + } + if (ImGui::Button("Save")) { + // Game_SaveSceneFile(sceneName); + shouldOpenSaveSceneDialog = true; + } + if (ImGui::Button("Load")) { + // Game_LoadSceneFile(sceneName); + shouldOpenLoadSceneDialog = true; + } + if (ImGui::Button("Clear Selection")) { + selectedEntity = EntityHandle_MAX; + } + + ImGui::Spacing(); + + if (selectedEntity != EntityHandle_MAX) { + RecordImGui_CompGrBinds(true, ECS_GetGrBinds(selectedEntity)); + RecordImGui_CompInstPos(false, ECS_GetInstance(selectedEntity)); + } + + RecordImGuiModalCreateEntityType(); + + ImGui::End(); + } +} + +void RecordImGuiEditor() { + if (pkeSettings.isShowingEditor) { + RecordImGuiEditorWrapper(); + RecordImGuiEntityList(); + RecordImGuiSceneEditor(); + RecordImGuiUBO(); + } +} + +void PkeEditor_Setup() { + shouldSetupEditor = false; + PkeInput_ActivateSet(debugControlsHandle); + Event_RegisterCallback("RenderImGui", RecordImGuiEditor); +} + +void PkeEditor_Disable() { + shouldDisableEditor = false; + PkeInput_DeactivateSet(debugControlsHandle); + Event_UnregisterCallback("RenderImGui", RecordImGuiEditor); +} + +void PkeEditor_Teardown() { + PkeEditor_Disable(); + PkeThreads_Teardown(threadPoolHandle); + entityInstancesToCreate.~DynArray(); +} + +void PkeEditor_Init() { + PkeInputSet debugControlsSet; + debugControlsSet.title = "debug-editor-controls"; + debugControlsSet.actionCount = 12; + debugControlsSet.actions = Pke_New<PkeInputAction>(debugControlsSet.actionCount); + + debugControlsSet.actions[0].name = dbgCtrl_CameraLeft; + debugControlsSet.actions[0].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_A, + }; + debugControlsSet.actions[1].name = dbgCtrl_CameraRight; + debugControlsSet.actions[1].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_D, + }; + debugControlsSet.actions[2].name = dbgCtrl_CameraForward; + debugControlsSet.actions[2].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_W, + }; + debugControlsSet.actions[3].name = dbgCtrl_CameraBack; + debugControlsSet.actions[3].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_S, + }; + debugControlsSet.actions[4].name = dbgCtrl_CameraUp; + debugControlsSet.actions[4].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_R, + }; + debugControlsSet.actions[5].name = dbgCtrl_CameraDown; + debugControlsSet.actions[5].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_F, + }; + debugControlsSet.actions[6].name = dbgCtrl_CameraRotCC; + debugControlsSet.actions[6].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_Q, + }; + debugControlsSet.actions[7].name = dbgCtrl_CameraRotC; + debugControlsSet.actions[7].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_E, + }; + debugControlsSet.actions[8].name = dbgCtrl_CameraRot; + debugControlsSet.actions[8].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_CURSOR_POS_EVENTS, + }; + debugControlsSet.actions[9].name = dbgCtrl_UnlockCamera; + debugControlsSet.actions[9].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_KEY_EVENTS, + .button = GLFW_KEY_ESCAPE, + }; + debugControlsSet.actions[10].name = dbgCtrl_SelectHovered; + debugControlsSet.actions[10].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS, + .button = GLFW_MOUSE_BUTTON_LEFT, + }; + debugControlsSet.actions[11].name = dbgCtrl_ClearSelection; + debugControlsSet.actions[11].primaryHash = PkeInputEventMask { + .computedHash = PKE_INPUT_HASH_ALL_MOUSE_BUTTON_EVENTS, + .button = GLFW_MOUSE_BUTTON_RIGHT, + }; + + debugControlsHandle = PkeInput_RegisterSet(debugControlsSet); + + ActiveCamera = &cameraDefault; + + threadPoolHandle = PkeThreads_Init(1, 1); + + Event_RegisterCallback<TickEvent>("GAME_TICK", PkeEditor_Tick); +} diff --git a/editor/editor.hpp b/editor/editor.hpp new file mode 100644 index 0000000..3cfb2df --- /dev/null +++ b/editor/editor.hpp @@ -0,0 +1,10 @@ +#ifndef PKE_EDITOR_HPP +#define PKE_EDITOR_HPP + +void PkeEditor_Tick(double delta); +void PkeEditor_Init(); +void PkeEditor_Setup(); +void PkeEditor_Disable(); +void PkeEditor_Teardown(); + +#endif /* PKE_EDITOR_HPP */ diff --git a/editor/main.cpp b/editor/main.cpp index 0d4ef9f..7400583 100644 --- a/editor/main.cpp +++ b/editor/main.cpp @@ -1,5 +1,7 @@ #include <csignal> +#include "editor.hpp" +#include "event.hpp" #include "game.hpp" #include "game-settings.hpp" #include "window-types.hpp" @@ -13,8 +15,16 @@ PKEWindowProperties windowProps{}; int main() { signal(SIGTERM, signal_handler); - fprintf(stdout, "PKE ENTERING\n"); + fprintf(stdout, "PKE_EDITOR ENTERING\n"); + // setup + { + pkeSettings.isShowingEditor = true; + Event_RegisterCallback<EventHandler>("GAME_INIT", PkeEditor_Init); + + Event_RegisterCallback<EventHandler>("GAME_TEARDOWN", PkeEditor_Teardown); + } + // run Game_Main(&windowProps); - fprintf(stdout, "PKE EXITING\n"); + fprintf(stdout, "PKE_EDITOR EXITING\n"); return 0; } |
