#pragma once #include #include "ECS_Base/Components/SHComponent.h" #include #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" #include "Resource/SHResourceManager.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "SHSerializationTools.h" namespace YAML { using namespace SHADE; template<> struct convert { static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader"; static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader"; static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass"; static constexpr std::string_view PROPS_YAML_TAG = "Properties"; static YAML::Node encode(SHMaterial const& rhs) { // Write Properties YAML::Node propertiesNode; Handle pipelineProperties = rhs.GetShaderBlockInterface(); for (int i = 0; i < static_cast(pipelineProperties->GetVariableCount()); ++i) { const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i); if (!VARIABLE) break; const std::string& VAR_NAME = pipelineProperties->GetVariableName(i); YAML::Node propNode; switch (VARIABLE->type) { case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT: propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::INT: propNode = rhs.GetProperty(VARIABLE->offset); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: propNode = SHSerializationTools::ValToYAML(rhs.GetProperty(VARIABLE->offset)); break; case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: default: continue; break; } propertiesNode[VAR_NAME.data()] = propNode; } // Get Shader Handles const auto& SHADERS = rhs.GetPipeline()->GetPipelineLayout()->GetShaderModules(); Handle vertexShader, fragShader; for (const auto& shader : SHADERS) { const auto FLAG_BITS = shader->GetShaderStageFlagBits(); if (FLAG_BITS & vk::ShaderStageFlagBits::eVertex) vertexShader = shader; else if (FLAG_BITS & vk::ShaderStageFlagBits::eFragment) fragShader = shader; } // Write Material YAML::Node node; node[VERT_SHADER_YAML_TAG.data()] = 0; // SHResourceManager::GetAssetID(vertexShader).value_or(0); node[FRAG_SHADER_YAML_TAG.data()] = 0; // SHResourceManager::GetAssetID(fragShader).value_or(0); node[SUBPASS_YAML_TAG.data()] = rhs.GetPipeline()->GetPipelineState().GetSubpass()->GetName(); node[PROPS_YAML_TAG.data()] = propertiesNode; return node; } static bool decode(YAML::Node const& node, SHMaterial& rhs) { /* // Retrieve Shader Asset IDs AssetID vertShaderId = 0; AssetID fragShaderId = 0; if (node[VERT_SHADER_YAML_TAG.data()]) vertShaderId = node[VERT_SHADER_YAML_TAG.data()].as(); if (node[FRAG_SHADER_YAML_TAG.data()]) fragShaderId = node[FRAG_SHADER_YAML_TAG.data()].as(); // Ensure that both shaders are present if (vertShaderId == 0 || fragShaderId == 0) return false; // No pipeline // Get Shader Modules Handle vertexShader, fragShader; vertexShader = SHResourceManager::LoadOrGet(vertShaderId); fragShader = SHResourceManager::LoadOrGet(fragShaderId); // Get Pipeline Library if (node[SUBPASS_YAML_TAG.data()]) { auto gfxSystem = SHSystemManager::GetSystem(); if (!gfxSystem) return false; // Grab subpass from worldRenderer auto renderPass = gfxSystem->GetPrimaryRenderpass(); if (!renderPass) return false; auto subPass = renderPass->GetSubpass(node[SUBPASS_YAML_TAG.data()].as()); if (!subPass) return false; // Set Pipeline rhs.SetPipeline(renderPass->GetOrCreatePipeline ( std::make_pair(vertexShader, fragShader), subPass )); } */ // TODO: Load Proper Material! // Set default material auto gfxSystem = SHSystemManager::GetSystem(); if (!gfxSystem) return false; rhs.SetPipeline(gfxSystem->GetDefaultMaterial()->GetPipeline()); if (node[PROPS_YAML_TAG.data()]) { // Loop through all properties Handle pipelineProperties = rhs.GetShaderBlockInterface(); const YAML::Node& PROPS_NODE = node[PROPS_YAML_TAG.data()]; for (int i = 0; i < static_cast(pipelineProperties->GetVariableCount()); ++i) { const std::string& PROP_NAME = pipelineProperties->GetVariableName(i); const auto& PROP_NODE = PROPS_NODE[PROP_NAME.data()]; if (PROP_NODE) { const std::string& VAR_NAME = pipelineProperties->GetVariableName(i); const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i); switch (VARIABLE->type) { case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT: rhs.SetProperty(VARIABLE->offset, PROP_NODE.as()); break; case SHADE::SHShaderBlockInterface::Variable::Type::INT: rhs.SetProperty(VARIABLE->offset, PROP_NODE.as()); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec2(PROP_NODE)); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec3(PROP_NODE)); break; case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: rhs.SetProperty(VARIABLE->offset, SHSerializationTools::YAMLToVec4(PROP_NODE)); break; case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: default: continue; break; } } } } return true; } }; template<> struct convert { static constexpr std::string_view MESH_YAML_TAG = "Mesh"; static constexpr std::string_view MAT_YAML_TAG = "Material"; static YAML::Node encode(SHRenderable const& rhs) { YAML::Node node; node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); node[MAT_YAML_TAG.data()] = 0; // TODO: Asset ID return node; } static bool decode(YAML::Node const& node, SHRenderable& rhs) { if (node[MESH_YAML_TAG.data()]) { rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); } if (node[MAT_YAML_TAG.data()]) { // TODO: Convert Asset ID To Material HAndle // Temporarily, use default material auto gfxSystem = SHSystemManager::GetSystem(); if (!gfxSystem) return false; rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(gfxSystem->GetDefaultMaterial())); } return true; } }; } 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 == 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; } 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; } else if (varType == rttr::type::get()) { node.SetStyle(YAML::EmitterStyle::Flow); node["X"] = var.convert().x; node["Y"] = var.convert().y; } 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 { auto properties = var.get_type().get_properties(); for (auto property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } } return node; } template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { YAML::Node node{}; if (!component) return node; auto componentType = rttr::type::get(); node = RTTRToNode(*component); return node; } template , bool> = true> static void InitializeProperty(ComponentType* component, rttr::property const& prop, YAML::Node const& propertyNode) { auto propType = prop.get_type(); if (propType == rttr::type::get()) { prop.set_value(component, SHSerializationTools::YAMLToVec4(propertyNode)); } else if (propType == rttr::type::get()) { prop.set_value(component, SHSerializationTools::YAMLToVec3(propertyNode)); } else if (propType == rttr::type::get()) { prop.set_value(component, SHSerializationTools::YAMLToVec2(propertyNode)); } else if (propType.is_arithmetic()) { bool ok = false; if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); else if (propType == rttr::type::get()) prop.set_value(component, propertyNode.as()); } else if (propType.is_enumeration()) { auto enumAlign = prop.get_enumeration(); prop.set_value(component, enumAlign.name_to_value(propertyNode.as())); } else { auto properties = propType.get_properties(); for (auto property : properties) { InitializeProperty(component, property, propertyNode[property.get_name().data()]); } } } template , bool> = true> static void InitializeComponentFromNode(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 (componentsNode.IsNull()) return; auto properties = rttrType.get_properties(); for (auto const& prop : properties) { if (componentNode[prop.get_name().data()]) { InitializeProperty(component, prop, componentNode[prop.get_name().data()]); } } } template , bool> = true> static void ConvertNodeToComponent(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 (componentsNode.IsNull()) return; YAML::convert::decode(componentNode, *component); } }; }