diff --git a/CopiumEngine/src/copium/core/Scene.cpp b/CopiumEngine/src/copium/core/Scene.cpp index f9b25fa..7496164 100644 --- a/CopiumEngine/src/copium/core/Scene.cpp +++ b/CopiumEngine/src/copium/core/Scene.cpp @@ -154,18 +154,40 @@ namespace Copium ImGui::Begin("Entity Tree View"); ecs->Each([&](EntityId entityId, SerializableC& serializable) { Entity entity{ecs.get(), entityId}; - std::string name; - if (entity.HasComponent()) - name = entity.GetComponent().name; - if (name.empty()) - name = String::Format("Entity %u", entity.GetId()); - ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; - if (selectedEntity == entity) - flags |= ImGuiTreeNodeFlags_Selected; - ImGui::TreeNodeEx(name.c_str(), flags); - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) - selectedEntity = entity; - }); + std::string name; + if (entity.HasComponent()) + name = entity.GetComponent().name; + if (name.empty()) + name = String::Format("Entity %u", entity.GetId()); + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; + if (selectedEntity == entity) + flags |= ImGuiTreeNodeFlags_Selected; + ImGui::TreeNodeEx(name.c_str(), flags); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + ImGui::SetDragDropPayload("ENTITY_UUID", &entity.GetComponent().uuid, sizeof(Uuid)); + ImGui::Text(name.c_str()); + ImGui::EndDragDropSource(); + } + else if (ImGui::IsMouseReleased(0) && ImGui::IsItemHovered() && !ImGui::IsItemToggledOpen()) + selectedEntity = entity; + + if (ImGui::BeginPopupContextItem()) + { + for (auto& componentHandler : componentHandlers) + { + if (!componentHandler->IsFlagComponent() && !componentHandler->HasComponent(entity)) + { + if (ImGui::Selectable(String::Format("Add %s", componentHandler->GetName().c_str()).c_str())) + { + componentHandler->AddDefaultComponent(entity); + } + } + } + ImGui::EndPopup(); + } + }); ImGui::End(); } diff --git a/CopiumEngine/src/copium/example/ComponentHandler.h b/CopiumEngine/src/copium/example/ComponentHandler.h index 1825d18..e40b9ba 100644 --- a/CopiumEngine/src/copium/example/ComponentHandler.h +++ b/CopiumEngine/src/copium/example/ComponentHandler.h @@ -3,6 +3,7 @@ #include "copium/example/ComponentHandlerBase.h" #include +#include namespace Copium { @@ -19,21 +20,20 @@ namespace Copium { serializedName = name; serializedName.erase(std::remove(serializedName.begin(), serializedName.end(), ' '), serializedName.end()); - CP_INFO("%s", serializedName.c_str()); } - void Serialize(Entity entity, MetaFile& metaFile) override + void Serialize(Entity entity, MetaFile& metaFile) const override { if(entity.HasComponent()) metaFile.AddMetaClass(serializedName, MetaFileClass{}); } - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { entity.AddComponent(); } - void ComponentGui(Entity entity) override + void ComponentGui(Entity entity) const override { if (flagComponent) FlagComponentGui(entity); @@ -51,11 +51,27 @@ namespace Copium return serializedName; } - protected: - virtual void Gui(Component& component) {} - virtual Component Create(Entity entity) { return Component{}; } + bool IsFlagComponent() const override + { + return flagComponent; + } - void FlagComponentGui(Entity entity) + void AddDefaultComponent(Entity entity) const override + { + Component component = Create(entity); + entity.AddComponent(component); + } + + bool HasComponent(Entity entity) const override + { + return entity.HasComponent(); + } + + protected: + virtual void Gui(Component& component) const {} + virtual Component Create(Entity entity) const { return Component{}; } + + void FlagComponentGui(Entity entity) const { bool shouldHaveComponent = entity.HasComponent(); ImGui::Checkbox(name.c_str(), &shouldHaveComponent); @@ -68,25 +84,42 @@ namespace Copium entity.RemoveComponent(); } - void DataComponentGui(Entity entity) + void DataComponentGui(Entity entity) const { - if (entity.HasComponent()) + if (!entity.HasComponent()) + return; + + Component& component = entity.GetComponent(); + if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - Component& component = entity.GetComponent(); - if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - Gui(component); - if (ImGui::Button(std::string("Delete " + name).c_str())) - entity.RemoveComponent(); - } - } - else - { - // TODO: These buttons should probably be in a context menu when you right-click the entity instead - if (ImGui::Button(std::string("Add " + name).c_str())) - entity.AddComponent(Create(entity)); + Gui(component); + if (ImGui::Button(std::string("Delete " + name).c_str())) + entity.RemoveComponent(); + ImGui::NewLine(); } } + void EntityGui(const std::string& name, Entity* entity) const + { + ImGui::Text(name.c_str()); + ImGui::SameLine(); + std::string str; + if (*entity) + str = entity->GetComponent().name; + else + str = "(drag and drop an entity)"; + ImGui::BeginDisabled(); + ImGui::InputText("##EntityGui", &str); + ImGui::EndDisabled(); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_UUID")) + *entity = GetEntity(entity->GetManager(), *(Uuid*)payload->Data); + ImGui::EndDragDropTarget(); + } + ImGui::SameLine(); + if (ImGui::Button("x")) + entity->Invalidate(); + } }; } diff --git a/CopiumEngine/src/copium/example/ComponentHandlerBase.cpp b/CopiumEngine/src/copium/example/ComponentHandlerBase.cpp index 41bf252..7e5d418 100644 --- a/CopiumEngine/src/copium/example/ComponentHandlerBase.cpp +++ b/CopiumEngine/src/copium/example/ComponentHandlerBase.cpp @@ -4,7 +4,7 @@ namespace Copium { - glm::vec2 ComponentHandlerBase::ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::vec2 vec) + glm::vec2 ComponentHandlerBase::ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::vec2 vec) const { if (!metaClass.HasValue(key)) return vec; @@ -16,7 +16,7 @@ namespace Copium return vec; } - glm::ivec2 ComponentHandlerBase::ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::ivec2 vec) + glm::ivec2 ComponentHandlerBase::ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::ivec2 vec) const { if (!metaClass.HasValue(key)) return vec; @@ -29,7 +29,7 @@ namespace Copium } - bool ComponentHandlerBase::ReadBoolOpt(const MetaFileClass& metaClass, const std::string& key, bool vec) + bool ComponentHandlerBase::ReadBoolOpt(const MetaFileClass& metaClass, const std::string& key, bool vec) const { if (!metaClass.HasValue(key)) return vec; diff --git a/CopiumEngine/src/copium/example/ComponentHandlerBase.h b/CopiumEngine/src/copium/example/ComponentHandlerBase.h index 8f51777..93c5f6f 100644 --- a/CopiumEngine/src/copium/example/ComponentHandlerBase.h +++ b/CopiumEngine/src/copium/example/ComponentHandlerBase.h @@ -13,16 +13,19 @@ namespace Copium class ComponentHandlerBase { public: - virtual void Serialize(Entity entity, MetaFile& metaFile) = 0; - virtual void Deserialize(Entity entity, const MetaFileClass& metaClass) = 0; - virtual void ComponentGui(Entity entity) = 0; + virtual void Serialize(Entity entity, MetaFile& metaFile) const = 0; + virtual void Deserialize(Entity entity, const MetaFileClass& metaClass) const = 0; + virtual void ComponentGui(Entity entity) const = 0; virtual const std::string& GetName() const = 0; virtual const std::string& GetSerializedName() const = 0; + virtual bool IsFlagComponent() const = 0; + virtual void AddDefaultComponent(Entity entity) const = 0; + virtual bool HasComponent(Entity entity) const = 0; protected: - glm::vec2 ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::vec2 vec); - glm::ivec2 ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::ivec2 vec); - bool ReadBoolOpt(const MetaFileClass& metaClass, const std::string& key, bool vec); + glm::vec2 ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::vec2 vec) const; + glm::ivec2 ReadVec2Opt(const MetaFileClass& metaClass, const std::string& key, glm::ivec2 vec) const; + bool ReadBoolOpt(const MetaFileClass& metaClass, const std::string& key, bool vec) const; // TODO: I don't like this implementation at all. // It shouldn't be the ComponentHandlerBases responsibility to know about entities diff --git a/CopiumEngine/src/copium/example/ComponentHandlers.h b/CopiumEngine/src/copium/example/ComponentHandlers.h index f7e7f7d..e4b2193 100644 --- a/CopiumEngine/src/copium/example/ComponentHandlers.h +++ b/CopiumEngine/src/copium/example/ComponentHandlers.h @@ -12,7 +12,7 @@ namespace Copium public: NameComponentHandler() : ComponentHandler{"Name", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { NameC name; name.name = metaClass.GetValue("name"); @@ -20,12 +20,12 @@ namespace Copium } protected: - void Gui(NameC& name) override + void Gui(NameC& name) const override { ImGui::InputText("Name##Name", &name.name); } - NameC Create(Entity entity) override + NameC Create(Entity entity) const override { return NameC{String::Format("Entity %d", entity.GetId())}; } @@ -36,7 +36,7 @@ namespace Copium public: TransformComponentHandler() : ComponentHandler{"Transform", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { TransformC transform; transform.position = ReadVec2Opt(metaClass, "position", glm::vec2{0.0f, 0.0f}); @@ -45,13 +45,13 @@ namespace Copium } protected: - void Gui(TransformC& transform) override + void Gui(TransformC& transform) const override { ImGui::DragFloat2("Position", (float*)&transform.position); ImGui::DragFloat2("Size", (float*)&transform.size); } - TransformC Create(Entity entity) override + TransformC Create(Entity entity) const override { return TransformC{glm::vec2{0, 0}, glm::vec2{1, 1}}; } @@ -62,7 +62,7 @@ namespace Copium public: TextureComponentHandler() : ComponentHandler{"Texture", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { TextureC texture; texture.asset = AssetRef{AssetManager::LoadAsset(Uuid{metaClass.GetValue("texture-uuid")})}; @@ -72,7 +72,7 @@ namespace Copium } protected: - void Gui(TextureC& texture) override + void Gui(TextureC& texture) const override { Asset& asset = AssetManager::GetAsset(texture.asset); ImGui::Text("Asset: %s", asset.GetName().c_str()); @@ -80,7 +80,7 @@ namespace Copium ImGui::DragFloat2("Tex Coord 2", (float*)&texture.texCoord2, 0.01, 0.0f, 1.0f); } - TextureC Create(Entity entity) override + TextureC Create(Entity entity) const override { return TextureC{AssetRef{AssetManager::DuplicateAsset(Vulkan::GetEmptyTexture2D())}, glm::vec2{0, 0}, glm::vec2{1, 1}}; } @@ -91,7 +91,7 @@ namespace Copium public: TextComponentHandler() : ComponentHandler{"Text", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { char* endPtr; TextC text; @@ -102,7 +102,7 @@ namespace Copium } protected: - void Gui(TextC& text) override + void Gui(TextC& text) const override { Asset& asset = AssetManager::GetAsset(text.font); ImGui::Text(asset.GetName().c_str()); @@ -110,7 +110,7 @@ namespace Copium ImGui::DragFloat("Font Size", &text.fontSize); } - TextC Create(Entity entity) override + TextC Create(Entity entity) const override { return TextC{AssetRef{AssetManager::LoadAsset("font.meta")}, "", 20.0f}; } @@ -121,7 +121,7 @@ namespace Copium public: StaticColliderComponentHandler() : ComponentHandler{"Static Collider", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { StaticColliderC staticCollider; staticCollider.resolveCollision = ReadBoolOpt(metaClass, "resolve-collision", true); @@ -129,12 +129,12 @@ namespace Copium } protected: - void Gui(StaticColliderC& staticCollider) override + void Gui(StaticColliderC& staticCollider) const override { ImGui::Checkbox("Resolve Collision##StaticCollider", &staticCollider.resolveCollision); } - StaticColliderC Create(Entity entity) override + StaticColliderC Create(Entity entity) const override { return StaticColliderC{false}; } @@ -145,7 +145,7 @@ namespace Copium public: DynamicColliderComponentHandler() : ComponentHandler{"Dynamic Collider", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { DynamicColliderC dynamicCollider; dynamicCollider.resolveCollision = ReadBoolOpt(metaClass, "resolve-collision", true); @@ -155,14 +155,14 @@ namespace Copium } protected: - void Gui(DynamicColliderC& dynamicCollider) override + void Gui(DynamicColliderC& dynamicCollider) const override { ImGui::Checkbox("Resolve Collision##DynamicCollider", &dynamicCollider.resolveCollision); ImGui::DragFloat2("Collider Offset", (float*)&dynamicCollider.colliderOffset, 0.01); ImGui::DragFloat2("Collider Size", (float*)&dynamicCollider.colliderSize, 0.01); } - DynamicColliderC Create(Entity entity) override + DynamicColliderC Create(Entity entity) const override { return DynamicColliderC{true, glm::vec2{0, 0}, glm::vec2{1, 1}}; } @@ -173,7 +173,7 @@ namespace Copium public: PlayerComponentHandler() : ComponentHandler{"Player", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { PlayerC player; player.camera = GetEntity(entity.GetManager(), Uuid{metaClass.GetValue("camera-uuid")}); @@ -181,17 +181,14 @@ namespace Copium } protected: - void Gui(PlayerC& player) override + void Gui(PlayerC& player) const override { - if (player.camera) - ImGui::Text("Camera: %s", player.camera.GetComponent().name.c_str()); - else - ImGui::Text("No camera attached"); + EntityGui("Camera", &player.camera); } - PlayerC Create(Entity entity) override + PlayerC Create(Entity entity) const override { - return PlayerC{}; + return PlayerC{Entity{entity.GetManager()}}; } }; @@ -202,7 +199,7 @@ namespace Copium public: CameraComponentHandler(BoundingBox* viewport) : ComponentHandler{"Camera", false}, viewport{viewport} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { float aspect = viewport->GetSize().x / viewport->GetSize().y; @@ -217,13 +214,13 @@ namespace Copium } protected: - void Gui(CameraC& camera) override + void Gui(CameraC& camera) const override { ImGui::Checkbox("Static", &camera.staticBoundingBox); ImGui::Checkbox("Ui camera", &camera.uiCamera); // TODO: If this changes, the bounding box should be modified if it is not static } - CameraC Create(Entity entity) override + CameraC Create(Entity entity) const override { return CameraC{BoundingBox{-1.0f, -1.0f, 1.0f, 1.0f}, false, false}; } @@ -234,7 +231,7 @@ namespace Copium public: UuidComponentHandler() : ComponentHandler{"Uuid", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { UuidC uuid; uuid.uuid = Uuid{metaClass.GetValue("uuid")}; @@ -242,7 +239,7 @@ namespace Copium } protected: - void ComponentGui(Entity entity) override {} + void ComponentGui(Entity entity) const override {} }; class HealthComponentHandler : public ComponentHandler @@ -250,7 +247,7 @@ namespace Copium public: HealthComponentHandler() : ComponentHandler{"Health", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { char* endPtr; HealthC health; @@ -260,12 +257,12 @@ namespace Copium } protected: - void Gui(HealthC& health) override + void Gui(HealthC& health) const override { ImGui::DragInt("Max Health", &health.max); } - HealthC Create(Entity entity) override + HealthC Create(Entity entity) const override { return HealthC{10, 10}; } @@ -276,7 +273,7 @@ namespace Copium public: PhysicsComponentHandler() : ComponentHandler{"Physics", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { char* endPtr; PhysicsC physics; @@ -285,12 +282,12 @@ namespace Copium } protected: - void Gui(PhysicsC& physics) override + void Gui(PhysicsC& physics) const override { ImGui::DragFloat("Mass", &physics.mass); } - PhysicsC Create(Entity entity) override + PhysicsC Create(Entity entity) const override { return PhysicsC{10.0f}; } @@ -301,7 +298,7 @@ namespace Copium public: AnimationComponentHandler() : ComponentHandler{"Animation", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { char* endPtr; AnimationC animation; @@ -314,7 +311,7 @@ namespace Copium } protected: - void Gui(AnimationC& animation) override + void Gui(AnimationC& animation) const override { ImGui::DragInt2("Sheet Size", (int*)&animation.sheetSize); ImGui::DragInt2("Sheet Coord", (int*)&animation.sheetCoord, 1, 0, std::max(animation.sheetSize.x, animation.sheetSize.y)); @@ -323,7 +320,7 @@ namespace Copium ImGui::Checkbox("Horizontal", &animation.horizontal); } - AnimationC Create(Entity entity) override + AnimationC Create(Entity entity) const override { return AnimationC{glm::ivec2{0, 0}, glm::ivec2{1, 1}, 1, true, 1.0f}; } @@ -334,7 +331,7 @@ namespace Copium public: DebugComponentHandler() : ComponentHandler{"Debug", false} {} - void Deserialize(Entity entity, const MetaFileClass& metaClass) override + void Deserialize(Entity entity, const MetaFileClass& metaClass) const override { DebugC debug; debug.playerEntity = GetEntity(entity.GetManager(), Uuid{metaClass.GetValue("player-uuid")}); @@ -342,17 +339,14 @@ namespace Copium } protected: - void Gui(DebugC& debug) override + void Gui(DebugC& debug) const override { - if (debug.playerEntity) - ImGui::Text("Player: %s", debug.playerEntity.GetComponent().name.c_str()); - else - ImGui::Text("No player attached"); + EntityGui("Player", &debug.playerEntity); } - DebugC Create(Entity entity) override + DebugC Create(Entity entity) const override { - return DebugC{}; + return DebugC{Entity{entity.GetManager()}}; } }; }