#include #include #include namespace XCEngine { namespace Resources { Material::Material() = default; Material::~Material() = default; void Material::Release() { m_shader.Reset(); m_renderQueue = static_cast(MaterialRenderQueue::Geometry); m_renderState = MaterialRenderState(); m_shaderPass.Clear(); m_tags.Clear(); m_properties.Clear(); m_textureBindings.Clear(); m_constantBufferData.Clear(); m_isValid = false; UpdateMemorySize(); } void Material::SetShader(const ResourceHandle& shader) { m_shader = shader; UpdateMemorySize(); } void Material::SetRenderQueue(Core::int32 renderQueue) { m_renderQueue = renderQueue; } void Material::SetRenderQueue(MaterialRenderQueue renderQueue) { SetRenderQueue(static_cast(renderQueue)); } void Material::SetRenderState(const MaterialRenderState& renderState) { m_renderState = renderState; UpdateMemorySize(); } void Material::SetShaderPass(const Containers::String& shaderPass) { m_shaderPass = shaderPass; UpdateMemorySize(); } void Material::SetTag(const Containers::String& name, const Containers::String& value) { for (TagEntry& tag : m_tags) { if (tag.name == name) { tag.value = value; UpdateMemorySize(); return; } } TagEntry tag; tag.name = name; tag.value = value; m_tags.PushBack(tag); UpdateMemorySize(); } Containers::String Material::GetTag(const Containers::String& name) const { for (const TagEntry& tag : m_tags) { if (tag.name == name) { return tag.value; } } return Containers::String(); } bool Material::HasTag(const Containers::String& name) const { for (const TagEntry& tag : m_tags) { if (tag.name == name) { return true; } } return false; } void Material::RemoveTag(const Containers::String& name) { for (size_t tagIndex = 0; tagIndex < m_tags.Size(); ++tagIndex) { if (m_tags[tagIndex].name == name) { if (tagIndex != m_tags.Size() - 1) { m_tags[tagIndex] = std::move(m_tags.Back()); } m_tags.PopBack(); UpdateMemorySize(); return; } } } void Material::ClearTags() { m_tags.Clear(); UpdateMemorySize(); } void Material::SetFloat(const Containers::String& name, float value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Float; prop.value.floatValue[0] = value; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetFloat2(const Containers::String& name, const Math::Vector2& value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Float2; prop.value.floatValue[0] = value.x; prop.value.floatValue[1] = value.y; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetFloat3(const Containers::String& name, const Math::Vector3& value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Float3; prop.value.floatValue[0] = value.x; prop.value.floatValue[1] = value.y; prop.value.floatValue[2] = value.z; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetFloat4(const Containers::String& name, const Math::Vector4& value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Float4; prop.value.floatValue[0] = value.x; prop.value.floatValue[1] = value.y; prop.value.floatValue[2] = value.z; prop.value.floatValue[3] = value.w; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetInt(const Containers::String& name, Core::int32 value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Int; prop.value.intValue[0] = value; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetBool(const Containers::String& name, bool value) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Bool; prop.value.boolValue = value; prop.refCount = 1; m_properties.Insert(name, prop); UpdateMemorySize(); } void Material::SetTexture(const Containers::String& name, const ResourceHandle& texture) { MaterialProperty prop; prop.name = name; prop.type = MaterialPropertyType::Texture; prop.refCount = 1; m_properties.Insert(name, prop); for (auto& binding : m_textureBindings) { if (binding.name == name) { binding.texture = texture; UpdateMemorySize(); return; } } TextureBinding binding; binding.name = name; binding.slot = static_cast(m_textureBindings.Size()); binding.texture = texture; m_textureBindings.PushBack(binding); UpdateMemorySize(); } float Material::GetFloat(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Float) { return prop->value.floatValue[0]; } return 0.0f; } Math::Vector2 Material::GetFloat2(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Float2) { return Math::Vector2(prop->value.floatValue[0], prop->value.floatValue[1]); } return Math::Vector2::Zero(); } Math::Vector3 Material::GetFloat3(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Float3) { return Math::Vector3(prop->value.floatValue[0], prop->value.floatValue[1], prop->value.floatValue[2]); } return Math::Vector3::Zero(); } Math::Vector4 Material::GetFloat4(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Float4) { return Math::Vector4(prop->value.floatValue[0], prop->value.floatValue[1], prop->value.floatValue[2], prop->value.floatValue[3]); } return Math::Vector4::Zero(); } Core::int32 Material::GetInt(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Int) { return prop->value.intValue[0]; } return 0; } bool Material::GetBool(const Containers::String& name) const { auto* prop = m_properties.Find(name); if (prop && prop->type == MaterialPropertyType::Bool) { return prop->value.boolValue; } return false; } ResourceHandle Material::GetTexture(const Containers::String& name) const { for (const auto& binding : m_textureBindings) { if (binding.name == name) { return binding.texture; } } return ResourceHandle(); } void Material::UpdateConstantBuffer() { m_constantBufferData.Clear(); UpdateMemorySize(); } void Material::RecalculateMemorySize() { UpdateMemorySize(); } bool Material::HasProperty(const Containers::String& name) const { return m_properties.Contains(name); } void Material::RemoveProperty(const Containers::String& name) { m_properties.Erase(name); UpdateMemorySize(); } void Material::ClearAllProperties() { m_properties.Clear(); m_textureBindings.Clear(); m_constantBufferData.Clear(); UpdateMemorySize(); } void Material::UpdateMemorySize() { m_memorySize = m_constantBufferData.Size() + sizeof(MaterialRenderState) + m_shaderPass.Length() + m_tags.Size() * sizeof(TagEntry) + m_textureBindings.Size() * sizeof(TextureBinding) + m_properties.Size() * sizeof(MaterialProperty) + m_name.Length() + m_path.Length(); for (const TagEntry& tag : m_tags) { m_memorySize += tag.name.Length(); m_memorySize += tag.value.Length(); } for (const auto& binding : m_textureBindings) { m_memorySize += binding.name.Length(); } } } // namespace Resources } // namespace XCEngine