diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp index f2f8d927..7c774067 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.cpp @@ -48,15 +48,28 @@ namespace SHADE if (Begin()) { + if(skipFrame) + { + ImGui::End(); + skipFrame = false; + return; + } DrawMenuBar(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); - if(const auto root = sceneGraph.GetRoot()) + + if (const auto root = sceneGraph.GetRoot()) { auto const& children = root->GetChildren(); - + for (const auto child : children) { - RecursivelyDrawEntityNode(child); + if(child) + RecursivelyDrawEntityNode(child); + if(skipFrame) + { + ImGui::End(); + return; + } } } else @@ -119,8 +132,10 @@ namespace SHADE } } - ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* currentNode) + ImRect SHHierarchyPanel::RecursivelyDrawEntityNode(SHSceneNode* const currentNode) { + if(currentNode == nullptr) + return {}; auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); //Get node data (Children, eid, selected) @@ -192,10 +207,16 @@ namespace SHADE if(ImGui::Selectable("Paste")) { SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard())); + skipFrame = true; + ImGui::EndPopup(); + if(isNodeOpen) + ImGui::TreePop(); + return nodeRect; } if(ImGui::Selectable("Paste as Child")) { SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid)); + skipFrame = true; } if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) { diff --git a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h index 0cfe6474..8fae5d6d 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h +++ b/SHADE_Engine/src/Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h @@ -26,10 +26,12 @@ namespace SHADE void SetScrollTo(EntityID eid); private: void DrawMenuBar() const noexcept; - ImRect RecursivelyDrawEntityNode(SHSceneNode*); + ImRect RecursivelyDrawEntityNode(SHSceneNode* const); void CreateChildEntity(EntityID parentEID) const noexcept; void ParentSelectedEntities(EntityID parentEID) const noexcept; void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID); + + bool skipFrame = false; std::string filter; bool isAnyNodeSelected = false; EntityID scrollTo = MAX_EID; diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp index fb999847..c7e327fa 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp @@ -146,4 +146,12 @@ namespace SHADE system->RemoveCollisionShape(GetEID(), index); } -} // namespace SHADE \ No newline at end of file +} // namespace SHADE + +RTTR_REGISTRATION +{ + using namespace rttr; + using namespace SHADE; + + registration::class_("Collider Component"); +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h index af726b51..7ce272a9 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h @@ -100,5 +100,6 @@ namespace SHADE SHQuaternion orientation; Colliders colliders; + RTTR_ENABLE() }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index f8913d8d..03498951 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -10,6 +10,7 @@ #include "Assets/SHAssetManager.h" #include +#include "Camera/SHCameraComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Components/SHRigidBodyComponent.h" @@ -58,7 +59,7 @@ namespace SHADE static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector& createdEntities, EntityID parentEID = MAX_EID) { EntityID eid = MAX_EID; - if(!node) + if (!node) return eid; if (node[EIDNode]) eid = node[EIDNode].as(); @@ -71,13 +72,13 @@ namespace SHADE createdEntities.push_back(eid); if (node[NumberOfChildrenNode]) { - if(const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) + if (const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) { ++it; for (int i = 0; i < numOfChildren; ++i) { DeserializeEntity(it, (*it), createdEntities, eid); - if((i + 1) < numOfChildren) + if ((i + 1) < numOfChildren) ++it; } } @@ -85,7 +86,9 @@ namespace SHADE // Deserialise scripts if (node[ScriptsNode]) - SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); + SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); + + return eid; } void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) @@ -120,10 +123,10 @@ namespace SHADE { DeserializeEntity(it, (*it), createdEntities); } - if(createdEntities.empty()) + if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") - return; + return; } //Initialize Entity auto entityVecIt = createdEntities.begin(); @@ -137,7 +140,7 @@ namespace SHADE { out << SerializeEntityToNode(entityNode); auto const& children = entityNode->GetChildren(); - for(auto const& child : children) + for (auto const& child : children) { EmitEntity(child, out); } @@ -162,17 +165,36 @@ namespace SHADE { } + template, bool> = true> + static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + { + if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); + } + } + + template, bool> = true> + static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + { + if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + componentsNode[rttr::type::get().get_name().data()] = YAML::convert::encode(*component); + } + } + + YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) { YAML::Node node; auto eid = sceneNode->GetEntityID(); auto entity = SHEntityManager::GetEntityByID(eid); - if (!sceneNode || !entity) + if (!sceneNode && !entity) { node = YAML::Null; return node; } - node.SetStyle(YAML::EmitterStyle::Block); + node.SetStyle(YAML::EmitterStyle::Block); node[EIDNode] = eid; node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); @@ -181,22 +203,13 @@ namespace SHADE YAML::Node components; - if (const auto transform = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(transform); - } - if (const auto renderable = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = *renderable; - } - if (const auto rigidbody = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody); - } - if(const auto light = SHComponentManager::GetComponent_s(eid)) - { - components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(light); - } + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddConvComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddConvComponentToComponentNode(components, eid); + node[ComponentsNode] = components; YAML::Node scripts; @@ -208,22 +221,22 @@ namespace SHADE EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept { - if(data.empty()) + if (data.empty()) return MAX_EID; YAML::Node entities = YAML::Load(data.c_str()); - EntityID eid{MAX_EID}; + EntityID eid{ MAX_EID }; std::vector createdEntities; - for(auto it = entities.begin(); it != entities.end(); ++it) + for (auto it = entities.begin(); it != entities.end(); ++it) { eid = DeserializeEntity(it, *it, createdEntities, parentEID); } - if(createdEntities.empty()) + if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") - return MAX_EID; + return MAX_EID; } auto entityVecIt = createdEntities.begin(); - for(auto it = entities.begin(); it != entities.end(); ++it) + for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } @@ -231,33 +244,22 @@ namespace SHADE } template, bool> = true> - std::optional GetComponentID(YAML::Node const& componentNode) + static void AddComponentID(std::vector& idList, YAML::Node const& componentNode) { if (componentNode[rttr::type::get().get_name().data()]) - return { SHFamilyID::GetID() }; - else - return std::nullopt; + idList.push_back(SHFamilyID::GetID()); } std::vector SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) { std::vector componentIDList; - - auto id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); - - id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); - - id = GetComponentID(componentsNode); - if (id.has_value()) - componentIDList.push_back(id.value()); - - id = GetComponentID(componentsNode); - if(id.has_value()) - componentIDList.push_back(id.value()); + + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); return componentIDList; } @@ -268,7 +270,10 @@ namespace SHADE if (!componentsNode) return; SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } } diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index 047232a0..bcd378c5 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -13,10 +13,235 @@ #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "SHSerializationTools.h" +#include "Physics/Components/SHColliderComponent.h" namespace YAML { using namespace SHADE; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + static constexpr const char* w = "w"; + + static Node encode(SHVec4 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + node[w] = rhs.w; + return node; + } + static bool decode(Node const& node, SHVec4& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + if (node[w].IsDefined()) + rhs.w = node[w].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + + static Node encode(SHVec3 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + return node; + } + static bool decode(Node const& node, SHVec3& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + + static Node encode(SHVec2 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + return node; + } + static bool decode(Node const& node, SHVec2& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* IsTrigger = "Is Trigger"; + + static constexpr const char* Type = "Type"; + static constexpr const char* HalfExtents = "Half Extents"; + static constexpr const char* Radius = "Radius"; + + static constexpr const char* Friction = "Friction"; + static constexpr const char* Bounciness = "Bounciness"; + static constexpr const char* Density = "Density"; + static constexpr const char* PositionOffset = "Position Offset"; + + static Node encode(SHCollider& rhs) + { + Node node; + + node[IsTrigger] = rhs.IsTrigger(); + + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + SHCollider::Type colliderType = rhs.GetType(); + + node[Type] = enumAlign.value_to_name(colliderType).data(); + + switch (colliderType) + { + case SHCollider::Type::BOX: + { + auto const bb = reinterpret_cast(rhs.GetShape()); + node[HalfExtents] = bb->GetHalfExtents(); + } + break; + case SHCollider::Type::SPHERE: + { + auto const bs = reinterpret_cast(rhs.GetShape()); + node[Radius] = bs->GetRadius(); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + + node[Friction] = rhs.GetFriction(); + node[Bounciness] = rhs.GetBounciness(); + node[Density] = rhs.GetDensity(); + node[PositionOffset] = rhs.GetPositionOffset(); + + return node; + } + static bool decode(Node const& node, SHCollider& rhs) + { + if (node[IsTrigger].IsDefined()) + rhs.SetIsTrigger(node[IsTrigger].as()); + if (!node[Type].IsDefined()) + return false; + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok; + const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as()).convert(&ok); + if (!ok) + return false; + switch (colliderType) + { + case SHCollider::Type::BOX: + { + if(node[HalfExtents].IsDefined()) + rhs.SetBoundingBox(node[HalfExtents].as()); + } + break; + case SHCollider::Type::SPHERE: + { + if(node[Radius].IsDefined()) + rhs.SetBoundingSphere(node[Radius].as()); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + if (node[Friction].IsDefined()) + rhs.SetFriction(node[Friction].as()); + if (node[Bounciness].IsDefined()) + rhs.SetBounciness(rhs.GetBounciness()); + if (node[Density].IsDefined()) + rhs.SetDensity(node[Density].as()); + if (node[PositionOffset].IsDefined()) + rhs.SetPositionOffset(node[PositionOffset].as()); + + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* Colliders = "Colliders"; + static Node encode(SHColliderComponent& rhs) + { + Node node, collidersNode; + auto const& colliders = rhs.GetColliders(); + int const numColliders = static_cast(colliders.size()); + for (int i = 0; i < numColliders; ++i) + { + auto& collider = rhs.GetCollider(i); + Node colliderNode = convert::encode(collider); + if (colliderNode.IsDefined()) + collidersNode[i] = colliderNode; + } + node[Colliders] = collidersNode; + return node; + } + static bool decode(Node const& node, SHColliderComponent& rhs) + { + if (node[Colliders].IsDefined()) + { + int numColliders{}; + for (auto const& colliderNode : node[Colliders]) + { + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok = false; + const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert::Type].as()).convert(&ok); + if (!ok) + return false; + + switch (colliderType) + { + case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; + case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; + case SHCollider::Type::CAPSULE: break; + default:; + } + YAML::convert::decode(colliderNode, rhs.GetCollider(numColliders++)); + } + } + } + }; + template<> struct convert { @@ -46,13 +271,13 @@ namespace YAML propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: - propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); + propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: default: @@ -135,7 +360,7 @@ namespace YAML return false; rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline()); - if (node[PROPS_YAML_TAG.data()]) + if (node[PROPS_YAML_TAG.data()].IsDefined()) { // Loop through all properties Handle pipelineProperties = rhs.GetShaderBlockInterface(); @@ -192,11 +417,11 @@ namespace YAML } static bool decode(YAML::Node const& node, SHRenderable& rhs) { - if (node[MESH_YAML_TAG.data()]) + if (node[MESH_YAML_TAG.data()].IsDefined()) { rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); } - if (node[MAT_YAML_TAG.data()]) + if (node[MAT_YAML_TAG.data()].IsDefined()) { // TODO: Convert Asset ID To Material HAndle // Temporarily, use default material @@ -210,46 +435,34 @@ namespace YAML }; } - namespace SHADE { struct SHSerializationHelper { - template , bool> = true> - static std::string SerializeComponentToString(ComponentType* component) - { - return std::string(); - } - template , bool> = true> - static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) - { - } static YAML::Node RTTRToNode(const rttr::variant& var) { YAML::Node node; auto varType = var.get_type(); + if (varType.is_sequential_container()) + { + for (auto const& elem : var.create_sequential_view()) + { + node.push_back(RTTRToNode(elem)); + } + } if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; - node["Z"] = var.convert().z; - node["W"] = var.convert().w; + node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; - node["Z"] = var.convert().z; + node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { - node.SetStyle(YAML::EmitterStyle::Flow); - node["X"] = var.convert().x; - node["Y"] = var.convert().y; + node = YAML::convert::encode(var.convert()); } else if (varType.is_arithmetic()) { @@ -300,7 +513,7 @@ namespace SHADE else { auto properties = var.get_type().get_properties(); - for (auto property : properties) + for (auto const& property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } @@ -308,6 +521,17 @@ namespace SHADE return node; } + template , bool> = true> + static std::string SerializeComponentToString(ComponentType* component) + { + return std::string(); + } + + template , bool> = true> + static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) + { + } + template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { @@ -327,15 +551,18 @@ namespace SHADE auto propType = prop.get_type(); if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode)); + SHVec4 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode)); + SHVec3 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType == rttr::type::get()) { - prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode)); + SHVec2 vec = propertyNode.as(); + prop.set_value(component, vec); } else if (propType.is_arithmetic()) { @@ -371,9 +598,10 @@ namespace SHADE else { auto properties = propType.get_properties(); - for (auto property : properties) + for (auto const& property : properties) { - InitializeProperty(component, property, propertyNode[property.get_name().data()]); + if(propertyNode[property.get_name().data()].IsDefined()) + InitializeProperty(component, property, propertyNode[property.get_name().data()]); } } } @@ -381,7 +609,7 @@ namespace SHADE template , bool> = true> static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) { - auto component = SHComponentManager::GetComponent_s(eid); + ComponentType* component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() && !component) return; auto rttrType = rttr::type::get(); @@ -406,7 +634,7 @@ namespace SHADE return; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; - if (componentsNode.IsNull()) + if (!componentNode.IsDefined()) return; YAML::convert::decode(componentNode, *component); }