diff options
author | rtk0c <[email protected]> | 2022-06-03 23:30:01 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-06-03 23:30:01 -0700 |
commit | 791b3f354b378769bffe623b05f1305c91b77101 (patch) | |
tree | 5409b311e6232eb4a6d3f8259b780d76b8ee1c59 /source/Game/EditorCorePrivate.cpp | |
parent | 60ccc62f4934e44ad5b905fdbcf458302b8d8a09 (diff) |
Changeset: 64 [WIP] Rename directoriesmaster-switch-to-build2
Diffstat (limited to 'source/Game/EditorCorePrivate.cpp')
-rw-r--r-- | source/Game/EditorCorePrivate.cpp | 1113 |
1 files changed, 0 insertions, 1113 deletions
diff --git a/source/Game/EditorCorePrivate.cpp b/source/Game/EditorCorePrivate.cpp deleted file mode 100644 index 43857a8..0000000 --- a/source/Game/EditorCorePrivate.cpp +++ /dev/null @@ -1,1113 +0,0 @@ -#include "EditorCorePrivate.hpp" - -#include "App.hpp" -#include "AppConfig.hpp" -#include "EditorAccessories.hpp" -#include "EditorAttachmentImpl.hpp" -#include "EditorCommandPalette.hpp" -#include "EditorNotification.hpp" -#include "EditorUtils.hpp" -#include "GameObject.hpp" -#include "Mesh.hpp" -#include "Player.hpp" -#include "SceneThings.hpp" -#include "VertexIndex.hpp" - -#include <Macros.hpp> -#include <Metadata.hpp> -#include <ScopeGuard.hpp> -#include <YCombinator.hpp> - -#define GLFW_INCLUDE_NONE -#include <GLFW/glfw3.h> - -#include <imgui.h> -#include <misc/cpp/imgui_stdlib.h> -#include <cstddef> -#include <cstdint> -#include <cstdlib> -#include <functional> -#include <glm/gtc/quaternion.hpp> -#include <glm/gtc/type_ptr.hpp> -#include <glm/gtx/quaternion.hpp> -#include <limits> -#include <memory> -#include <string> -#include <string_view> -#include <utility> - -using namespace std::literals; - -namespace ProjectBrussel_UNITY_ID { -// TODO handle internal state internally and move this to EditorUtils.hpp -enum RenamableSelectableAction { - RSA_None, - RSA_Selected, - RSA_RenameCommitted, - RSA_RenameCancelled, -}; -RenamableSelectableAction RenamableSelectable(const char* displayName, bool selected, bool& renaming, std::string& renamingScratchBuffer) // -{ - RenamableSelectableAction result = RSA_None; - - ImGuiSelectableFlags flags = 0; - // When renaming, disable all other entries that is not the one being renamed - if (renaming && !selected) { - flags |= ImGuiSelectableFlags_Disabled; - } - - if (renaming && selected) { - // State: being renamed - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 }); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0); - ImGui::SetKeyboardFocusHere(); - if (ImGui::InputText("##Rename", &renamingScratchBuffer, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) { - // Confirm - renaming = false; - result = RSA_RenameCommitted; - } - ImGui::PopStyleVar(2); - - if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { - // Cancel - renaming = false; - result = RSA_RenameCancelled; - } - } else { - // State: normal - - if (ImGui::Selectable(displayName, selected, flags)) { - result = RSA_Selected; - } - } - - return result; -} -} // namespace ProjectBrussel_UNITY_ID - -void EditorInspector::SelectTarget(TargetType type, void* object) { - selectedItt = type; - selectedItPtr = object; - renaming = false; - renamingScratchBuffer.clear(); -} - -EditorContentBrowser::EditorContentBrowser(EditorInspector* inspector) - : mInspector{ inspector } { -} - -EditorContentBrowser::~EditorContentBrowser() { -} - -void EditorContentBrowser::Show(bool* open) { - using namespace ProjectBrussel_UNITY_ID; - - ImGuiWindowFlags windowFlags; - if (mDocked) { - // Center window horizontally, align bottom vertically - auto& viewportSize = ImGui::GetMainViewport()->Size; - ImGui::SetNextWindowPos(ImVec2(viewportSize.x / 2, viewportSize.y), ImGuiCond_Always, ImVec2(0.5f, 1.0f)); - ImGui::SetNextWindowSizeRelScreen(0.8f, mBrowserHeight); - windowFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse; - } else { - windowFlags = 0; - } - ImGui::Begin("Content Browser", open, windowFlags); - - ImGui::Splitter(true, kSplitterThickness, &mSplitterLeft, &mSplitterRight, kLeftPaneMinWidth, kRightPaneMinWidth); - - ImGui::BeginChild("LeftPane", ImVec2(mSplitterLeft - kPadding, 0.0f)); - { - if (ImGui::Selectable("Settings", mPane == P_Settings)) { - mPane = P_Settings; - } - if (ImGui::Selectable("Ires", mPane == P_Ires)) { - mPane = P_Ires; - } - if (ImGui::Selectable("Levels", mPane == P_Level)) { - mPane = P_Level; - } - } - ImGui::EndChild(); - - ImGui::SameLine(0.0f, kPadding + kSplitterThickness + kPadding); - ImGui::BeginChild("RightPane"); // Fill remaining space - auto origItt = mInspector->selectedItt; - auto origItPtr = mInspector->selectedItPtr; - switch (mPane) { - case P_Settings: { - ImGui::Checkbox("Docked", &mDocked); - ImGui::SliderFloat("Height", &mBrowserHeight, 0.1f, 1.0f); - } break; - - case P_Ires: { - bool isIttIres = origItt == EditorInspector::ITT_Ires; - - if (ImGui::Button("New")) { - ImGui::OpenPopup("New Ires"); - } - if (ImGui::BeginPopup("New Ires")) { - for (int i = 0; i < (int)IresObject::KD_COUNT; ++i) { - auto kind = static_cast<IresObject::Kind>(i); - if (ImGui::MenuItem(Metadata::EnumToString(kind).data())) { - auto ires = IresObject::Create(kind); - auto [DISCARD, success] = IresManager::instance->Add(ires.get()); - if (success) { - (void)ires.release(); - } - } - } - ImGui::EndPopup(); - } - - ImGui::SameLine(); - if (ImGui::Button("Refresh list") || - ImGui::IsKeyPressed(ImGuiKey_F5)) - { - // TODO - } - - ImGui::SameLine(); - if (ImGui::Button("Save", !isIttIres)) { - auto ires = static_cast<IresObject*>(origItPtr); - IresManager::instance->Save(ires); - } - - ImGui::SameLine(); - if (ImGui::Button("Reload", !isIttIres)) { - auto ires = static_cast<IresObject*>(origItPtr); - IresManager::instance->Reload(ires); - } - - ImGui::SameLine(); - if (ImGui::Button("Rename", !isIttIres) || - (isIttIres && ImGui::IsKeyPressed(ImGuiKey_F2, false))) - { - auto ires = static_cast<IresObject*>(origItPtr); - mInspector->renaming = true; - mInspector->renamingScratchBuffer = ires->GetName(); - } - - ImGui::SameLine(); - if (ImGui::Button("Delete", !isIttIres) || - (isIttIres && ImGui::IsKeyPressed(ImGuiKey_Delete, false))) - { - ImGui::OpenPopup("Delete Ires"); - } - bool openedDummy = true; - if (ImGui::BeginPopupModal("Delete Ires", &openedDummy, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize)) { - if (ImGui::Button("Confirm")) { - auto ires = static_cast<IresObject*>(origItPtr); - IresManager::instance->Delete(ires); - } - ImGui::SameLine(); - if (ImGui::Button("Cancel")) { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - - auto& objects = IresManager::instance->GetObjects(); - for (auto it = objects.begin(); it != objects.end(); ++it) { - auto ires = it->second.Get(); - auto& name = ires->GetName(); - - bool selected = origItPtr == ires; - - switch (RenamableSelectable(name.c_str(), selected, mInspector->renaming, mInspector->renamingScratchBuffer)) { - case RSA_Selected: { - mInspector->SelectTarget(EditorInspector::ITT_Ires, ires); - } break; - - case RSA_RenameCommitted: { - ires->SetName(std::move(mInspector->renamingScratchBuffer)); - } break; - - // Do nothing - case RSA_RenameCancelled: - case RSA_None: break; - } - if (!mInspector->renaming) { - if (ImGui::BeginDragDropSource()) { - auto kindName = Metadata::EnumToString(ires->GetKind()); - // Reason: intentionally using pointer as payload - ImGui::SetDragDropPayload(kindName.data(), &ires, sizeof(ires)); // NOLINT(bugprone-sizeof-expression) - ImGui::Text("%s '%s'", kindName.data(), name.c_str()); - ImGui::EndDragDropSource(); - } - } - } - } break; - - case P_Level: { - bool isIttLevel = origItt == EditorInspector::ITT_Level; - - if (ImGui::Button("New")) { - auto uid = Uid::Create(); - auto& ldObj = LevelManager::instance->AddLevel(uid); - mInspector->SelectTarget(EditorInspector::ITT_Level, &ldObj); - mInspector->renaming = true; - mInspector->renamingScratchBuffer = ldObj.name; - } - - if (ImGui::Button("Save", !isIttLevel)) { - auto ldObj = static_cast<LevelManager::LoadableObject*>(origItPtr); - LevelManager::instance->SaveLevel(ldObj->level->GetUid()); - } - - auto& objects = LevelManager::instance->mObjByUid; - for (auto it = objects.begin(); it != objects.end(); ++it) { - auto& uid = it->first; - auto& ldObj = it->second; - auto* level = ldObj.level.Get(); - bool selected = origItPtr == &ldObj; - const char* displayName = ldObj.name.c_str(); - if (strcmp(displayName, "") == 0) { - displayName = "<unnamed level>"; - } - - switch (RenamableSelectable(displayName, selected, mInspector->renaming, mInspector->renamingScratchBuffer)) { - case RSA_Selected: { - mInspector->SelectTarget(EditorInspector::ITT_Level, &ldObj); - } break; - - case RSA_RenameCommitted: { - ldObj.name = std::move(mInspector->renamingScratchBuffer); - } break; - - // Do nothing - case RSA_RenameCancelled: - case RSA_None: break; - } - if (!mInspector->renaming) { - if (ImGui::BeginDragDropSource()) { - // Reason: intentionally using pointer as payload - ImGui::SetDragDropPayload(BRUSSEL_TAG_Level, &ldObj, sizeof(ldObj)); // NOLINT(bugprone-sizeof-expression) - ImGui::Text(BRUSSEL_Uid_FORMAT_STR, BRUSSEL_Uid_FORMAT_EXPAND(uid)); - ImGui::TextUnformatted(ldObj.name.c_str()); - ImGui::EndDragDropSource(); - } - } - } - } break; - } - ImGui::EndChild(); - - ImGui::End(); -} - -namespace ProjectBrussel_UNITY_ID { -glm::quat CalcQuaternionFromDegreesEulerAngle(glm::vec3 eulerAngleDegrees) { - glm::vec3 eulerAngleRadians; - eulerAngleRadians.x = eulerAngleDegrees.x / 180 * M_PI; - eulerAngleRadians.y = eulerAngleDegrees.y / 180 * M_PI; - eulerAngleRadians.z = eulerAngleDegrees.z / 180 * M_PI; - return glm::quat(eulerAngleRadians); -} - -void PushKeyCodeRecorder(App* app, int* writeKey, bool* writeKeyStatus) { - app->PushKeyCaptureCallback([=](int key, int action) { - // Allow the user to cancel by pressing Esc - if (key == GLFW_KEY_ESCAPE) { - return true; - } - - if (action == GLFW_PRESS) { - *writeKey = key; - *writeKeyStatus = writeKeyStatus; - return true; - } - return false; - }); -} - -struct GobjTreeNodeShowInfo { - EditorInstance* in_editor; - GameObject* out_openPopup = nullptr; -}; - -void GobjTreeNode(GobjTreeNodeShowInfo& showInfo, GameObject* object) { - auto& inspector = showInfo.in_editor->GetInspector(); - - auto attachment = object->GetEditorAttachment(); - if (!attachment) { - attachment = EaGameObject::Create(object).release(); - object->SetEditorAttachment(attachment); // NOTE: takes ownership - } - - ImGuiTreeNodeFlags flags = - ImGuiTreeNodeFlags_DefaultOpen | - ImGuiTreeNodeFlags_OpenOnDoubleClick | - ImGuiTreeNodeFlags_OpenOnArrow | - ImGuiTreeNodeFlags_SpanAvailWidth | - ImGuiTreeNodeFlags_NoTreePushOnOpen; - if (inspector.selectedItPtr == object) { - flags |= ImGuiTreeNodeFlags_Selected; - } - - ImGui::PushID(reinterpret_cast<uintptr_t>(object)); - // BEGIN tree node - - bool opened = ImGui::TreeNodeEx(attachment->name.c_str(), flags); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - inspector.SelectTarget(EditorInspector::ITT_GameObject, object); - } - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) - { - showInfo.out_openPopup = object; - } - - if (opened) { - ImGui::Indent(); - for (auto& child : object->GetChildren()) { - GobjTreeNode(showInfo, child); - } - ImGui::Unindent(); - } - - // END tree node - ImGui::PopID(); -}; - -#define GAMEOBJECT_CONSTRUCTOR(ClassName) [](GameWorld* world) -> GameObject* { return new ClassName(world); } -struct CreatableGameObject { - GameObject* (*factory)(GameWorld*); - const char* name; - GameObject::Kind kind; -} creatableGameObjects[] = { - { - .factory = GAMEOBJECT_CONSTRUCTOR(GameObject), - .name = "GameObject", - .kind = GameObject::KD_Generic, - }, - { - .factory = GAMEOBJECT_CONSTRUCTOR(SimpleGeometryObject), - .name = "Simple Geometry", - .kind = GameObject::KD_SimpleGeometry, - }, - { - .factory = GAMEOBJECT_CONSTRUCTOR(BuildingObject), - .name = "Building", - .kind = GameObject::KD_Building, - }, - { - .factory = GAMEOBJECT_CONSTRUCTOR(LevelWrapperObject), - .name = "Level Wrapper", - .kind = GameObject::KD_LevelWrapper, - }, -}; -#undef GAMEOBJECT_CONSTRUCTOR -} // namespace ProjectBrussel_UNITY_ID - -std::unique_ptr<IEditor> IEditor::CreateInstance(App* app) { - return std::make_unique<EditorInstance>(app); -} - -EditorInstance::EditorInstance(App* app) - : mApp{ app } - , mEdContentBrowser(&mEdInspector) { - mEditorCamera.name = "Editor Camera"s; - mEditorCamera.SetEyePos(glm::vec3(0, 0, 1)); - mEditorCamera.SetTargetDirection(glm::vec3(0, 0, -1)); - app->BindActiveCamera(&mEditorCamera); -} - -EditorInstance::~EditorInstance() { -} - -void EditorInstance::OnGameStateChanged(bool running) { - if (running) { - mApp->UnbindActiveCamera(); - } else { - mApp->BindActiveCamera(&mEditorCamera); - } -} - -void EditorInstance::Show() { - using namespace ProjectBrussel_UNITY_ID; - using namespace Tags; - - auto world = mApp->GetWorld(); - auto& io = ImGui::GetIO(); - - ImGui::BeginMainMenuBar(); - if (ImGui::BeginMenu("View")) { - ImGui::MenuItem("ImGui Demo", nullptr, &mWindowVisible_ImGuiDemo); - ImGui::MenuItem("Command Palette", "Ctrl+Shift+P", &mWindowVisible_CommandPalette); - ImGui::MenuItem("Inspector", nullptr, &mWindowVisible_Inspector); - ImGui::MenuItem("Content Browser", "Ctrl+Space", &mWindowVisible_ContentBrowser); - ImGui::MenuItem("World Structure", nullptr, &mWindowVisible_WorldStructure); - ImGui::MenuItem("World Properties", nullptr, &mWindowVisible_WorldProperties); - ImGui::EndMenu(); - } - ImGui::EndMainMenuBar(); - - if (mWindowVisible_ImGuiDemo) { - ImGui::ShowDemoWindow(&mWindowVisible_ImGuiDemo); - } - - if (io.KeyCtrl && io.KeyShift && ImGui::IsKeyPressed(GLFW_KEY_P, false)) { - mWindowVisible_CommandPalette = !mWindowVisible_CommandPalette; - } - if (mWindowVisible_CommandPalette) { - mEdCommandPalette.Show(&mWindowVisible_CommandPalette); - } - - if (io.KeyCtrl && ImGui::IsKeyPressed(GLFW_KEY_SPACE, false)) { - mWindowVisible_ContentBrowser = !mWindowVisible_ContentBrowser; - } - if (mWindowVisible_ContentBrowser) { - mEdContentBrowser.Show(&mWindowVisible_ContentBrowser); - } - - auto& camera = *mApp->GetActiveCamera(); - ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); - ImGuizmo::SetDrawlist(ImGui::GetBackgroundDrawList()); - - if (IsCurrentCameraEditor() && mEcm == ECM_Side3D) { - float viewManipulateRight = io.DisplaySize.x; - float viewManipulateTop = 0; - - // TODO get rid of this massive hack: how to manage const better for intuitively read-only, but write doesn't-care data? - auto& lastFrameInfo = const_cast<RendererFrameInfo&>(mApp->GetWorldRenderer()->GetLastFrameInfo()); - auto& view = lastFrameInfo.matrixView; - auto& proj = lastFrameInfo.matrixProj; - -#if 0 - ImGuizmo::ViewManipulate( - glm::value_ptr(view), - 200.0f, // TODO - ImVec2(viewManipulateRight - 128, viewManipulateTop), - ImVec2(128, 128), - 0x10101010); - // Extract eye and target position from view matrix - // - View matrix transforms world space to view space - // - Inverse view matrix should transform view space into world space - // - In view space, camera's pos is (0,0,0) and the look/forward vector should be (0,0,-1) - auto invView = glm::inverse(view); - camera.eye = invView * glm::vec4(0, 0, 0, 1); - camera.target = camera.eye + glm::vec3(invView * glm::vec4(0, 0, -1, 1)); -#endif - - // TODO draw this as a part of the world so it doesn't block objects -#if 0 - glm::mat4 identity(1.00f); - ImGuizmo::DrawGrid( - glm::value_ptr(view), - glm::value_ptr(proj), - glm::value_ptr(identity), - 100.f); -#endif - - { // Camera controls - auto cameraPos = camera.eye; - auto cameraForward = glm::normalize(camera.target - camera.eye); - // Always move on the horzontal flat plane - cameraForward.y = 0.0f; - - if (mMoveCamKeyboard) { - if (ImGui::IsKeyDown(ImGuiKey_W)) { - cameraPos += mMoveCamSlideSpeed * cameraForward; - } - if (ImGui::IsKeyDown(ImGuiKey_S)) { - auto cameraBack = glm::normalize(-cameraForward); - cameraPos += mMoveCamSlideSpeed * cameraBack; - } - if (ImGui::IsKeyDown(ImGuiKey_A)) { - auto cameraRight = glm::normalize(glm::cross(cameraForward, glm::vec3(0, 1, 0))); - auto cameraLeft = -cameraRight; - cameraPos += mMoveCamSlideSpeed * cameraLeft; - } - if (ImGui::IsKeyDown(ImGuiKey_D)) { - auto cameraRight = glm::normalize(glm::cross(cameraForward, glm::vec3(0, 1, 0))); - cameraPos += mMoveCamSlideSpeed * cameraRight; - } - if (ImGui::IsKeyDown(ImGuiKey_Space)) { - cameraPos.y += mMoveCamSlideSpeed; - } - if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - cameraPos.y -= mMoveCamSlideSpeed; - } - } - - if (mMoveCamScrollWheel) { - cameraPos += cameraForward * io.MouseWheel * mMoveCamScrollSpeed; - } - - camera.SetEyePos(cameraPos); - } - } else { - { // Camera controls - auto cameraPos = camera.eye; - - if (ImGui::IsMouseClicked(ImGuiMouseButton_Right) && !io.WantCaptureMouse && !mDragCam_Happening) { - mDragCam_CamInitial = camera.eye; - mDragCam_CursorInitial = ImGui::GetMousePos(); - mDragCam_Happening = true; - } - if (mDragCam_Happening) { - auto newPos = ImGui::GetMousePos(); - // NOTE: we are emulating as if the mouse is dragging the "canvas", through moving the camera in the opposite direction of the natural position delta - float deltaX = mDragCam_CursorInitial.x - newPos.x; - cameraPos.x = mDragCam_CamInitial.x + deltaX / camera.pixelsPerMeter; - float deltaY = -(mDragCam_CursorInitial.y - newPos.y); // Invert Y delta because ImGui uses top-left origin (mouse moving down translates to positive value, but in our coordinate system down is negative) - cameraPos.y = mDragCam_CamInitial.y + deltaY / camera.pixelsPerMeter; - } - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right)) { - mDragCam_Happening = false; - } - - if (mMoveCamKeyboard) { - if (ImGui::IsKeyDown(ImGuiKey_W)) { - cameraPos.y += mMoveCamSlideSpeed; - } - if (ImGui::IsKeyDown(ImGuiKey_S)) { - cameraPos.y -= mMoveCamSlideSpeed; - } - if (ImGui::IsKeyDown(ImGuiKey_A)) { - cameraPos.x -= mMoveCamSlideSpeed; - } - if (ImGui::IsKeyDown(ImGuiKey_D)) { - cameraPos.x += mMoveCamSlideSpeed; - } - } - - if (mMoveCamScrollWheel) { - cameraPos.z = std::clamp(cameraPos.z + io.MouseWheel, 0.1f, 100.0f); - } - - camera.SetEyePos(cameraPos); - } - } - - if (mWindowVisible_Inspector) { - ImGui::Begin("Inspector"); - switch (mEdInspector.selectedItt) { - case EditorInspector::ITT_GameObject: { - auto object = static_cast<GameObject*>(mEdInspector.selectedItPtr); - ShowInspector(object); - } break; - - case EditorInspector::ITT_Ires: { - auto ires = static_cast<IresObject*>(mEdInspector.selectedItPtr); - ShowInspector(ires); - } break; - - case EditorInspector::ITT_Level: { - auto ldObj = static_cast<LevelManager::LoadableObject*>(mEdInspector.selectedItPtr); - ShowInspector(ldObj); - } break; - - case EditorInspector::ITT_None: break; - } - ImGui::End(); - } - - if (mWindowVisible_WorldProperties) { - ImGui::Begin("World properties"); - ShowWorldProperties(); - ImGui::End(); - } - - if (mWindowVisible_WorldStructure) { - ImGui::Begin("World structure"); - GobjTreeNodeShowInfo showInfo{ - .in_editor = this, - }; - GobjTreeNode(showInfo, &world->GetRoot()); - - if (showInfo.out_openPopup) { - mPopupCurrent_GameObject = showInfo.out_openPopup; - - ImGui::OpenPopup("GameObject Popup"); - ImGui::SetNextWindowPos(ImGui::GetMousePos()); - } - if (ImGui::BeginPopup("GameObject Popup")) { - // Target no longer selected during popup open - if (!mPopupCurrent_GameObject) { - ImGui::CloseCurrentPopup(); - } - - if (ImGui::BeginMenu("Add child")) { - for (size_t i = 0; i < std::size(creatableGameObjects); ++i) { - auto& info = creatableGameObjects[i]; - if (ImGui::MenuItem(info.name)) { - auto object = info.factory(world); - mPopupCurrent_GameObject->AddChild(object); - } - } - ImGui::EndMenu(); - } - ImGui::Separator(); - if (ImGui::MenuItem("Remove")) { - ImGui::DialogConfirmation("Are you sure you want to delete this GameObject?", [object = mPopupCurrent_GameObject](bool yes) { - object->RemoveSelfFromParent(); - delete object; - }); - } - ImGui::EndPopup(); - } - ImGui::End(); - } - - ShowSpriteViewer(); - - ImGui::ShowDialogs(); - ImGui::ShowNotifications(); -} - -void EditorInstance::ShowWorldProperties() { - if (mApp->IsGameRunning()) { - if (ImGui::Button("Pause")) { - mApp->SetGameRunning(false); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("The game is currently running. Click to pause."); - } - } else { - if (ImGui::Button("Play")) { - mApp->SetGameRunning(true); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("The game is currently paused. Click to run."); - } - } - - auto& camera = *mApp->GetActiveCamera(); - - // vvv Camera settings (per instance) - ImGui::TextUnformatted("Active camera:"); - ImGui::Indent(); - - ImGui::TextUnformatted(camera.name.c_str()); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Object at <%p>", &camera); - } - - ImGui::InputFloat3("Eye", glm::value_ptr(camera.eye)); - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { - ImGui::OpenPopup("##CTXMENU"); - } - ImGui::InputFloat3("Target", glm::value_ptr(camera.target)); - if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsItemHovered()) { - ImGui::OpenPopup("##CTXMENU"); - } - if (ImGui::BeginPopup("##CTXMENU", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) { - if (ImGui::MenuItem("Reset to origin")) { - camera.SetEyePos(glm::vec3(1.0f, 1.0f, 1.0f)); - } - if (ImGui::MenuItem("Reset completely")) { - camera.eye = glm::vec3(0, 0, 1); - camera.target = glm::vec3(0, 0, 0); - } - ImGui::EndPopup(); - } - - if (IsCurrentCameraEditor()) { - const char* preview; - switch (mEcm) { - case ECM_2D: preview = "2D view"; break; - case ECM_Side3D: preview = "Side 3D view"; break; - } - if (ImGui::BeginCombo("Mode", preview)) { - if (ImGui::Selectable("2D view", mEcm == ECM_2D)) { - if (mEcm != ECM_2D) { - mEcm = ECM_2D; - - // TODO project eye to world plane - - camera.SetHasPerspective(false); - } - } - if (ImGui::Selectable("Side 3D view", mEcm == ECM_Side3D, ImGuiSelectableFlags_None)) { - if (mEcm != ECM_Side3D) { - mEcm = ECM_Side3D; - - auto origEye = camera.eye; - auto origTarget = camera.target; - - // New setup: focus on the point of world plane that we were originally "hovering above" - camera.target = origEye; - camera.target.z = 0.0f; - - // New setup: move the eye back at an angle - camera.eye = camera.target; - camera.eye.x += 4.0f * std::cos(60.0f); - camera.eye.y += 0.0f; - camera.eye.z += 4.0f * std::sin(60.0f); - - camera.SetHasPerspective(true); - } - } - ImGui::EndCombo(); - } - } - - ImGui::Checkbox("Perspective", &camera.perspective); - if (camera.perspective) { - float fovDegress = camera.fov / M_PI * 180.0f; - if (ImGui::SliderFloat("FOV", &fovDegress, 1.0f, 180.0f)) { - camera.fov = fovDegress / 180.0f * M_PI; - } - } else { - if (ImGui::InputFloat("Pixels per meter", &camera.pixelsPerMeter)) { - camera.pixelsPerMeter = std::max(camera.pixelsPerMeter, 0.0f); - } - } - - ImGui::Unindent(); - // ^^^ Camera settings (per instance) - // vvv Camera control settings - ImGui::TextUnformatted("Camera controls:"); - ImGui::Indent(); - - ImGui::Checkbox("Move camera with WASD", &mMoveCamKeyboard); - ImGui::SliderFloat("Slide speed", &mMoveCamSlideSpeed, 0.1f, 10.0f); - - ImGui::Checkbox("Move camera with scoll wheel", &mMoveCamScrollWheel); - ImGui::SliderFloat("Scroll speed", &mMoveCamScrollSpeed, 0.01, 10.0f); - - ImGui::Unindent(); - // ^^^ Camera control settings -} - -// TOOD move resource-specific and gameobject-specific inspector code into attachments mechanism - -void EditorInstance::ShowInspector(IresObject* ires) { - ires->ShowEditor(*this); -} - -void EditorInstance::ShowInspector(LevelManager::LoadableObject* ldObj) { - using namespace Tags; - using namespace ProjectBrussel_UNITY_ID; - - ImGui::InputText("Name", &ldObj->name); - ImGui::InputTextMultiline("Desciption", &ldObj->description); - - if (ImGui::CollapsingHeader("Instanciation Entries")) { - ldObj->level->ShowInstanciationEntries(*this); - } -} - -void EditorInstance::ShowInspector(GameObject* object) { - using namespace Tags; - using namespace ProjectBrussel_UNITY_ID; - - auto& io = ImGui::GetIO(); - - auto objectEa = static_cast<EaGameObject*>(object->GetEditorAttachment()); - - auto ShowInspector = [&](/*array[6]*/ float* bounds = nullptr) { - glm::mat4 identityMatrix(1.00f); - - if (io.KeyAlt && ImGui::IsKeyPressed(ImGuiKey_T)) - mGuizmo.currOperation = ImGuizmo::TRANSLATE; - if (io.KeyAlt && ImGui::IsKeyPressed(ImGuiKey_R)) - mGuizmo.currOperation = ImGuizmo::ROTATE; - if (io.KeyAlt && ImGui::IsKeyPressed(ImGuiKey_S)) - mGuizmo.currOperation = ImGuizmo::SCALE; - if (ImGui::RadioButton("Translate", mGuizmo.currOperation == ImGuizmo::TRANSLATE)) - mGuizmo.currOperation = ImGuizmo::TRANSLATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Rotate", mGuizmo.currOperation == ImGuizmo::ROTATE)) - mGuizmo.currOperation = ImGuizmo::ROTATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Scale", mGuizmo.currOperation == ImGuizmo::SCALE)) - mGuizmo.currOperation = ImGuizmo::SCALE; - ImGui::SameLine(); - if (ImGui::RadioButton("Universal", mGuizmo.currOperation == ImGuizmo::UNIVERSAL)) - mGuizmo.currOperation = ImGuizmo::UNIVERSAL; - - if (mGuizmo.currOperation != ImGuizmo::SCALE) { - if (ImGui::RadioButton("Local", mGuizmo.currMode == ImGuizmo::LOCAL)) - mGuizmo.currMode = ImGuizmo::LOCAL; - ImGui::SameLine(); - if (ImGui::RadioButton("World", mGuizmo.currMode == ImGuizmo::WORLD)) - mGuizmo.currMode = ImGuizmo::WORLD; - } - - ImGui::Checkbox("##UseSnap", &mGuizmo.useSnap); - ImGui::SameLine(); - switch (mGuizmo.currOperation) { - case ImGuizmo::TRANSLATE: - ImGui::InputFloat3("Pos Snap", &mGuizmo.snap[0]); - break; - case ImGuizmo::ROTATE: - ImGui::InputFloat("Angle Snap", &mGuizmo.snap[0]); - break; - case ImGuizmo::SCALE: - ImGui::InputFloat("Scale Snap", &mGuizmo.snap[0]); - break; - default: break; - } - - if (bounds) { - ImGui::Checkbox("Bound Sizing", &mGuizmo.boundSizing); - if (mGuizmo.boundSizing) { - ImGui::PushID(3); - ImGui::Checkbox("##BoundSizing", &mGuizmo.boundSizingSnap); - ImGui::SameLine(); - ImGui::InputFloat3("Bound Snap", mGuizmo.boundsSnap); - ImGui::PopID(); - } - } - - ImGui::Separator(); - - auto objectPos = object->GetPos(); - if (ImGui::InputFloat3("Translation", &objectPos.x)) { - object->SetPos(objectPos); - } - - auto objectRot = object->GetRotation(); - if (ImGui::InputFloat3("Rotation", &objectEa->eulerAnglesRotation.x)) { - objectRot = CalcQuaternionFromDegreesEulerAngle(objectEa->eulerAnglesRotation); - object->SetRotation(objectRot); - } - - auto objectScale = object->GetScale(); - if (ImGui::InputFloat3("Scale", &objectScale.x)) { - object->SetScale(objectScale); - } - }; - - auto ShowGuizmo = [&](/*array[6]*/ float* bounds = nullptr) { - glm::mat4 identityMatrix(1.00f); - - auto& lastFrameInfo = mApp->GetWorldRenderer()->GetLastFrameInfo(); - auto& cameraViewMat = lastFrameInfo.matrixView; - const float* cameraView = &cameraViewMat[0][0]; - auto& cameraProjMat = lastFrameInfo.matrixProj; - const float* cameraProj = &cameraProjMat[0][0]; - - auto objectPos = object->GetPos(); - auto objectScale = object->GetScale(); - - float matrix[16]; - ImGuizmo::RecomposeMatrixFromComponents(&objectPos.x, &objectEa->eulerAnglesRotation.x, &objectScale.x, matrix); - - bool edited = ImGuizmo::Manipulate( - cameraView, - cameraProj, - mGuizmo.currOperation, - mGuizmo.currMode, - matrix, - nullptr, - mGuizmo.useSnap ? mGuizmo.snap : nullptr, - mGuizmo.boundSizing ? bounds : nullptr, - (bounds && mGuizmo.boundSizingSnap) ? mGuizmo.boundsSnap : nullptr); - - if (edited) { - ImGuizmo::DecomposeMatrixToComponents(matrix, &objectPos.x, &objectEa->eulerAnglesRotation.x, &objectScale.x); - object->SetPos(objectPos); - object->SetRotation(CalcQuaternionFromDegreesEulerAngle(objectEa->eulerAnglesRotation)); - object->SetScale(objectScale); - } - }; - - auto type = object->GetKind(); - switch (type) { - case GameObject::KD_Player: { - ShowInspector(); - ShowGuizmo(); - ImGui::Separator(); - - auto player = static_cast<Player*>(object); - auto ea = static_cast<EaPlayer*>(objectEa); - auto& kb = player->keybinds; - - ImGui::Text("Player #%d", player->GetId()); - - ImGui::TextUnformatted("Spritesheet: "); - ImGui::SameLine(); - IresObject::ShowReferenceSafe(*this, ea->confSprite.Get()); - if (ImGui::BeginDragDropTarget()) { - if (auto payload = ImGui::AcceptDragDropPayload(Metadata::EnumToString(IresObject::KD_Spritesheet).data())) { - auto spritesheet = *static_cast<IresSpritesheet* const*>(payload->Data); - ea->confSprite.Attach(spritesheet); - auto def = spritesheet->GetInstance(); - player->sprite.SetDefinition(def); - player->renderObject.autofill_TextureAtlas.Attach(def->GetAtlas()); - } - ImGui::EndDragDropTarget(); - } - - ImGui::TextUnformatted("Material: "); - ImGui::SameLine(); - IresObject::ShowReferenceSafe(*this, ea->confMaterial.Get()); - if (ImGui::BeginDragDropTarget()) { - if (auto payload = ImGui::AcceptDragDropPayload(Metadata::EnumToString(IresObject::KD_Material).data())) { - auto material = *static_cast<IresMaterial* const*>(payload->Data); - ea->confMaterial.Attach(material); - player->SetMaterial(material->GetInstance()); - } - ImGui::EndDragDropTarget(); - } - - if (ImGui::Button("Load config")) { - bool success = player->LoadFromFile(); - if (success) { - ImGui::AddNotification(ImGuiToast(ImGuiToastType_Success, "Successfully loaded player config")); - } - } - ImGui::SameLine(); - if (ImGui::Button("Save config")) { - bool success = player->SaveToFile(); - if (success) { - ImGui::AddNotification(ImGuiToast(ImGuiToastType_Success, "Successfully saved player config")); - } - } - - ImGui::Text("Move left (%s)", ImGui::GetKeyNameGlfw(kb.keyLeft)); - ImGui::SameLine(); - if (ImGui::Button("Change##Move left")) { - PushKeyCodeRecorder(mApp, &kb.keyLeft, &kb.pressedLeft); - } - - ImGui::Text("Move right (%s)", ImGui::GetKeyNameGlfw(kb.keyRight)); - ImGui::SameLine(); - if (ImGui::Button("Change##Move right")) { - PushKeyCodeRecorder(mApp, &kb.keyRight, &kb.pressedRight); - } - - ImGui::Text("Jump (%s)", ImGui::GetKeyNameGlfw(kb.keyJump)); - ImGui::SameLine(); - if (ImGui::Button("Change##Jump")) { - PushKeyCodeRecorder(mApp, &kb.keyJump, &kb.pressedJump); - } - - ImGui::Text("Attack (%s)", ImGui::GetKeyNameGlfw(kb.keyAttack)); - ImGui::SameLine(); - if (ImGui::Button("Change##Attack")) { - PushKeyCodeRecorder(mApp, &kb.keyAttack, &kb.pressedAttack); - } - } break; - - case GameObject::KD_SimpleGeometry: { - auto sg = static_cast<SimpleGeometryObject*>(object); - - float bounds[6] = { - /*x1*/ -sg->GetSize().x / 2.0f, - /*y1*/ -sg->GetSize().y / 2.0f, - /*z1*/ -sg->GetSize().z / 2.0f, - /*x2*/ +sg->GetSize().x / 2.0f, - /*y2*/ +sg->GetSize().y / 2.0f, - /*z2*/ +sg->GetSize().z / 2.0f, - }; - - ShowInspector(bounds); - ShowGuizmo(bounds); - ImGui::Separator(); - - sg->SetSize(glm::vec3(bounds[3] - bounds[0], bounds[4] - bounds[1], bounds[5] - bounds[2])); - - auto size = sg->GetSize(); - if (ImGui::InputFloat3("Size", &size.x)) { - sg->SetSize(size); - } - - auto xFaceColor = sg->GetXFaceColor(); - if (ImGui::ColorEdit4("X color", &xFaceColor)) { - sg->SetXFaceColor(xFaceColor); - } - auto yFaceColor = sg->GetYFaceColor(); - if (ImGui::ColorEdit4("Y color", &yFaceColor)) { - sg->SetYFaceColor(yFaceColor); - } - auto zFaceColor = sg->GetZFaceColor(); - if (ImGui::ColorEdit4("Z color", &zFaceColor)) { - sg->SetZFaceColor(zFaceColor); - } - - if (ImGui::Button("Sync from X color")) { - sg->SetYFaceColor(xFaceColor); - sg->SetZFaceColor(xFaceColor); - } - ImGui::SameLine(); - if (ImGui::Button("Reset")) { - sg->SetXFaceColor(kXAxisColor); - sg->SetYFaceColor(kYAxisColor); - sg->SetZFaceColor(kZAxisColor); - } - } break; - - case GameObject::KD_Building: { - ShowInspector(); - ShowGuizmo(); - ImGui::Separator(); - - auto b = static_cast<BuildingObject*>(object); - // TODO - } break; - - case GameObject::KD_LevelWrapper: { - ShowInspector(); - ShowGuizmo(); - ImGui::Separator(); - - auto lwo = static_cast<LevelWrapperObject*>(object); - // TODO - } break; - - default: { - ShowInspector(); - ShowGuizmo(); - } break; - } -} - -void EditorInstance::OpenSpriteViewer(SpriteDefinition* sprite) { - mSpriteView_Instance.Attach(sprite); - mSpriteView_Frame = 0; - mSpriteView_OpenNextFrame = true; -} - -void EditorInstance::ShowSpriteViewer() { - if (mSpriteView_Instance == nullptr) return; - if (!mSpriteView_Instance->IsValid()) return; - - if (mSpriteView_OpenNextFrame) { - mSpriteView_OpenNextFrame = false; - ImGui::OpenPopup("Sprite Viewer"); - } - - bool windowOpen = true; - if (ImGui::BeginPopupModal("Sprite Viewer", &windowOpen)) { - auto atlas = mSpriteView_Instance->GetAtlas(); - auto atlasSize = atlas->GetInfo().size; - auto& frames = mSpriteView_Instance->GetFrames(); - - int frameCount = mSpriteView_Instance->GetFrames().size(); - if (ImGui::Button("<")) { - --mSpriteView_Frame; - } - ImGui::SameLine(); - ImGui::Text("%d/%d", mSpriteView_Frame + 1, frameCount); - ImGui::SameLine(); - if (ImGui::Button(">")) { - ++mSpriteView_Frame; - } - // Scrolling down (negative value) should advance, so invert the sign - mSpriteView_Frame += -std::round(ImGui::GetIO().MouseWheel); - // Clamp mSpriteView_Frame to range [0, frameCount) - if (mSpriteView_Frame < 0) { - mSpriteView_Frame = frameCount - 1; - } else if (mSpriteView_Frame >= frameCount) { - mSpriteView_Frame = 0; - } - - auto& currFrame = frames[mSpriteView_Frame]; - auto boundingBox = mSpriteView_Instance->GetBoundingBox(); - ImGui::Text("Frame size: (%d, %d)", boundingBox.x, boundingBox.y); - ImGui::Text("Frame location: (%f, %f) to (%f, %f)", currFrame.u0, currFrame.v0, currFrame.u1, currFrame.v1); - ImGui::Image( - (ImTextureID)(uintptr_t)atlas->GetHandle(), - Utils::FitImage(atlasSize), - ImVec2(currFrame.u0, currFrame.v0), - ImVec2(currFrame.u1, currFrame.v1)); - - ImGui::EndPopup(); - } -} |