diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.cpp new file mode 100644 index 00000000..0652b2bf --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.cpp @@ -0,0 +1,74 @@ +/************************************************************************************//*! +\file SHMaterialSpec.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 2, 2022 +\brief Contains the function definitions of SHMaterialSpec. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#include "SHpch.h" +#include "SHMaterialSpec.h" +#include "Graphics/Shaders/SHVkShaderModule.h" +#include "Resource/SHResourceManager.h" +#include "Graphics/MiddleEnd/Interface/SHMaterial.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------------*/ + SHMaterialSpec::SHMaterialSpec(const SHMaterial& material) + { + // Get Shader Handles + const auto& SHADERS = material.GetPipeline()->GetPipelineLayout()->GetShaderModules(); + Handle vShaderMod, fShaderMod; + for (const auto& shader : SHADERS) + { + const auto FLAG_BITS = shader->GetShaderStageFlagBits(); + if (FLAG_BITS & vk::ShaderStageFlagBits::eVertex) + vShaderMod = shader; + else if (FLAG_BITS & vk::ShaderStageFlagBits::eFragment) + fShaderMod = shader; + } + vertexShader = SHResourceManager::GetAssetID(vShaderMod).value_or(0); + fragShader = SHResourceManager::GetAssetID(vShaderMod).value_or(0); + subpassName = material.GetPipeline()->GetPipelineState().GetSubpass()->GetName(); + + // Write Properties + Handle pipelineProperties = material.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 = material.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::INT: + propNode = material.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2: + propNode = material.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: + propNode = material.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: + propNode = material.GetProperty(VARIABLE->offset); + break; + case SHADE::SHShaderBlockInterface::Variable::Type::OTHER: + default: + continue; + break; + } + properties[VAR_NAME.data()] = propNode; + } + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.h b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.h index e41436ce..03928cfa 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Materials/SHMaterialSpec.h @@ -20,6 +20,14 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Forward Declaration */ + /*-----------------------------------------------------------------------------------*/ + class SHMaterial; + + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ /*************************************************************************************/ /*! \brief @@ -33,5 +41,11 @@ namespace SHADE AssetID fragShader; std::string subpassName; YAML::Node properties; + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + SHMaterialSpec() = default; + SHMaterialSpec(const SHMaterial& material); }; } diff --git a/SHADE_Engine/src/Resource/SHResourceManager.h b/SHADE_Engine/src/Resource/SHResourceManager.h index 61689420..bf26c16c 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.h +++ b/SHADE_Engine/src/Resource/SHResourceManager.h @@ -13,6 +13,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include + +namespace SHADE { class SHMaterial; } // Project Includes #include "SH_API.h" #include "SHResourceLibrary.h" @@ -24,6 +26,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h" #include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h" +#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Assets/Asset Types/SHMaterialAsset.h" namespace SHADE @@ -50,9 +53,11 @@ namespace SHADE using AssetType = SHShaderAsset; }; template<> + struct SHResourceLoader { using AssetType = SHMaterialAsset; }; + template<> struct SHResourceLoader { - using AssetType = SHMaterialAsset; + using AssetType = SHMaterialSpec; }; @@ -79,6 +84,8 @@ namespace SHADE /// Handle to a loaded runtime asset. template static Handle LoadOrGet(AssetID assetId); + template<> + static inline Handle LoadOrGet(AssetID assetId); /// /// Unloads an existing loaded asset. Attempting to unload an invalid Handle will /// simply do nothing except emit a warning. diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index 15834cdf..aa0a0af9 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" +#include "Serialization/SHSerializationHelper.hpp" namespace SHADE { @@ -34,7 +35,12 @@ namespace SHADE Handle SHResourceManager::LoadOrGet(AssetID assetId) { // Check if it is an unsupported type - if (!std::is_same_v && !std::is_same_v) + if (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v + ) { static_assert(true, "Unsupported Resource Type specified for SHResourceManager."); } @@ -54,14 +60,41 @@ namespace SHADE } auto handle = load(assetId, *assetData); - Handle genericHandle = Handle(); + Handle genericHandle = Handle(handle); + typedHandleMap.get().emplace(assetId, genericHandle); + typedAssetIdMap.get().emplace(genericHandle, assetId); + return handle; + } + + template<> + Handle SHResourceManager::LoadOrGet(AssetID assetId) + { + /* Attempt to get existing loaded asset */ + auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); + if (typedHandleMap.get().contains(assetId)) + return Handle(typedHandleMap.get()[assetId]); + + /* Otherwise, we need to load it! */ + // Get system + SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem(); + if (gfxSystem == nullptr) + throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed."); + + // Get SHMaterialSpec + Handle matSpec = LoadOrGet(assetId); + if (!matSpec) + return {}; + + // Create the material + auto handle = load(assetId, *matSpec); + Handle genericHandle = Handle(handle); typedHandleMap.get().emplace(assetId, genericHandle); typedAssetIdMap.get().emplace(genericHandle, assetId); return handle; } template - void SHResourceManager::Unload(Handle assetId) + void SHResourceManager::Unload(Handle asset) { // Check if it is an unsupported type if (!std::is_same_v && !std::is_same_v) @@ -71,14 +104,18 @@ namespace SHADE /* Attempt to get existing loaded asset */ auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap(); - if (typedHandleMap.get().contains(assetId)) + if (typedHandleMap.get().contains(asset)) { + // Remove from ResourceHub if SHMaterialSpec + if (std::is_same_v) + resourceHub.Free(asset); + // Dispose - Handle handle = typedHandleMap.get()[assetId]; - Handle typedHandle = static_cast>(handle); + Handle handle = typedHandleMap.get()[asset]; + auto typedHandle = static_cast>(handle); typedHandle.Free(); typedAssetIdMap.get().erase(handle); - typedHandleMap.get().erase(assetId); + typedHandleMap.get().erase(asset); } else { @@ -179,15 +216,20 @@ namespace SHADE shader->Reflect(); return shader; } + // Material Spec + else if constexpr (std::is_same_v) + { + // Get the data we need to construct + auto matSpec = resourceHub.Create(); + *matSpec = YAML::Node(assetData.data).as(); + return matSpec; + } // Materials else if constexpr (std::is_same_v) { - // Get the data we need to construct - SHMaterialSpec matSpec = YAML::Node(assetData.data).as(); - // Load shaders - auto vertexShader = SHResourceManager::LoadOrGet(matSpec.vertexShader); - auto fragShader = SHResourceManager::LoadOrGet(matSpec.fragShader); + auto vertexShader = SHResourceManager::LoadOrGet(assetData.vertexShader); + auto fragShader = SHResourceManager::LoadOrGet(assetData.fragShader); // Ensure that both shaders are present if (!(vertexShader && fragShader)) @@ -203,7 +245,7 @@ namespace SHADE SHLOG_ERROR("[SHResourceManager] Failed to load material as RenderPass could not be found."); return {}; } - auto subPass = renderPass->GetSubpass(matSpec.subpassName); + auto subPass = renderPass->GetSubpass(assetData.subpassName); if (!subPass) { SHLOG_ERROR("[SHResourceManager] Failed to load material as SubPass could not be found."); @@ -218,7 +260,7 @@ namespace SHADE for (int i = 0; i < static_cast(pipelineProperties->GetVariableCount()); ++i) { const std::string& PROP_NAME = pipelineProperties->GetVariableName(i); - const auto& PROP_NODE = matSpec.properties; + const auto& PROP_NODE = assetData.properties; if (PROP_NODE) { const std::string& VAR_NAME = pipelineProperties->GetVariableName(i); diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index 2179d1cf..f2c4572a 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -20,9 +20,9 @@ namespace YAML { - using namespace SHADE; + using namespace SHADE; - template<> + template<> struct convert { static constexpr const char* x = "x"; @@ -172,17 +172,17 @@ namespace YAML switch (colliderType) { case SHCollider::Type::BOX: - { - if(node[HalfExtents].IsDefined()) - rhs.SetBoundingBox(node[HalfExtents].as()); - } - break; + { + if (node[HalfExtents].IsDefined()) + rhs.SetBoundingBox(node[HalfExtents].as()); + } + break; case SHCollider::Type::SPHERE: - { - if(node[Radius].IsDefined()) - rhs.SetBoundingSphere(node[Radius].as()); - } - break; + { + if (node[Radius].IsDefined()) + rhs.SetBoundingSphere(node[Radius].as()); + } + break; case SHCollider::Type::CAPSULE: break; default:; } @@ -194,7 +194,7 @@ namespace YAML rhs.SetDensity(node[Density].as()); if (node[PositionOffset].IsDefined()) rhs.SetPositionOffset(node[PositionOffset].as()); - + return true; } }; @@ -231,7 +231,7 @@ namespace YAML 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; @@ -246,143 +246,84 @@ namespace YAML } }; - template<> - struct convert + 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(SHMaterialSpec const& rhs) { - 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"; + YAML::Node node; + node[VERT_SHADER_YAML_TAG.data()] = rhs.vertexShader; + node[FRAG_SHADER_YAML_TAG.data()] = rhs.fragShader; + node[SUBPASS_YAML_TAG.data()] = rhs.subpassName; + node[PROPS_YAML_TAG.data()] = rhs.properties; + return node; + } - 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 = rhs.GetProperty(VARIABLE->offset); - break; - case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3: - propNode = rhs.GetProperty(VARIABLE->offset); - break; - case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4: - propNode = 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()] = SHResourceManager::GetAssetID(vertexShader).value_or(0); - node[FRAG_SHADER_YAML_TAG.data()] = SHResourceManager::GetAssetID(fragShader).value_or(0); - node[SUBPASS_YAML_TAG.data()] = rhs.GetPipeline()->GetPipelineState().GetSubpass()->GetName(); - node[PROPS_YAML_TAG.data()] = propertiesNode; - - return node; - } - }; - - template<> - struct convert + static bool decode(YAML::Node const& node, SHMaterialSpec& rhs) { - 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"; + // Retrieve Shader Asset IDs + if (!node[VERT_SHADER_YAML_TAG.data()]) + return false; + rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as(); + if (!node[FRAG_SHADER_YAML_TAG.data()]) + return false; + rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as(); - static bool decode(YAML::Node const& node, SHMaterialSpec& rhs) + // Retrieve Subpass + if (!node[SUBPASS_YAML_TAG.data()]) + return false; + rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as(); + + // Retrieve + if (!node[PROPS_YAML_TAG.data()]) + return false; + rhs.properties = node[PROPS_YAML_TAG.data()]; + + 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()] = SHResourceManager::GetAssetID(rhs.GetMaterial()->GetBaseMaterial()).value_or(0); + return node; + } + static bool decode(YAML::Node const& node, SHRenderable& rhs) + { + if (node[MESH_YAML_TAG.data()].IsDefined()) { - // Retrieve Shader Asset IDs - if (!node[VERT_SHADER_YAML_TAG.data()]) - return false; - rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as(); - if (!node[FRAG_SHADER_YAML_TAG.data()]) - return false; - rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as(); - - // Retrieve Subpass - if (!node[SUBPASS_YAML_TAG.data()]) - return false; - rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as(); - - // Retrieve - if (!node[PROPS_YAML_TAG.data()]) - return false; - rhs.properties = node[PROPS_YAML_TAG.data()]; - - return true; + rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); } - }; - - 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) + if (node[MAT_YAML_TAG.data()].IsDefined()) + { + // Temporarily, use default material + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + Handle baseMat = SHResourceManager::LoadOrGet(node[MAT_YAML_TAG.data()].as()); + if (!baseMat) { - YAML::Node node; - node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); - node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMaterial()->GetBaseMaterial()).value_or(0); - return node; + baseMat = gfxSystem->GetDefaultMaterial(); + SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material."); } - static bool decode(YAML::Node const& node, SHRenderable& rhs) - { - if (node[MESH_YAML_TAG.data()].IsDefined()) - { - rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); - } - if (node[MAT_YAML_TAG.data()].IsDefined()) - { - // Temporarily, use default material - auto gfxSystem = SHSystemManager::GetSystem(); - if (!gfxSystem) - return false; - Handle baseMat = SHResourceManager::LoadOrGet(node[MAT_YAML_TAG.data()].as()); - if (!baseMat) - { - baseMat = gfxSystem->GetDefaultMaterial(); - SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material."); - } - rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat)); - } - return true; - } - }; + rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat)); + } + return true; + } + }; } namespace SHADE @@ -550,7 +491,7 @@ namespace SHADE auto properties = propType.get_properties(); for (auto const& property : properties) { - if(propertyNode[property.get_name().data()].IsDefined()) + if (propertyNode[property.get_name().data()].IsDefined()) InitializeProperty(component, property, propertyNode[property.get_name().data()]); } } @@ -564,7 +505,7 @@ namespace SHADE return; auto rttrType = rttr::type::get(); auto componentNode = componentsNode[rttrType.get_name().data()]; - if(!componentNode.IsDefined()) + if (!componentNode.IsDefined()) return; auto properties = rttrType.get_properties(); for (auto const& prop : properties)