#include "EditorCore.hpp" #include "App.hpp" #include "AppConfig.hpp" #include "CpuMesh.hpp" #include "EditorAccessories.hpp" #include "EditorAttachmentImpl.hpp" #include "EditorNotification.hpp" #include "EditorUtils.hpp" #include "GameObjectTags.hpp" #include "Level.hpp" #include "Mesh.hpp" #include "Player.hpp" #define GLFW_INCLUDE_NONE #include #include #include #include #include namespace ProjectBrussel_UNITY_ID { 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; }); } } // namespace ProjectBrussel_UNITY_ID EditorInstance::EditorInstance(App* app, GameWorld* world) : mApp{ app } , mWorld{ world } , mEdContentBrowser(this) {} EditorInstance::~EditorInstance() { } void EditorInstance::Show() { if (!mWorld) return; auto& io = ImGui::GetIO(); if (io.KeyCtrl && ImGui::IsKeyPressed(GLFW_KEY_SPACE, false)) { mEdContentBrowserVisible = !mEdContentBrowserVisible; } ImGui::Begin("World properties"); ShowWorldProperties(); ImGui::End(); ImGui::Begin("World structure"); ShowGameObjectInTree(&mWorld->GetRoot()); ImGui::End(); ImGui::Begin("Inspector"); switch (mSelectedItt) { case ITT_GameObject: ShowInspector(static_cast(mSelectedItPtr)); break; case ITT_Shader: ShowInspector(static_cast(mSelectedItPtr)); break; case ITT_None: break; } ImGui::End(); if (mEdContentBrowserVisible) { mEdContentBrowser.Show(&mEdContentBrowserVisible); } } void EditorInstance::SelectIt(void* ptr, InspectorTargetType itt) { mSelectedItPtr = ptr; mSelectedItt = itt; } void EditorInstance::ShowWorldProperties() { } // TOOD move resource-specific and gameobject-specific inspector code into attachments mechanism void EditorInstance::ShowInspector(Shader* shader) { using namespace Tags; using namespace ProjectBrussel_UNITY_ID; auto info = shader->GetInfo(); if (!info) { ImGui::TextUnformatted("No info present for this shader."); if (ImGui::Button("Create empty info")) { shader->CreateEmptyInfoIfAbsent(); } if (ImGui::Button("Gather info")) { shader->GatherInfoIfAbsent(); } return; } auto& name = shader->GetName(); bool isAnnoymous = name.empty(); if (isAnnoymous) { ImGui::Text("", (void*)shader); } else { ImGui::Text("Name: %s", shader->GetName().c_str()); } // TODO use std::filesystem::path auto GetMetadataPath = [&](char* path, int pathLength) { snprintf(path, pathLength, "%s/Shaders/%s.json", AppConfig::assetDir.c_str(), shader->GetName().c_str()); }; if (ImGui::Button("Reimport metadata", isAnnoymous)) { char path[512]; GetMetadataPath(path, sizeof(path)); info->LoadFromFile(path); } ImGui::SameLine(); if (ImGui::Button("Export metadata", isAnnoymous)) { char path[512]; GetMetadataPath(path, sizeof(path)); info->SaveToFile(path); } auto ShowThing = [&](const std::vector& things) { for (auto& thing : things) { ImGui::BulletText("Location %d\nName: %s\nSemantic: %s\nType: %s %dx%d", thing.variable.location, thing.variable.name.c_str(), Tags::NameOf(thing.semantic).data(), Tags::NameOfGLType(thing.variable.scalarType).data(), thing.variable.width, thing.variable.height); } }; if (ImGui::CollapsingHeader("Inputs")) { ShowThing(info->inputs); } if (ImGui::CollapsingHeader("Outputs")) { ShowThing(info->outputs); } if (ImGui::CollapsingHeader("Uniforms")) { } if (ImGui::CollapsingHeader("Uniform blocks")) { } } void EditorInstance::ShowInspector(GameObject* object) { using namespace Tags; using namespace ProjectBrussel_UNITY_ID; auto type = object->GetTypeTag(); switch (type) { case Tags::GOT_Player: { ShowGameObjecetFields(object); ImGui::Separator(); auto player = static_cast(object); auto& kb = player->keybinds; ImGui::Text("Player #%d", player->GetId()); 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 Tags::GOT_LevelWrapper: { ShowGameObjecetFields(object); ImGui::Separator(); auto lwo = static_cast(object); // TODO } break; default: ShowGameObjecetFields(object); break; } } void EditorInstance::ShowGameObjecetFields(GameObject* object) { auto pos = object->GetPos(); if (ImGui::InputFloat3("Position", &pos.x)) { object->SetPos(pos); } auto quat = object->GetRotation(); if (ImGui::InputFloat4("Rotation", &quat.x)) { object->SetRotation(quat); } } void EditorInstance::ShowGameObjectInTree(GameObject* object) { auto attachment = object->GetEditorAttachment(); if (!attachment) { attachment = EaGameObject::Create(object).release(); object->SetEditorAttachment(attachment); // NOTE: takes ownership } ImGuiTreeNodeFlags flags = 0; flags |= ImGuiTreeNodeFlags_DefaultOpen; flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick; flags |= ImGuiTreeNodeFlags_OpenOnArrow; flags |= ImGuiTreeNodeFlags_SpanAvailWidth; if (mSelectedItPtr == object) { flags |= ImGuiTreeNodeFlags_Selected; } if (ImGui::TreeNodeEx(attachment->name.c_str(), flags)) { if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) { mSelectedItPtr = object; mSelectedItt = ITT_GameObject; } for (auto& child : object->GetChildren()) { ShowGameObjectInTree(child); } ImGui::TreePop(); } }