#pragma once #include "SHYAMLConverters.h" #include #include "ECS_Base/Components/SHComponent.h" #include #include #include "ECS_Base/Managers/SHComponentManager.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Tools/Logger/SHLog.h" namespace SHADE { static constexpr std::string_view IsActive = "IsActive"; using AssetQueue = std::unordered_map; struct SHSerializationHelper { 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 = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { node = YAML::convert::encode(var.convert()); } else if (varType.is_arithmetic()) { bool ok = false; if (varType == rttr::type::get()) node = var.to_bool(); else if (varType == rttr::type::get()) node = var.to_int8(&ok); else if (varType == rttr::type::get()) node = var.to_int16(&ok); else if (varType == rttr::type::get()) node = var.to_int32(&ok); else if (varType == rttr::type::get()) node = var.to_int64(&ok); else if (varType == rttr::type::get()) node = var.to_uint8(&ok); else if (varType == rttr::type::get()) node = var.to_uint16(&ok); else if (varType == rttr::type::get()) node = var.to_uint32(&ok); else if (varType == rttr::type::get()) node = var.to_uint64(&ok); else if (varType == rttr::type::get()) node = var.to_float(&ok); else if (varType == rttr::type::get()) node = var.to_double(&ok); //else if (varType == rttr::type::get()) //same as uint8_t // node = var.to_uint8(); } else if (varType.is_enumeration()) { bool ok = false; auto result = var.to_string(&ok); if (ok) { node = var.to_string(); } else { ok = false; auto value = var.to_uint64(&ok); if (ok) node = value; else node = YAML::Null; } } else if (varType == rttr::type::get()) node = var.to_string(); else { auto properties = var.get_type().get_properties(); for (auto const& property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } } return node; } template , bool> = true> static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) { } template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { if constexpr (YAML::HasYAMLConv()) { if (component) { auto componentNode = YAML::convert::encode(*component); componentNode[IsActive.data()] = component->isActive; return componentNode; } } else { if (component) { YAML::Node compNode{}; if (!component) return compNode; auto componentType = rttr::type::get(); compNode = RTTRToNode(*component); compNode[IsActive.data()] = component->isActive; return compNode; } } } template static void InitializeProperty(Type* object, rttr::property const& prop, YAML::Node const& propertyNode) { auto propType = prop.get_type(); if (propType == rttr::type::get()) { SHVec4 vec = propertyNode.as(); prop.set_value(object, vec); } else if (propType == rttr::type::get()) { SHVec3 vec = propertyNode.as(); prop.set_value(object, vec); } else if (propType == rttr::type::get()) { SHVec2 vec = propertyNode.as(); prop.set_value(object, vec); } else if (propType.is_arithmetic()) { bool ok = false; if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); } else if (propType.is_enumeration()) { auto enumAlign = prop.get_enumeration(); prop.set_value(object, enumAlign.name_to_value(propertyNode.as())); } else if (propType == rttr::type::get()) prop.set_value(object, propertyNode.as()); else { auto properties = propType.get_properties(); for (auto const& property : properties) { if(propertyNode[property.get_name().data()].IsDefined()) InitializeProperty(object, property, propertyNode[property.get_name().data()]); } } } template , bool> = true> static bool InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) { if constexpr (YAML::HasYAMLConv()) { auto component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() || !component) return false; auto componentNode = GetComponentNode(componentsNode, eid); if (componentNode.IsNull() || !componentNode.IsDefined()) return false; if (componentNode[IsActive.data()].IsDefined()) component->isActive = componentNode[IsActive.data()].as(); YAML::convert::decode(componentNode, *component); return true; } else { ComponentType* component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() && !component) return false; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; if (!componentNode.IsDefined()) return false; if (componentNode[IsActive.data()].IsDefined()) component->isActive = componentNode[IsActive.data()].as(); auto properties = rttrType.get_properties(); for (auto const& prop : properties) { if (componentNode[prop.get_name().data()].IsDefined()) { InitializeProperty(component, prop, componentNode[prop.get_name().data()]); } } } return true; } template , bool> = true> static YAML::Node GetComponentNode(YAML::Node const& componentsNode, EntityID const& eid) { auto component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() && !component) return {}; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; if (!componentNode.IsDefined()) return {}; return componentNode; } //template, bool> = true> //static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) //{ // if constexpr (YAML::HasYAMLConv()) // { // if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) // { // auto componentNode = YAML::convert::encode(*component); // componentNode[IsActive.data()] = component->isActive; // componentsNode[rttr::type::get().get_name().data()] = componentNode; // } // } // else // { // if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) // { // componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); // } // } //} template , bool> = true> static std::string SerializeComponentToString(EntityID const& eid) { if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) { YAML::Emitter out; YAML::Node node{}; node[rttr::type::get().get_name().data()] = SerializeComponentToNode(component); out << node; return out.c_str(); } return std::string(); } template , bool> = true> static bool DeserializeComponentFromString(std::string data, EntityID const& eid) { YAML::Node node = YAML::Load(data); return InitializeComponentFromNode(node, eid); } template , bool> = true> static void FetchAssetsFromComponent(YAML::Node const& componentsNode, EntityID const& eid, AssetQueue& assetQueue) { } template<> static void FetchAssetsFromComponent(YAML::Node const& componentsNode, EntityID const& eid, AssetQueue& assetQueue) { auto node = GetComponentNode(componentsNode, eid); if(!node.IsDefined()) return; if (auto const& meshNode = node[YAML::convert::MESH_YAML_TAG.data()]; meshNode.IsDefined()) { assetQueue.insert({meshNode.as(), AssetType::MESH}); //SHResourceManager::LoadOrGet(node[YAML::convert::MESH_YAML_TAG.data()].as()); } if (auto const& matNode = node[YAML::convert::MAT_YAML_TAG.data()]; matNode.IsDefined()) { auto const matAsset = SHAssetManager::GetData(matNode.as()); if(matAsset) { SHMaterialSpec spec; YAML::convert::decode(*YAML::Load(matAsset->data).begin(), spec); if(spec.properties.IsDefined()) { auto fragShader = SHResourceManager::LoadOrGet(spec.fragShader); auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface(SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA); int const varCount = static_cast(interface->GetVariableCount()); for (int i = 0; i < varCount; ++i) { auto variable = interface->GetVariable(i); if(variable->type != SHShaderBlockInterface::Variable::Type::INT) continue; const std::string& VAR_NAME = interface->GetVariableName(i); if(VAR_NAME.empty()) continue; assetQueue.insert({spec.properties[VAR_NAME.data()].as(), AssetType::TEXTURE}); } } } //assetQueue.insert({matNode.as(), AssetType::MATERIAL}); //SHResourceManager::LoadOrGet(node[YAML::convert::MAT_YAML_TAG.data()].as()); } } }; }