diff --git a/docs/tasks/core.todo b/docs/tasks/core.todo index 52ae2c0..73b4303 100644 --- a/docs/tasks/core.todo +++ b/docs/tasks/core.todo @@ -9,7 +9,8 @@ Build System: Core: ✔ Wrap NFD in an API in the platform module @low @done(22-05-31 15:44) Wrapper added to utils - not platform - ☐ Add custom (64 bit?) UUID generator (based on Chreno's UUIDs) + ✔ Add custom (64 bit?) UUID generator (based on Chreno's UUIDs) @done(22-06-27 13:34) + ☐ Allow Entities to have children @medium ✔ Add Terminal subsystem to allow for printing colored text in a cross-platform way @done(22-05-16 18:05) ✔ Create a LogListener that uses the colored text (replace the current stdout listener) @done(22-05-16 18:23) ✔ Replace XML with JSON (https://github.com/nlohmann/json) @high @done(22-05-19 15:35) diff --git a/docs/tasks/editor.todo b/docs/tasks/editor.todo index 15e55d4..178d3f3 100644 --- a/docs/tasks/editor.todo +++ b/docs/tasks/editor.todo @@ -7,10 +7,13 @@ Editor: ✔ Implement Run Mode interface class @high @done (2/8/2022, 4:05:17 PM) ✔ Reference raw asset files in a "content" folder@high @done (3/3/2022, 3:15:32 PM) ✔ Platform independant file browsing @done (2/8/2022, 4:05:29 PM) + ☐ Turn World into an editor asset that can be created + ☐ Store entities in the World object + ☐ Implement Saving/loading the World asset ☐ Test the Asset Trashing system @high ☐ Add ability to browse and restore trashed assets - ☐ Scan script files to make sure they don't overwrite globals - ☐ Figure out how to make game asset types integrate with editor asset types @critical + ✔ Figure out how to make game asset types integrate with editor asset types @critical @done(22-06-27 13:32) + - Probably just wrap the game object in an EditorAsset object if needed Panel System: ☐ Allow for saving custom panel layouts @low diff --git a/src/run_modes/editor/component_guis.cpp b/src/run_modes/editor/component_guis.cpp index ec135c7..c5d6f34 100644 --- a/src/run_modes/editor/component_guis.cpp +++ b/src/run_modes/editor/component_guis.cpp @@ -15,9 +15,13 @@ namespace lunarium { namespace editor { void CompGui::RenderTagComp(TagComponent& comp) { + const int BUFFER_SIZE = 256; + static char buffer[BUFFER_SIZE] = ""; ImGui::Text("Tag:"); ImGui::SameLine(); - ImGui::InputText("##Tag", comp.Info.data(), comp.Info.capacity()); + strcpy(buffer, comp.Info.c_str()); + ImGui::InputText("##Tag", buffer, BUFFER_SIZE); + comp.Info = buffer; } void CompGui::RenderTransformComp(TransformComponent& comp) diff --git a/src/run_modes/editor/editor.cpp b/src/run_modes/editor/editor.cpp index ca3eef1..bf35d90 100644 --- a/src/run_modes/editor/editor.cpp +++ b/src/run_modes/editor/editor.cpp @@ -28,7 +28,7 @@ #include -// TEST STUFF +// Game objects #include #include #include @@ -69,7 +69,7 @@ namespace editor } mPanelManager.AddPanel(new AssetBrowser("", this), mPanels.AssetBrowser).LogIfFailed(LogCat); - mPanelManager.AddPanel(new WorldTree(), mPanels.WorldTree).LogIfFailed(LogCat); + mPanelManager.AddPanel(new WorldTree(this), mPanels.WorldTree).LogIfFailed(LogCat); mPanelManager.AddPanel(new WorldView(), mPanels.WorldView).LogIfFailed(LogCat); mPanelManager.AddPanel(new PropertiesView(), mPanels.PropertiesView).LogIfFailed(LogCat); @@ -434,5 +434,14 @@ namespace editor ImGui::End(); } + ///////////////////////////////////////////////////////////////////// + // PANEL EVENTS + ///////////////////////////////////////////////////////////////////// + + void Editor::OnEntitySelect(lunarium::Entity* pEnt) + { + //Logger::Info(Editor::LogCat, "ENTITY SELECT: %ll", (long long) pEnt); + ((PropertiesView*)mPanelManager.GetPanel(mPanels.PropertiesView))->SetSelection(pEnt); + } } } \ No newline at end of file diff --git a/src/run_modes/editor/editor.h b/src/run_modes/editor/editor.h index 895e3e4..aa4bd9d 100644 --- a/src/run_modes/editor/editor.h +++ b/src/run_modes/editor/editor.h @@ -23,6 +23,7 @@ namespace lunarium { class World; + class Entity; } namespace lunarium { namespace editor @@ -56,6 +57,9 @@ namespace lunarium { namespace editor std::filesystem::path GetAssetBrowserLocation(); Project* GetProject(); + // Panel events + void OnEntitySelect(lunarium::Entity* pEnt); + private: Editor(const Editor&) = delete; const Editor& operator=(const Editor&) = delete; diff --git a/src/run_modes/editor/panels/properties_view.cpp b/src/run_modes/editor/panels/properties_view.cpp index 4ad18e1..defabb2 100644 --- a/src/run_modes/editor/panels/properties_view.cpp +++ b/src/run_modes/editor/panels/properties_view.cpp @@ -18,35 +18,84 @@ namespace lunarium { namespace editor { PropertiesView::PropertiesView() : Panel("Properties", PanelDockZone::DDZ_RIGHT, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), - mpSelectedAsset(nullptr), mpSelectedEntity(nullptr) + mpSelectedAsset(nullptr), mpSelectedEntity(nullptr), mIsLocked(false) { } + ///////////////////////////////////////////////////////////////////// + // RENDER METHOD + ///////////////////////////////////////////////////////////////////// + void PropertiesView::DoFrame() { + ShowToolBar(); + if (mpSelectedEntity) { - // TODO: iterate through components - if (mpSelectedEntity->HasComponent()) - { - CompGui::RenderTagComp(mpSelectedEntity->GetComponent()); - } + ShowEntity(); + } + + if (mpSelectedAsset) + { + ShowAsset(); } } + ///////////////////////////////////////////////////////////////////// + // INTERFACE METHODS + ///////////////////////////////////////////////////////////////////// + void PropertiesView::SetSelection(Entity* pEntity) { + if (mIsLocked) + { + return; + } + mpSelectedAsset = nullptr; mpSelectedEntity = pEntity; } void PropertiesView::SetSelection(EditorAsset* pAsset) { + if (mIsLocked) + { + return; + } + mpSelectedEntity = nullptr; mpSelectedAsset = pAsset; } + ///////////////////////////////////////////////////////////////////// + // HELPER METHODS HELPER METHODS + ///////////////////////////////////////////////////////////////////// + void PropertiesView::ShowToolBar() + { + ImGui::BeginChild("##PropsToolBar", ImVec2(0, ImGui::GetFrameHeightWithSpacing())); + + ImGui::Checkbox("Locked", &mIsLocked); + + ImGui::EndChild(); + ImGui::Separator(); + } + + void PropertiesView::ShowEntity() + { + ImGui::Text("Components"); + + // TODO: iterate through components + if (mpSelectedEntity->HasComponent()) + { + CompGui::RenderTagComp(mpSelectedEntity->GetComponent()); + } + } + + void PropertiesView::ShowAsset() + { + + } }} \ No newline at end of file diff --git a/src/run_modes/editor/panels/properties_view.h b/src/run_modes/editor/panels/properties_view.h index 658ec6c..01fc13a 100644 --- a/src/run_modes/editor/panels/properties_view.h +++ b/src/run_modes/editor/panels/properties_view.h @@ -32,11 +32,18 @@ namespace editor void DoFrame(); private: + bool mIsLocked; std::vector mCustomProps; // Only ONE of these should be set at a time Entity* mpSelectedEntity; EditorAsset* mpSelectedAsset; + + private: // HELPERS + + void ShowToolBar(); + void ShowEntity(); + void ShowAsset(); }; } } diff --git a/src/run_modes/editor/panels/world_tree.cpp b/src/run_modes/editor/panels/world_tree.cpp index 1e735fc..6bf5ee1 100644 --- a/src/run_modes/editor/panels/world_tree.cpp +++ b/src/run_modes/editor/panels/world_tree.cpp @@ -1,12 +1,13 @@ /****************************************************************************** -* File - worldTree.cpp -* Author - Joey Pollack -* Date - 2021/11/04 (y/m/d) -* Mod Date - 2021/11/04 (y/m/d) -* Description - The tree view listing all objects in the world -******************************************************************************/ + * File - worldTree.cpp + * Author - Joey Pollack + * Date - 2021/11/04 (y/m/d) + * Mod Date - 2021/11/04 (y/m/d) + * Description - The tree view listing all objects in the world + ******************************************************************************/ #include "world_tree.h" +#include #include #include #include @@ -17,109 +18,135 @@ namespace lunarium { -namespace editor -{ - WorldTree::WorldTree() - : Panel("World Tree", PanelDockZone::DDZ_LEFT, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), - mpWorld(new lunarium::World), mDoNewEntity(false) - { - - } - - void WorldTree::SetWorld(lunarium::World* pWorld) - { - mpWorld = pWorld; - } - - lunarium::World* WorldTree::GetWorld() - { - return mpWorld; - } - - void WorldTree::DoFrame() + namespace editor { - if (ImGui::TreeNode("World Root") && mpWorld) + WorldTree::WorldTree(Editor *editor) + : Panel("World Tree", PanelDockZone::DDZ_LEFT, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), + mpEditor(editor), + // TODO: Temp world created here + mpWorld(new lunarium::World), + mDoNewEntity(false), mpSelectedEntity(nullptr) { - // List all world entities - // This will fail if we end up implementing child entities - // In that case this needs to become recursive - int idx = 0; - for (auto iter = mpWorld->EntitiesBegin(); !mpWorld->EntitiesIsEnd(iter); iter++, idx++) - { - std::string name = "Entity"; - name += std::to_string(idx); - if ((*iter)->HasComponent()) + AddPopup(PopUp::NEW_ENTITY, "New Entity", [](Panel *p) { - name = (*iter)->GetComponent().Info; - } + WorldTree* pWT = (WorldTree*)p; + char name_buf[64] = "NewEntity"; + ImGui::TextUnformatted("Entity Name: "); + ImGui::SameLine(); + if (ImGui::InputText("##Entity Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) + { + LUUID id = pWT->mpWorld->CreateEntity(); + pWT->mpWorld->GetEntity(id)->AddComponent(); + TagComponent& tc = pWT->mpWorld->GetEntity(id)->GetComponent(); + tc.Info = name_buf; + return false; + } - if (ImGui::TreeNode(name.c_str())) - { + if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) + { + return false; + } - ImGui::TreePop(); - } - } + return true; + }); + } - ImGui::TreePop(); + void WorldTree::SetWorld(lunarium::World *pWorld) + { + mpWorld = pWorld; } - - DoContextMenu(); - HandlePopupEvents(); - } + lunarium::World *WorldTree::GetWorld() + { + return mpWorld; + } - void WorldTree::DoContextMenu() - { - if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight)) + void WorldTree::DoFrame() { - if (ImGui::Button("Create New Entity")) + Entity *pSelection = nullptr; + if (ImGui::TreeNode("World Root") && mpWorld) { - if (!mpWorld) - { - Logger::Warn(Editor::LogCat, "Can not create new entity - World pointer is null"); - } - else + // List all world entities + // This will fail if we end up implementing child entities + // In that case this needs to become recursive + int idx = 0; + for (auto iter = mpWorld->EntitiesBegin(); !mpWorld->EntitiesIsEnd(iter); iter++, idx++) { - mDoNewEntity = true; + std::string name = "Entity"; + name += std::to_string(idx); + if ((*iter)->HasComponent()) + { + name = (*iter)->GetComponent().Info; + } + + if ((*iter)->HasChildren()) + { + // TODO: Recurse through children + if (ImGui::TreeNode(name.c_str())) + { + ImGui::TreePop(); + } + } + else + { + bool is_selected = false; + if ((*iter) == mpSelectedEntity) + { + is_selected = true; + } + if (ImGui::Selectable(name.c_str(), &is_selected)) + { + mpSelectedEntity = (*iter); + if (is_selected) + { + mpEditor->OnEntitySelect(mpSelectedEntity); + } + else + { + mpEditor->OnEntitySelect(nullptr); + mpSelectedEntity = nullptr; + } + } + } } - } - ImGui::EndPopup(); - } - } - void WorldTree::HandlePopupEvents() - { - if (mDoNewEntity) - { - PopupNewEntity(); - ImGui::OpenPopup("New Entity"); - } - } + ImGui::TreePop(); + } - void WorldTree::PopupNewEntity() - { - if (ImGui::BeginPopupContextItem("New Entity")) - { - char name_buf[64] = "NewEntity"; - ImGui::TextUnformatted("Entity Name: "); - ImGui::SameLine(); - if (ImGui::InputText("##Entity Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) { - LUUID id = mpWorld->CreateEntity(); - mpWorld->GetEntity(id)->AddComponent(); - TagComponent& tc = mpWorld->GetEntity(id)->GetComponent(); - tc.Info = name_buf; - mDoNewEntity = false; - ImGui::CloseCurrentPopup(); + mpSelectedEntity = nullptr; + mpEditor->OnEntitySelect(nullptr); } - if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) + // TODO: Find a way to change this so that OnEntitySelect is not called every frame + // if (pSelection != mpSelectedEntity) + // { + // mpSelectedEntity = pSelection; + // mpEditor->OnEntitySelect(mpSelectedEntity); + // } + + DoContextMenu(); + } + + void WorldTree::DoContextMenu() + { + if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight)) { - mDoNewEntity = false; - ImGui::CloseCurrentPopup(); + if (ImGui::Button("Create New Entity")) + { + if (!mpWorld) + { + Logger::Warn(Editor::LogCat, "Can not create new entity - World pointer is null"); + } + else + { + OpenPopup(PopUp::NEW_ENTITY); + } + } + ImGui::EndPopup(); } - ImGui::EndPopup(); } + } -} } \ No newline at end of file diff --git a/src/run_modes/editor/panels/world_tree.h b/src/run_modes/editor/panels/world_tree.h index a79a7a9..3ddfa67 100644 --- a/src/run_modes/editor/panels/world_tree.h +++ b/src/run_modes/editor/panels/world_tree.h @@ -14,13 +14,16 @@ namespace lunarium { class World; + class Entity; namespace editor { + class Editor; + class WorldTree : public Panel { public: - WorldTree(); + WorldTree(Editor* editor); void SetWorld(lunarium::World* pWorld); lunarium::World* GetWorld(); @@ -29,6 +32,8 @@ namespace editor private: lunarium::World* mpWorld; + Editor* mpEditor; + Entity* mpSelectedEntity; // Context menus void DoContextMenu(); @@ -38,6 +43,13 @@ namespace editor void HandlePopupEvents(); void PopupNewEntity(); + + + private: // POPUP ENUMS + enum PopUp + { + NEW_ENTITY, + }; }; } } diff --git a/src/world/entity.cpp b/src/world/entity.cpp index 09f81c3..8243b98 100644 --- a/src/world/entity.cpp +++ b/src/world/entity.cpp @@ -33,4 +33,10 @@ namespace lunarium { return mUUID; } + + + bool Entity::HasChildren() const + { + return mChildren.size() > 0; + } } \ No newline at end of file diff --git a/src/world/entity.h b/src/world/entity.h index 3e05b7e..e1ebf4b 100644 --- a/src/world/entity.h +++ b/src/world/entity.h @@ -64,11 +64,13 @@ namespace lunarium LUUID GetUUID() const; + bool HasChildren() const; + private: LUUID mUUID; entt::entity mHandle; World& mWorld; // The world the entity is contained within - //entt::registry* mpRegistry; + std::vector mChildren; private: void Init();