#pragma once class BaseMaterial; class PostProcessingMaterial; class MaterialManager final : public Singleton { public: MaterialManager(const MaterialManager& other) = delete; MaterialManager(MaterialManager&& other) noexcept = delete; MaterialManager& operator=(const MaterialManager& other) = delete; MaterialManager& operator=(MaterialManager&& other) noexcept = delete; template std::enable_if, T>::type* CreateMaterial(); template std::enable_if, T>::type* CreateMaterial(); template std::enable_if, T>::type* GetMaterial(UINT materialId) const; template std::enable_if, T>::type* GetMaterial(UINT materialId) const; BaseMaterial* GetMaterial(UINT materialId) const; void RemoveMaterial(UINT materialId, bool deleteObj = false); void RemoveMaterial(BaseMaterial* pMaterial, bool deleteObj = false); void RemoveMaterial(PostProcessingMaterial* pMaterial, bool deleteObj = false); protected: void Initialize() override {}; private: friend Singleton; MaterialManager() = default; ~MaterialManager(); static constexpr UINT MATERIAL_PP_ID_OFFSET{ UINT_MAX / 2 }; static bool IsValid(UINT id) { return id != UINT_MAX; } static bool IsBaseMaterial(UINT id) { return id < MATERIAL_PP_ID_OFFSET; } static bool IsPostProcessingMaterial(UINT id) { return id != UINT_MAX && id >= MATERIAL_PP_ID_OFFSET; } static UINT FromPPID(UINT id) { return id - MATERIAL_PP_ID_OFFSET; } static UINT ToPPID(UINT id) { return id + MATERIAL_PP_ID_OFFSET; } PostProcessingMaterial* GetMaterial_Post(UINT materialId) const; std::vector m_Materials{}; std::vector m_MaterialsPP{}; }; template std::enable_if, T>::type* MaterialManager::CreateMaterial() { auto pMaterial = new T(); UINT newMaterialId{ UINT_MAX}; for (size_t i{ 0 }; i < m_Materials.size(); ++i) { if (m_Materials[i] == nullptr) { newMaterialId = UINT(i); break; } } if (newMaterialId == UINT_MAX) { newMaterialId = UINT(m_Materials.size()); m_Materials.push_back(pMaterial); } else m_Materials[newMaterialId] = pMaterial; pMaterial->SetMaterialName(StringUtil::utf8_decode(typeid(T).name())); pMaterial->Initialize(m_GameContext.d3dContext, newMaterialId); return pMaterial; } template std::enable_if, T>::type* MaterialManager::CreateMaterial() { auto pMaterial = new T(); UINT newMaterialId{ UINT_MAX }; for (size_t i{ 0 }; i < m_MaterialsPP.size(); ++i) { if (m_MaterialsPP[i] == nullptr) { newMaterialId = UINT(i); break; } } if (newMaterialId == UINT_MAX) { newMaterialId = UINT(m_MaterialsPP.size()); m_MaterialsPP.push_back(pMaterial); } else m_MaterialsPP[newMaterialId] = pMaterial; pMaterial->InitializeBase(m_GameContext, ToPPID(newMaterialId)); //Todo: Fix Virtual Overload Initialize return pMaterial; } template std::enable_if, T>::type* MaterialManager::GetMaterial(UINT materialId) const { if(auto pBase = GetMaterial(materialId)) { if(T * pDerived = dynamic_cast(pBase)) { return pDerived; } HANDLE_ERROR(L"Failed to cast Material (BaseMaterial) with ID={} to \'{}\'", materialId, StringUtil::utf8_decode(typeid(T).name())); } return nullptr; } template std::enable_if, T>::type* MaterialManager::GetMaterial(UINT materialId) const { if (auto pBase = GetMaterial_Post(materialId)) { if (T* pDerived = dynamic_cast(pBase)) { return pDerived; } HANDLE_ERROR(L"Failed to cast Material (PostProcessingMaterial) with ID={} to \'{}\'", materialId, StringUtil::utf8_decode(typeid(T).name())); } return nullptr; }