aboutsummaryrefslogtreecommitdiff
path: root/source/EditorCore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/EditorCore.cpp')
-rw-r--r--source/EditorCore.cpp289
1 files changed, 234 insertions, 55 deletions
diff --git a/source/EditorCore.cpp b/source/EditorCore.cpp
index 59da2b3..601a850 100644
--- a/source/EditorCore.cpp
+++ b/source/EditorCore.cpp
@@ -2,17 +2,20 @@
#include "App.hpp"
#include "AppConfig.hpp"
-#include "CpuMesh.hpp"
#include "EditorAccessories.hpp"
#include "EditorAttachmentImpl.hpp"
+#include "EditorCommandPalette.hpp"
#include "EditorNotification.hpp"
#include "EditorUtils.hpp"
-#include "GameObjectTags.hpp"
+#include "GameObject.hpp"
#include "Level.hpp"
#include "Macros.hpp"
#include "Mesh.hpp"
#include "Player.hpp"
+#include "SceneThings.hpp"
#include "ScopeGuard.hpp"
+#include "VertexIndex.hpp"
+#include "YCombinator.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
@@ -217,6 +220,84 @@ void PushKeyCodeRecorder(App* app, int* writeKey, bool* writeKeyStatus) {
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
EditorInstance::EditorInstance(App* app, GameWorld* world)
@@ -228,44 +309,129 @@ EditorInstance::~EditorInstance() {
}
void EditorInstance::Show() {
- if (!mWorld) return;
+ using namespace ProjectBrussel_UNITY_ID;
+ using namespace Tags;
+
+ if (!mWorld) {
+ return;
+ }
auto& io = ImGui::GetIO();
- if (io.KeyCtrl && ImGui::IsKeyPressed(GLFW_KEY_SPACE, false)) {
- mEdContentBrowserVisible = !mEdContentBrowserVisible;
+
+ 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();
- ImGui::Begin("World properties");
- ShowWorldProperties();
- ImGui::End();
+ if (mWindowVisible_ImGuiDemo) {
+ ImGui::ShowDemoWindow(&mWindowVisible_ImGuiDemo);
+ }
- ImGui::Begin("World structure");
- ShowGameObjectInTree(&mWorld->GetRoot());
- ImGui::End();
+ if (io.KeyCtrl && io.KeyShift && ImGui::IsKeyPressed(GLFW_KEY_P, false)) {
+ mWindowVisible_CommandPalette = !mWindowVisible_CommandPalette;
+ }
+ if (mWindowVisible_CommandPalette) {
+ ImCmd::ShowCommandPaletteWindow("Command Palette", &mWindowVisible_CommandPalette);
+ }
- ImGui::Begin("Inspector");
- switch (mEdInspector.selectedItt) {
- case EditorInspector::ITT_GameObject: {
- ShowInspector(static_cast<GameObject*>(mEdInspector.selectedItPtr));
- } break;
+ if (io.KeyCtrl && ImGui::IsKeyPressed(GLFW_KEY_SPACE, false)) {
+ mWindowVisible_ContentBrowser = !mWindowVisible_ContentBrowser;
+ }
+ if (mWindowVisible_ContentBrowser) {
+ mEdContentBrowser.Show(&mWindowVisible_ContentBrowser);
+ }
- case EditorInspector::ITT_Ires: {
- auto ires = static_cast<IresObject*>(mEdInspector.selectedItPtr);
- ShowInspector(ires);
- } break;
+ if (mWindowVisible_Inspector) {
+ ImGui::Begin("Inspector");
+ switch (mEdInspector.selectedItt) {
+ case EditorInspector::ITT_GameObject: {
+ ShowInspector(static_cast<GameObject*>(mEdInspector.selectedItPtr));
+ } break;
- case EditorInspector::ITT_None: break;
+ case EditorInspector::ITT_Ires: {
+ auto ires = static_cast<IresObject*>(mEdInspector.selectedItPtr);
+ ShowInspector(ires);
+ } break;
+
+ case EditorInspector::ITT_None: break;
+ }
+ ImGui::End();
}
- ImGui::End();
- if (mEdContentBrowserVisible) {
- mEdContentBrowser.Show(&mEdContentBrowserVisible);
+ if (mWindowVisible_WorldProperties) {
+ ImGui::Begin("World properties");
+ ShowWorldProperties();
+ ImGui::End();
+ }
+
+ if (mWindowVisible_WorldStructure) {
+ ImGui::Begin("World structure");
+ {
+ GobjTreeNodeShowInfo showInfo{
+ .in_editor = this,
+ };
+ GobjTreeNode(showInfo, &mWorld->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(mWorld);
+ mPopupCurrent_GameObject->AddChild(object);
+ }
+ }
+ ImGui::EndMenu();
+ }
+ ImGui::Separator();
+ if (ImGui::MenuItem("Remove")) {
+ // TODO
+ }
+ ImGui::EndPopup();
+ }
+ }
+ ImGui::End();
}
ShowSpriteViewer();
+
+ 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.");
+ }
+ }
}
// TOOD move resource-specific and gameobject-specific inspector code into attachments mechanism
@@ -290,17 +456,42 @@ void EditorInstance::ShowInspector(GameObject* object) {
}
};
- auto type = object->GetTypeTag();
+ auto type = object->GetKind();
switch (type) {
- case Tags::GOT_Player: {
+ case GameObject::KD_Player: {
ShowFields();
ImGui::Separator();
auto player = static_cast<Player*>(object);
+ auto ea = static_cast<EaPlayer*>(player->GetEditorAttachment());
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(IresObject::ToString(IresObject::KD_Spritesheet).data())) {
+ auto spritesheet = *static_cast<IresSpritesheet* const*>(payload->Data);
+ ea->confSprite.Attach(spritesheet);
+ player->sprite.SetDefinition(spritesheet->GetInstance());
+ }
+ ImGui::EndDragDropTarget();
+ }
+
+ ImGui::TextUnformatted("Material: ");
+ ImGui::SameLine();
+ IresObject::ShowReferenceSafe(*this, ea->confMaterial.Get());
+ if (ImGui::BeginDragDropTarget()) {
+ if (auto payload = ImGui::AcceptDragDropPayload(IresObject::ToString(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) {
@@ -340,49 +531,37 @@ void EditorInstance::ShowInspector(GameObject* object) {
}
} break;
- case Tags::GOT_LevelWrapper: {
+ case GameObject::KD_SimpleGeometry: {
ShowFields();
ImGui::Separator();
- auto lwo = static_cast<LevelWrapperObject*>(object);
+ auto sg = static_cast<SimpleGeometryObject*>(object);
// TODO
} break;
- default: {
+ case GameObject::KD_Building: {
ShowFields();
- } break;
- }
-}
+ ImGui::Separator();
-void EditorInstance::ShowGameObjectInTree(GameObject* object) {
- auto attachment = object->GetEditorAttachment();
- if (!attachment) {
- attachment = EaGameObject::Create(object).release();
- object->SetEditorAttachment(attachment); // NOTE: takes ownership
- }
+ auto b = static_cast<BuildingObject*>(object);
+ // TODO
+ } break;
- ImGuiTreeNodeFlags flags = 0;
- flags |= ImGuiTreeNodeFlags_DefaultOpen;
- flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick;
- flags |= ImGuiTreeNodeFlags_OpenOnArrow;
- flags |= ImGuiTreeNodeFlags_SpanAvailWidth;
- if (mEdInspector.selectedItPtr == object) {
- flags |= ImGuiTreeNodeFlags_Selected;
- }
+ case GameObject::KD_LevelWrapper: {
+ ShowFields();
+ ImGui::Separator();
- if (ImGui::TreeNodeEx(attachment->name.c_str(), flags)) {
- if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
- mEdInspector.SelectTarget(EditorInspector::ITT_GameObject, object);
- }
+ auto lwo = static_cast<LevelWrapperObject*>(object);
+ // TODO
+ } break;
- for (auto& child : object->GetChildren()) {
- ShowGameObjectInTree(child);
- }
- ImGui::TreePop();
+ default: {
+ ShowFields();
+ } break;
}
}
-void EditorInstance::OpenSpriteViewer(Sprite* sprite) {
+void EditorInstance::OpenSpriteViewer(SpriteDefinition* sprite) {
mSpriteView_Instance.Attach(sprite);
mSpriteView_Frame = 0;
mSpriteView_OpenNextFrame = true;