aboutsummaryrefslogtreecommitdiff
path: root/source/30-game/EditorCorePrivate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/30-game/EditorCorePrivate.cpp')
-rw-r--r--source/30-game/EditorCorePrivate.cpp1171
1 files changed, 0 insertions, 1171 deletions
diff --git a/source/30-game/EditorCorePrivate.cpp b/source/30-game/EditorCorePrivate.cpp
deleted file mode 100644
index 3efa33c..0000000
--- a/source/30-game/EditorCorePrivate.cpp
+++ /dev/null
@@ -1,1171 +0,0 @@
-#include "EditorCorePrivate.hpp"
-
-#include "App.hpp"
-#include "AppConfig.hpp"
-#include "EditorAccessories.hpp"
-#include "EditorAttachmentImpl.hpp"
-#include "EditorCommandPalette.hpp"
-#include "EditorUtils.hpp"
-#include "GameObject.hpp"
-#include "Mesh.hpp"
-#include "Player.hpp"
-#include "SceneThings.hpp"
-#include "VertexIndex.hpp"
-
-#include <ImGuiNotification.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 <rapidjson/document.h>
-#include <rapidjson/filereadstream.h>
-#include <rapidjson/filewritestream.h>
-#include <rapidjson/writer.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();
- }
-
- ImGui::SameLine();
- if (ImGui::Button("...")) {
- ImGui::OpenPopup("More Actions");
- }
- if (ImGui::BeginPopup("More Actions")) {
- if (ImGui::MenuItem("Rewrite all Ires to disk")) {
- IresManager::instance->OverwriteAllToDisk();
- }
- 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
-
-void SaveRendererBindings(const Renderer& renderer) {
- auto file = Utils::OpenCstdioFile("assets/GameRendererBindings.json", Utils::WriteTruncate);
- if (!file) return;
- DEFER {
- fclose(file);
- };
-
- char writerBuffer[65536];
- rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer));
- rapidjson::Writer writer(stream);
-
- rapidjson::Document root(rapidjson::kObjectType);
- renderer.SaveBindings(root, root);
-
- root.Accept(writer);
-}
-} // 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)
- , mEdGuides(app, this) //
-{
- 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("Keyboard Viewer", nullptr, &mWindowVisible_KeyboardViewer);
- 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);
- }
-
- if (mWindowVisible_KeyboardViewer) {
- mEdKbViewer.Show(&mWindowVisible_KeyboardViewer);
- }
-
- 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() {
- using namespace ProjectBrussel_UNITY_ID;
-
- 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& renderer = *mApp->GetWorldRenderer();
- auto& camera = *mApp->GetActiveCamera();
-
- if (ImGui::CollapsingHeader("Renderer settings")) {
- if (ImGui::Checkbox("Draw shaded", &mRenderer_DrawShaded)) {
- renderer.SetRenderOption(Renderer::RO_Shading, mRenderer_DrawShaded);
- }
- if (ImGui::Checkbox("Draw wireframe", &mRenderer_DrawWireFrame)) {
- renderer.SetRenderOption(Renderer::RO_Wireframe, mRenderer_DrawWireFrame);
- }
-
- if (auto ires = Utils::SimpleIresReceptor<IresMaterial>(renderer.binding_WireframeMaterial->GetIres(), *this, IresObject::KD_Material)) {
- renderer.binding_WireframeMaterial.Attach(ires->GetInstance());
- SaveRendererBindings(renderer);
- }
- }
-
- if (ImGui::CollapsingHeader("Camera settings")) {
- // 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();
- }
-}