From 7f8430b71daaef0fa4c587b10695497fc4e83cb7 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 3 Apr 2025 13:05:13 -0400 Subject: [PATCH] Updated material properties to use std::variant --- .../PostProcess/AutoExposureEffect.cpp | 20 +- .../Rendering/PostProcess/BloomEffect.cpp | 12 +- .../PostProcess/TonemappingEffect.cpp | 6 +- .../OvCore/Rendering/ShadowRenderFeature.cpp | 8 +- .../src/OvCore/Rendering/ShadowRenderPass.cpp | 4 +- .../Resources/Loaders/MaterialLoader.cpp | 4 +- .../OvCore/src/OvCore/Resources/Material.cpp | 147 +++++------ .../src/OvEditor/Core/EditorActions.cpp | 18 +- .../src/OvEditor/Panels/AssetView.cpp | 12 +- .../src/OvEditor/Panels/MaterialEditor.cpp | 78 ++++-- .../src/OvEditor/Panels/SceneView.cpp | 4 +- .../OvEditor/Rendering/DebugSceneRenderer.cpp | 12 +- .../OvEditor/Rendering/GizmoRenderFeature.cpp | 10 +- .../src/OvEditor/Rendering/GridRenderPass.cpp | 2 +- .../Rendering/OutlineRenderFeature.cpp | 6 +- .../OvEditor/Rendering/PickingRenderPass.cpp | 12 +- .../OvGame/src/OvGame/Core/Context.cpp | 4 +- .../include/OvRendering/Data/Material.h | 49 ++-- .../include/OvRendering/Data/Material.inl | 50 ---- .../src/OvRendering/Core/ABaseRenderer.cpp | 6 +- .../src/OvRendering/Data/Material.cpp | 236 +++++++++++++----- .../Features/DebugShapeRenderFeature.cpp | 8 +- .../HAL/OpenGL/GLShaderProgram.cpp | 41 +-- 23 files changed, 429 insertions(+), 320 deletions(-) delete mode 100644 Sources/Overload/OvRendering/include/OvRendering/Data/Material.inl diff --git a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/AutoExposureEffect.cpp b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/AutoExposureEffect.cpp index 785af64d8..1817dc4ea 100644 --- a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/AutoExposureEffect.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/AutoExposureEffect.cpp @@ -55,7 +55,7 @@ void OvCore::Rendering::PostProcess::AutoExposureEffect::Draw( // Luminance calculation m_luminanceBuffer.Resize(kLuminanceBufferResolution, kLuminanceBufferResolution); - m_luminanceMaterial.Set("_CenterWeightBias", autoExposureSettings.centerWeightBias, true); + m_luminanceMaterial.SetProperty("_CenterWeightBias", autoExposureSettings.centerWeightBias, true); m_renderer.Blit(p_pso, p_src, m_luminanceBuffer, m_luminanceMaterial, OvRendering::Settings::EBlitFlags::DEFAULT & ~OvRendering::Settings::EBlitFlags::RESIZE_DST_TO_MATCH_SRC); const auto luminanceTex = m_luminanceBuffer.GetAttachment(OvRendering::Settings::EFramebufferAttachment::COLOR); @@ -76,18 +76,18 @@ void OvCore::Rendering::PostProcess::AutoExposureEffect::Draw( m_exposurePingPongIndex = (m_exposurePingPongIndex + 1) % 2; // Exposure adaptation - m_exposureMaterial.Set("_LuminanceTexture", luminanceTex, true); - m_exposureMaterial.Set("_MinLuminanceEV", autoExposureSettings.minLuminanceEV, true); - m_exposureMaterial.Set("_MaxLuminanceEV", autoExposureSettings.maxLuminanceEV, true); - m_exposureMaterial.Set("_ExposureCompensationEV", autoExposureSettings.exposureCompensationEV, true); - m_exposureMaterial.Set("_ElapsedTime", elapsedTime, true); - m_exposureMaterial.Set("_Progressive", static_cast(autoExposureSettings.progressive), true); - m_exposureMaterial.Set("_SpeedUp", autoExposureSettings.speedUp, true); - m_exposureMaterial.Set("_SpeedDown", autoExposureSettings.speedDown, true); + m_exposureMaterial.SetProperty("_LuminanceTexture", &luminanceTex.value(), true); + m_exposureMaterial.SetProperty("_MinLuminanceEV", autoExposureSettings.minLuminanceEV, true); + m_exposureMaterial.SetProperty("_MaxLuminanceEV", autoExposureSettings.maxLuminanceEV, true); + m_exposureMaterial.SetProperty("_ExposureCompensationEV", autoExposureSettings.exposureCompensationEV, true); + m_exposureMaterial.SetProperty("_ElapsedTime", elapsedTime, true); + m_exposureMaterial.SetProperty("_Progressive", static_cast(autoExposureSettings.progressive), true); + m_exposureMaterial.SetProperty("_SpeedUp", autoExposureSettings.speedUp, true); + m_exposureMaterial.SetProperty("_SpeedDown", autoExposureSettings.speedDown, true); m_renderer.Blit(p_pso, previousExposure, currentExposure, m_exposureMaterial); // Apply the exposure to the final image const auto exposureTex = currentExposure.GetAttachment(OvRendering::Settings::EFramebufferAttachment::COLOR); - m_compensationMaterial.Set("_ExposureTexture", exposureTex, true); + m_compensationMaterial.SetProperty("_ExposureTexture", &exposureTex.value(), true); m_renderer.Blit(p_pso, p_src, p_dst, m_compensationMaterial); } diff --git a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/BloomEffect.cpp b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/BloomEffect.cpp index e3b45dfd9..4e38ac471 100644 --- a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/BloomEffect.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/BloomEffect.cpp @@ -49,7 +49,7 @@ void OvCore::Rendering::PostProcess::BloomEffect::Draw( const auto& bloomSettings = static_cast(p_settings); // Step 1: Extract bright spots from the source - m_brightnessMaterial.Set("_Threshold", bloomSettings.threshold, true); + m_brightnessMaterial.SetProperty("_Threshold", bloomSettings.threshold, true); m_renderer.Blit(p_pso, p_src, m_bloomPingPong[0], m_brightnessMaterial); // Step 2: Apply gaussian blur on bright spots (horizontal and vertical) @@ -60,9 +60,9 @@ void OvCore::Rendering::PostProcess::BloomEffect::Draw( auto& currentSrc = horizontal ? m_bloomPingPong[0] : m_bloomPingPong[1]; auto& currentDst = horizontal ? m_bloomPingPong[1] : m_bloomPingPong[0]; - m_blurMaterial.Set("_Horizontal", horizontal ? true : false, true); - m_blurMaterial.Set("_BlurSize", bloomSettings.radius, true); - m_blurMaterial.Set("_KernelSize", bloomSettings.kernelSize, true); + m_blurMaterial.SetProperty("_Horizontal", horizontal ? true : false, true); + m_blurMaterial.SetProperty("_BlurSize", bloomSettings.radius, true); + m_blurMaterial.SetProperty("_KernelSize", bloomSettings.kernelSize, true); m_renderer.Blit(p_pso, currentSrc, currentDst, m_blurMaterial); horizontal = !horizontal; @@ -70,7 +70,7 @@ void OvCore::Rendering::PostProcess::BloomEffect::Draw( // Step 3: Combine bloom with original framebuffer const auto bloomTex = m_bloomPingPong[0].GetAttachment(OvRendering::Settings::EFramebufferAttachment::COLOR); - m_bloomMaterial.Set("_BloomTexture", bloomTex, true); - m_bloomMaterial.Set("_BloomIntensity", bloomSettings.intensity, true); + m_bloomMaterial.SetProperty("_BloomTexture", &bloomTex.value(), true); + m_bloomMaterial.SetProperty("_BloomIntensity", bloomSettings.intensity, true); m_renderer.Blit(p_pso, p_src, p_dst, m_bloomMaterial); } diff --git a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/TonemappingEffect.cpp b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/TonemappingEffect.cpp index b230784f6..fbb784f4f 100644 --- a/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/TonemappingEffect.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Rendering/PostProcess/TonemappingEffect.cpp @@ -23,8 +23,8 @@ void OvCore::Rendering::PostProcess::TonemappingEffect::Draw( const auto& tonemappingSettings = static_cast(p_settings); // Tonemapping - m_tonemappingMaterial.Set("_Exposure", tonemappingSettings.exposure, true); - m_tonemappingMaterial.Set("_Mode", static_cast(tonemappingSettings.mode), true); - m_tonemappingMaterial.Set("_GammaCorrection", static_cast(tonemappingSettings.gammaCorrection), true); + m_tonemappingMaterial.SetProperty("_Exposure", tonemappingSettings.exposure, true); + m_tonemappingMaterial.SetProperty("_Mode", static_cast(tonemappingSettings.mode), true); + m_tonemappingMaterial.SetProperty("_GammaCorrection", static_cast(tonemappingSettings.gammaCorrection), true); m_renderer.Blit(p_pso, p_src, p_dst, m_tonemappingMaterial); } diff --git a/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderFeature.cpp b/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderFeature.cpp index b4a0d3e71..1605bda75 100644 --- a/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderFeature.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderFeature.cpp @@ -4,8 +4,12 @@ * @licence: MIT */ + #include #include + +#include + #include constexpr uint8_t kMaxShadowMaps = 1; @@ -38,8 +42,8 @@ void OvCore::Rendering::ShadowRenderFeature::OnBeforeDraw(OvRendering::Data::Pip if (light.type == OvRendering::Settings::ELightType::DIRECTIONAL) { const auto shadowTex = light.GetShadowBuffer().GetAttachment(OvRendering::Settings::EFramebufferAttachment::DEPTH); - material.Set("_ShadowMap", shadowTex, true); // Single use material property - material.Set("_LightSpaceMatrix", light.GetLightSpaceMatrix()); + material.SetProperty("_ShadowMap", &shadowTex.value(), true); // Single use material property + material.SetProperty("_LightSpaceMatrix", light.GetLightSpaceMatrix()); ++lightIndex; } } diff --git a/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderPass.cpp b/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderPass.cpp index f1e79e41f..53db71f41 100644 --- a/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderPass.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Rendering/ShadowRenderPass.cpp @@ -58,7 +58,7 @@ void OvCore::Rendering::ShadowRenderPass::Draw(OvRendering::Data::PipelineState light.UpdateShadowData(frameDescriptor.camera.value()); const auto& lightSpaceMatrix = light.GetLightSpaceMatrix(); const auto& shadowBuffer = light.GetShadowBuffer(); - m_shadowMaterial.Set("_LightSpaceMatrix", lightSpaceMatrix); + m_shadowMaterial.SetProperty("_LightSpaceMatrix", lightSpaceMatrix); shadowBuffer.Bind(); m_renderer.SetViewport(0, 0, light.shadowMapResolution, light.shadowMapResolution); m_renderer.Clear(true, true, true); @@ -108,7 +108,7 @@ void OvCore::Rendering::ShadowRenderPass::DrawOpaques( drawable.material = m_shadowMaterial; drawable.stateMask = m_shadowMaterial.GenerateStateMask(); - drawable.material.value().Set("_ModelMatrix", modelMatrix); + drawable.material.value().SetProperty("_ModelMatrix", modelMatrix); m_renderer.DrawEntity(p_pso, drawable); } diff --git a/Sources/Overload/OvCore/src/OvCore/Resources/Loaders/MaterialLoader.cpp b/Sources/Overload/OvCore/src/OvCore/Resources/Loaders/MaterialLoader.cpp index e584060eb..2054b3325 100644 --- a/Sources/Overload/OvCore/src/OvCore/Resources/Loaders/MaterialLoader.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Resources/Loaders/MaterialLoader.cpp @@ -4,7 +4,9 @@ * @licence: MIT */ -#include "OvCore/Resources/Loaders/MaterialLoader.h" +#include + +#include OvCore::Resources::Material * OvCore::Resources::Loaders::MaterialLoader::Create(const std::string & p_path) { diff --git a/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp b/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp index e18f77506..6c8c577ea 100644 --- a/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp +++ b/Sources/Overload/OvCore/src/OvCore/Resources/Material.cpp @@ -4,13 +4,12 @@ * @licence: MIT */ -#include "OvCore/Resources/Material.h" +#include -void OvCore::Resources::Material::OnSerialize(tinyxml2::XMLDocument & p_doc, tinyxml2::XMLNode * p_node) +void OvCore::Resources::Material::OnSerialize(tinyxml2::XMLDocument& p_doc, tinyxml2::XMLNode* p_node) { using namespace OvCore::Helpers; using namespace OvRendering::Settings; - using namespace OvRendering::Resources; using namespace OvMaths; Serializer::SerializeShader(p_doc, p_node, "shader", m_shader); @@ -33,54 +32,80 @@ void OvCore::Resources::Material::OnSerialize(tinyxml2::XMLDocument & p_doc, tin tinyxml2::XMLNode* uniformsNode = p_doc.NewElement("uniforms"); p_node->InsertEndChild(uniformsNode); - for (const auto&[name, prop] : m_properties) + for (const auto& [name, prop] : m_properties) { auto& value = prop.value; - tinyxml2::XMLNode* uniform = p_doc.NewElement("uniform"); - uniformsNode->InsertEndChild(uniform); // Instead of p_node, use uniformNode (To create) + uniformsNode->InsertEndChild(uniform); const auto uniformInfo = m_shader->GetProgram().GetUniformInfo(name); - Serializer::SerializeString(p_doc, uniform, "name", name); - if (uniformInfo && value.has_value()) + if (uniformInfo && !std::holds_alternative(value)) { - switch (uniformInfo->type) - { - case EUniformType::BOOL: - if (value.type() == typeid(bool)) Serializer::SerializeInt(p_doc, uniform, "value", std::any_cast(value)); - break; - - case EUniformType::INT: - if (value.type() == typeid(int)) Serializer::SerializeInt(p_doc, uniform, "value", std::any_cast(value)); - break; - - case EUniformType::FLOAT: - if (value.type() == typeid(float)) Serializer::SerializeFloat(p_doc, uniform, "value", std::any_cast(value)); - break; - - case EUniformType::FLOAT_VEC2: - if (value.type() == typeid(FVector2)) Serializer::SerializeVec2(p_doc, uniform, "value", std::any_cast(value)); - break; + auto visitor = [&](auto&& arg) { + using T = std::decay_t; + using enum EUniformType; + const auto type = uniformInfo->type; - case EUniformType::FLOAT_VEC3: - if (value.type() == typeid(FVector3)) Serializer::SerializeVec3(p_doc, uniform, "value", std::any_cast(value)); - break; - - case EUniformType::FLOAT_VEC4: - if (value.type() == typeid(FVector4)) Serializer::SerializeVec4(p_doc, uniform, "value", std::any_cast(value)); - break; + if constexpr (std::same_as) + { + if (type == BOOL) + { + Serializer::SerializeInt(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == INT) + { + Serializer::SerializeInt(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == FLOAT) + { + Serializer::SerializeFloat(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == FLOAT_VEC2) + { + Serializer::SerializeVec2(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == FLOAT_VEC3) + { + Serializer::SerializeVec3(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == FLOAT_VEC4) + { + Serializer::SerializeVec4(p_doc, uniform, "value", arg); + } + } + else if constexpr (std::same_as) + { + if (type == SAMPLER_2D) + { + Serializer::SerializeTexture(p_doc, uniform, "value", arg); + } + } + // No need to handle TextureHandle* here as it's not serializable (only texture assets are) + }; - case EUniformType::SAMPLER_2D: - if (value.type() == typeid(Texture*)) Serializer::SerializeTexture(p_doc, uniform, "value", std::any_cast(value)); - break; - } + std::visit(visitor, value); } } } -void OvCore::Resources::Material::OnDeserialize(tinyxml2::XMLDocument & p_doc, tinyxml2::XMLNode * p_node) +void OvCore::Resources::Material::OnDeserialize(tinyxml2::XMLDocument& p_doc, tinyxml2::XMLNode* p_node) { using namespace OvCore::Helpers; @@ -101,13 +126,13 @@ void OvCore::Resources::Material::OnDeserialize(tinyxml2::XMLDocument & p_doc, t } /* We get the shader with Deserialize method */ - OvRendering::Resources::Shader* deserializedShader = OvCore::Helpers::Serializer::DeserializeShader(p_doc, p_node, "shader"); + const auto shader = Serializer::DeserializeShader(p_doc, p_node, "shader"); /* We verify that the shader is valid (Not null) */ - if (deserializedShader) + if (shader) { /* If the shader is valid, we set it to the material (Modify m_shader pointer + Query + FillUniforms) */ - SetShader(deserializedShader); + SetShader(shader); tinyxml2::XMLNode* uniformsNode = p_node->FirstChildElement("uniforms"); // Access to "Uniforms" (Every uniform will be attached to "Uniforms") @@ -130,41 +155,19 @@ void OvCore::Resources::Material::OnDeserialize(tinyxml2::XMLDocument & p_doc, t /* Deserialization of the uniform value depending on the uniform type (Deserialization result to std::any) */ switch (uniformInfo->type) { - case OvRendering::Settings::EUniformType::BOOL: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeBoolean(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::INT: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeInt(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::FLOAT: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeFloat(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::FLOAT_VEC2: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeVec2(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::FLOAT_VEC3: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeVec3(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::FLOAT_VEC4: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeVec4(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::FLOAT_MAT4: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeMat4(p_doc, uniform, "value"); - break; - - case OvRendering::Settings::EUniformType::SAMPLER_2D: - m_properties[uniformInfo->name] = OvCore::Helpers::Serializer::DeserializeTexture(p_doc, uniform, "value"); - break; + using enum OvRendering::Settings::EUniformType; + case BOOL: SetProperty(uniformInfo->name, Serializer::DeserializeBoolean(p_doc, uniform, "value")); break; + case INT: SetProperty(uniformInfo->name, Serializer::DeserializeInt(p_doc, uniform, "value")); break; + case FLOAT: SetProperty(uniformInfo->name, Serializer::DeserializeFloat(p_doc, uniform, "value")); break; + case FLOAT_VEC2: SetProperty(uniformInfo->name, Serializer::DeserializeVec2(p_doc, uniform, "value")); break; + case FLOAT_VEC3: SetProperty(uniformInfo->name, Serializer::DeserializeVec3(p_doc, uniform, "value")); break; + case FLOAT_VEC4: SetProperty(uniformInfo->name, Serializer::DeserializeVec4(p_doc, uniform, "value")); break; + case FLOAT_MAT4: SetProperty(uniformInfo->name, Serializer::DeserializeMat4(p_doc, uniform, "value")); break; + case SAMPLER_2D: SetProperty(uniformInfo->name, Serializer::DeserializeTexture(p_doc, uniform, "value")); break; } } } } } } -} \ No newline at end of file +} diff --git a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp index 46b6daf10..6ebcbaeef 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Core/EditorActions.cpp @@ -849,12 +849,22 @@ void OvEditor::Core::EditorActions::PropagateFileRename(std::string p_previousNa { if (auto texture = OvCore::Global::ServiceLocator::Get().GetResource(p_previousName, false)) { - for (auto[name, instance] : OvCore::Global::ServiceLocator::Get().GetResources()) + for (auto [name, instance] : OvCore::Global::ServiceLocator::Get().GetResources()) + { if (instance) - for (auto&[name, prop] : instance->GetProperties()) - if (prop.value.has_value() && prop.value.type() == typeid(OvRendering::Resources::Texture*)) - if (std::any_cast(prop.value) == texture) + { + for (auto& [name, prop] : instance->GetProperties()) + { + if (const auto pval = std::get_if(&prop.value); pval && *pval) + { + if (*pval == texture) + { prop.value = static_cast(nullptr); + } + } + } + } + } auto& assetView = EDITOR_PANEL(Panels::AssetView, "Asset View"); auto assetViewRes = assetView.GetResource(); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp index 63c1583ed..99491f8c3 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/AssetView.cpp @@ -51,16 +51,16 @@ OvEditor::Panels::AssetView::AssetView /* Default Material */ m_defaultMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Standard.ovfx"]); - m_defaultMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); - m_defaultMaterial.Set("u_Shininess", 100.0f); - m_defaultMaterial.Set("u_DiffuseMap", nullptr); + m_defaultMaterial.SetProperty("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); + m_defaultMaterial.SetProperty("u_Shininess", 100.0f); + m_defaultMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); /* Texture Material */ m_textureMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); - m_textureMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); + m_textureMaterial.SetProperty("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.f)); m_textureMaterial.SetBackfaceCulling(false); m_textureMaterial.SetBlendable(true); - m_textureMaterial.Set("u_DiffuseMap", nullptr); + m_textureMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); m_image->AddPlugin>>("File").DataReceivedEvent += [this](auto p_data) { @@ -118,7 +118,7 @@ void OvEditor::Panels::AssetView::SetTexture(OvRendering::Resources::Texture& p_ m_assetActor->transform.SetLocalRotation(OvMaths::FQuaternion({ -90.0f, 0.0f, 0.0f })); m_assetActor->transform.SetLocalScale(OvMaths::FVector3::One * 3.0f); m_modelRenderer->SetModel(EDITOR_CONTEXT(editorResources)->GetModel("Plane")); - m_textureMaterial.Set("u_DiffuseMap", &p_texture); + m_textureMaterial.SetProperty("u_DiffuseMap", &p_texture); m_materialRenderer->FillWithMaterial(m_textureMaterial); m_cameraController.MoveToTarget(*m_assetActor); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp index 533687956..823d88927 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp @@ -117,8 +117,8 @@ OvEditor::Panels::MaterialEditor::MaterialEditor m_settings->enabled = false; m_shaderSettings->enabled = false; - m_materialDroppedEvent += std::bind(&MaterialEditor::OnMaterialDropped, this); - m_shaderDroppedEvent += std::bind(&MaterialEditor::OnShaderDropped, this); + m_materialDroppedEvent += std::bind(&MaterialEditor::OnMaterialDropped, this); + m_shaderDroppedEvent += std::bind(&MaterialEditor::OnShaderDropped, this); } void OvEditor::Panels::MaterialEditor::Refresh() @@ -312,7 +312,13 @@ void OvEditor::Panels::MaterialEditor::GenerateShaderSettingsContent() m_shaderSettingsColumns->RemoveAllWidgets(); // Ensure that the m_shaderSettingsColumns is empty - std::multimap> sortedUniformsData; + std::multimap< + int, + std::pair< + std::string, + OvRendering::Data::MaterialPropertyType* + > + > sortedUniformsData; for (auto&[name, value] : m_target->GetProperties()) { @@ -333,38 +339,62 @@ void OvEditor::Panels::MaterialEditor::GenerateShaderSettingsContent() case EUniformType::BOOL: orderID = 6; break; } - sortedUniformsData.emplace(orderID, std::pair{ name, & value.value }); + sortedUniformsData.emplace(orderID, std::pair{ name, & value.value }); } } for (auto& [order, info] : sortedUniformsData) { auto uniformData = m_target->GetShader()->GetProgram().GetUniformInfo(info.first); - + if (uniformData) { const auto formattedType = UniformFormat(info.first); - switch (uniformData->type) - { - case EUniformType::BOOL: GUIDrawer::DrawBoolean(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second)); break; - case EUniformType::INT: GUIDrawer::DrawScalar(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second)); break; - case EUniformType::FLOAT: GUIDrawer::DrawScalar(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second), 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); break; - case EUniformType::FLOAT_VEC2: GUIDrawer::DrawVec2(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second), 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); break; - case EUniformType::FLOAT_VEC3: DrawHybridVec3(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second), 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); break; - case EUniformType::FLOAT_VEC4: DrawHybridVec4(*m_shaderSettingsColumns, formattedType, reinterpret_cast(*info.second), 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); break; - case EUniformType::SAMPLER_2D: + + // Create a visitor to handle each type in the variant + auto drawVisitor = [&](auto& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { - try - { - auto& texture = std::any_cast(*info.second); - GUIDrawer::DrawTexture(*m_shaderSettingsColumns, formattedType, texture); - } - catch (const std::bad_any_cast&) - { - // If the cast failed, it means that the uniform is not a texture (It's a texture handle) - } + if (uniformData->type == EUniformType::BOOL) + GUIDrawer::DrawBoolean(*m_shaderSettingsColumns, formattedType, arg); } - } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::INT) + GUIDrawer::DrawScalar(*m_shaderSettingsColumns, formattedType, arg); + } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::FLOAT) + GUIDrawer::DrawScalar(*m_shaderSettingsColumns, formattedType, arg, 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); + } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::FLOAT_VEC2) + GUIDrawer::DrawVec2(*m_shaderSettingsColumns, formattedType, arg, 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); + } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::FLOAT_VEC3) + DrawHybridVec3(*m_shaderSettingsColumns, formattedType, arg, 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); + } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::FLOAT_VEC4) + DrawHybridVec4(*m_shaderSettingsColumns, formattedType, arg, 0.01f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); + } + else if constexpr (std::is_same_v) + { + if (uniformData->type == EUniformType::SAMPLER_2D) + GUIDrawer::DrawTexture(*m_shaderSettingsColumns, formattedType, arg); + } + // No UI for TextureHandle* since it's not handled in the original code + }; + + // Apply the visitor to the variant + std::visit(drawVisitor, *info.second); } } } diff --git a/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp b/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp index cd0dc8df8..3066f4b09 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp @@ -26,8 +26,8 @@ OvEditor::Panels::SceneView::SceneView m_camera.SetFar(5000.0f); m_fallbackMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); - m_fallbackMaterial.Set("u_Diffuse", { 1.f, 0.f, 1.f, 1.0f }); - m_fallbackMaterial.Set("u_DiffuseMap", nullptr); + m_fallbackMaterial.SetProperty("u_Diffuse", OvMaths::FVector4{ 1.f, 0.f, 1.f, 1.0f }); + m_fallbackMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); m_image->AddPlugin>>("File").DataReceivedEvent += [this](auto p_data) { diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp index dcffe27dd..fed1fcc2b 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/DebugSceneRenderer.cpp @@ -78,8 +78,8 @@ class DebugCamerasRenderPass : public OvRendering::Core::ARenderPass DebugCamerasRenderPass(OvRendering::Core::CompositeRenderer& p_renderer) : OvRendering::Core::ARenderPass(p_renderer) { m_cameraMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Lambert.ovfx"]); - m_cameraMaterial.Set("u_Diffuse", FVector4(0.0f, 0.3f, 0.7f, 1.0f)); - m_cameraMaterial.Set("u_DiffuseMap", nullptr); + m_cameraMaterial.SetProperty("u_Diffuse", FVector4{ 0.0f, 0.3f, 0.7f, 1.0f }); + m_cameraMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); } protected: @@ -112,7 +112,7 @@ class DebugLightsRenderPass : public OvRendering::Core::ARenderPass DebugLightsRenderPass(OvRendering::Core::CompositeRenderer& p_renderer) : OvRendering::Core::ARenderPass(p_renderer) { m_lightMaterial.SetShader(EDITOR_CONTEXT(editorResources)->GetShader("Billboard")); - m_lightMaterial.Set("u_Diffuse", FVector4(1.f, 1.f, 0.5f, 0.5f)); + m_lightMaterial.SetProperty("u_Diffuse", FVector4{ 1.f, 1.f, 0.5f, 0.5f }); m_lightMaterial.SetBackfaceCulling(false); m_lightMaterial.SetBlendable(true); m_lightMaterial.SetDepthTest(false); @@ -123,7 +123,7 @@ class DebugLightsRenderPass : public OvRendering::Core::ARenderPass { auto& sceneDescriptor = m_renderer.GetDescriptor(); - m_lightMaterial.Set("u_Scale", OvEditor::Settings::EditorSettings::LightBillboardScale * 0.1f); + m_lightMaterial.SetProperty("u_Scale", OvEditor::Settings::EditorSettings::LightBillboardScale * 0.1f); for (auto light : sceneDescriptor.scene.GetFastAccessComponents().lights) { @@ -142,8 +142,8 @@ class DebugLightsRenderPass : public OvRendering::Core::ARenderPass nullptr; const auto& lightColor = light->GetColor(); - m_lightMaterial.Set("u_DiffuseMap", lightTexture); - m_lightMaterial.Set("u_Diffuse", OvMaths::FVector4(lightColor.x, lightColor.y, lightColor.z, 0.75f)); + m_lightMaterial.SetProperty("u_DiffuseMap", lightTexture); + m_lightMaterial.SetProperty("u_Diffuse", OvMaths::FVector4(lightColor.x, lightColor.y, lightColor.z, 0.75f)); m_renderer.GetFeature() .DrawModelWithSingleMaterial(p_pso, model, m_lightMaterial, modelMatrix); diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/GizmoRenderFeature.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/GizmoRenderFeature.cpp index 39be57b10..692126b65 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/GizmoRenderFeature.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/GizmoRenderFeature.cpp @@ -34,13 +34,13 @@ OvEditor::Rendering::GizmoRenderFeature::GizmoRenderFeature(OvRendering::Core::C /* Gizmo Arrow Material */ m_gizmoArrowMaterial.SetShader(EDITOR_CONTEXT(editorResources)->GetShader("Gizmo")); m_gizmoArrowMaterial.SetGPUInstances(3); - m_gizmoArrowMaterial.Set("u_IsBall", false); - m_gizmoArrowMaterial.Set("u_IsPickable", false); + m_gizmoArrowMaterial.SetProperty("u_IsBall", false); + m_gizmoArrowMaterial.SetProperty("u_IsPickable", false); /* Gizmo Ball Material */ m_gizmoBallMaterial.SetShader(EDITOR_CONTEXT(editorResources)->GetShader("Gizmo")); - m_gizmoBallMaterial.Set("u_IsBall", true); - m_gizmoBallMaterial.Set("u_IsPickable", false); + m_gizmoBallMaterial.SetProperty("u_IsBall", true); + m_gizmoBallMaterial.SetProperty("u_IsPickable", false); } std::string GetArrowModelName(OvEditor::Core::EGizmoOperation p_operation) @@ -93,7 +93,7 @@ void OvEditor::Rendering::GizmoRenderFeature::DrawGizmo( if (auto arrowModel = EDITOR_CONTEXT(editorResources)->GetModel(arrowModelName)) { const auto axisIndex = GetAxisIndexFromDirection(p_highlightedDirection); - m_gizmoArrowMaterial.Set("u_HighlightedAxis", axisIndex); + m_gizmoArrowMaterial.SetProperty("u_HighlightedAxis", axisIndex); m_renderer.GetFeature() .DrawModelWithSingleMaterial( diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/GridRenderPass.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/GridRenderPass.cpp index 48185bf40..ace990401 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/GridRenderPass.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/GridRenderPass.cpp @@ -41,7 +41,7 @@ void OvEditor::Rendering::GridRenderPass::Draw(OvRendering::Data::PipelineState OvMaths::FMatrix4::Translation({ gridDescriptor.viewPosition.x, 0.0f, gridDescriptor.viewPosition.z }) * OvMaths::FMatrix4::Scaling({ gridSize * 2.0f, 1.f, gridSize * 2.0f }); - m_gridMaterial.Set("u_Color", gridDescriptor.gridColor); + m_gridMaterial.SetProperty("u_Color", gridDescriptor.gridColor); // Stencil test to ensure the grid doesn't render over any other scene geometry pso.stencilTest = true; diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp index c115c8f2d..f1d349ccc 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/OutlineRenderFeature.cpp @@ -24,11 +24,11 @@ OvEditor::Rendering::OutlineRenderFeature::OutlineRenderFeature(OvRendering::Cor m_stencilFillMaterial.SetBackfaceCulling(true); m_stencilFillMaterial.SetDepthTest(false); m_stencilFillMaterial.SetColorWriting(false); - m_stencilFillMaterial.Set("u_DiffuseMap", nullptr); + m_stencilFillMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); /* Outline Material */ m_outlineMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); - m_outlineMaterial.Set("u_DiffuseMap", nullptr); + m_outlineMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); m_outlineMaterial.SetDepthTest(false); } @@ -73,7 +73,7 @@ void OvEditor::Rendering::OutlineRenderFeature::DrawOutlinePass(OvCore::ECS::Act pso.lineWidthPow2 = OvRendering::Utils::Conversions::FloatToPow2(p_thickness); // Prepare the outline material - m_outlineMaterial.Set("u_Diffuse", p_color); + m_outlineMaterial.SetProperty("u_Diffuse", p_color); DrawActorOutline(pso, p_actor); } diff --git a/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp b/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp index 40b81b1c1..3a3c6f34b 100644 --- a/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp +++ b/Sources/Overload/OvEditor/src/OvEditor/Rendering/PickingRenderPass.cpp @@ -29,13 +29,13 @@ OvEditor::Rendering::PickingRenderPass::PickingRenderPass(OvRendering::Core::Com /* Gizmo Pickable Material */ m_gizmoPickingMaterial.SetShader(EDITOR_CONTEXT(editorResources)->GetShader("Gizmo")); m_gizmoPickingMaterial.SetGPUInstances(3); - m_gizmoPickingMaterial.Set("u_IsBall", false); - m_gizmoPickingMaterial.Set("u_IsPickable", true); + m_gizmoPickingMaterial.SetProperty("u_IsBall", false); + m_gizmoPickingMaterial.SetProperty("u_IsPickable", true); /* Picking Material */ m_actorPickingMaterial.SetShader(EDITOR_CONTEXT(shaderManager)[":Shaders\\Unlit.ovfx"]); - m_actorPickingMaterial.Set("u_Diffuse", OvMaths::FVector4(1.f, 1.f, 1.f, 1.0f)); - m_actorPickingMaterial.Set("u_DiffuseMap", nullptr); + m_actorPickingMaterial.SetProperty("u_Diffuse", OvMaths::FVector4{ 1.f, 1.f, 1.f, 1.0f }); + m_actorPickingMaterial.SetProperty("u_DiffuseMap", static_cast(nullptr)); m_actorPickingMaterial.SetFrontfaceCulling(false); m_actorPickingMaterial.SetBackfaceCulling(false); } @@ -128,7 +128,7 @@ void PreparePickingMaterial(OvCore::ECS::Actor& p_actor, OvCore::Resources::Mate auto bytes = reinterpret_cast(&actorID); auto color = OvMaths::FVector4{ bytes[0] / 255.0f, bytes[1] / 255.0f, bytes[2] / 255.0f, 1.0f }; - p_material.Set("u_Diffuse", color); + p_material.SetProperty("u_Diffuse", color); } void OvEditor::Rendering::PickingRenderPass::DrawPickableModels( @@ -210,7 +210,7 @@ void OvEditor::Rendering::PickingRenderPass::DrawPickableLights( { m_renderer.Clear(false, true, false); - m_lightMaterial.Set("u_Scale", Settings::EditorSettings::LightBillboardScale * 0.1f); + m_lightMaterial.SetProperty("u_Scale", Settings::EditorSettings::LightBillboardScale * 0.1f); for (auto light : p_scene.GetFastAccessComponents().lights) { diff --git a/Sources/Overload/OvGame/src/OvGame/Core/Context.cpp b/Sources/Overload/OvGame/src/OvGame/Core/Context.cpp index 4e977690a..d7453d25a 100644 --- a/Sources/Overload/OvGame/src/OvGame/Core/Context.cpp +++ b/Sources/Overload/OvGame/src/OvGame/Core/Context.cpp @@ -7,8 +7,10 @@ #include #include -#include #include +#include + +#include #include diff --git a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h b/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h index 587720852..db7115d6b 100644 --- a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h +++ b/Sources/Overload/OvRendering/include/OvRendering/Data/Material.h @@ -9,28 +9,35 @@ #include #include #include +#include -#include "OvRendering/Resources/Shader.h" -#include "OvRendering/Resources/Texture.h" -#include "OvRendering/Data/StateMask.h" +#include +#include +#include +#include namespace OvRendering::Data { + using MaterialPropertyType = std::variant< + std::monostate, + bool, + int, + float, + OvMaths::FVector2, + OvMaths::FVector3, + OvMaths::FVector4, + OvMaths::FMatrix4, + OvRendering::HAL::TextureHandle*, // Texture handle + OvRendering::Resources::Texture* // Texture asset (serializable) + >; + /** * Represents a material property to be used as a shader uniform */ struct MaterialProperty { - std::any value; + MaterialPropertyType value; bool singleUse; - - // Conversion constructor to initialize directly from std::any - MaterialProperty& operator=(const std::any& p_value) - { - value = p_value; - singleUse = false; // Reset singleUse to default when assigning new value - return *this; - } }; /** @@ -62,26 +69,26 @@ namespace OvRendering::Data * Bind the material and send its uniform data to the GPU * @param p_emptyTexture (The texture to use if a texture uniform is null) */ - void Bind(OvRendering::Resources::Texture* p_emptyTexture = nullptr); + void Bind(OvRendering::HAL::Texture* p_emptyTexture = nullptr); /** * Unbind the material */ - void UnBind() const; + void Unbind() const; /** - * Set a shader uniform value - * @param p_key + * Sets a material property value + * @param p_name * @param p_value * @param p_singleUse (automatically consume the value after the first use) */ - template void Set(const std::string p_key, const T& p_value, bool p_singleUse = false); + void SetProperty(const std::string p_name, const MaterialPropertyType& p_value, bool p_singleUse = false); /** - * Set a shader uniform value - * @param p_key + * Gets a material property + * @param p_name */ - template const T& Get(const std::string p_key) const; + OvTools::Utils::OptRef GetProperty(const std::string p_name) const; /** * Returns the attached shader @@ -236,5 +243,3 @@ namespace OvRendering::Data int m_gpuInstances = 1; }; } - -#include "OvRendering/Data/Material.inl" \ No newline at end of file diff --git a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.inl b/Sources/Overload/OvRendering/include/OvRendering/Data/Material.inl deleted file mode 100644 index 2c3691357..000000000 --- a/Sources/Overload/OvRendering/include/OvRendering/Data/Material.inl +++ /dev/null @@ -1,50 +0,0 @@ -/** -* @project: Overload -* @author: Overload Tech. -* @licence: MIT -*/ - -#pragma once - -#include - -#include "OvRendering/Data/Material.h" - -namespace OvRendering::Data -{ - template - inline void Material::Set(const std::string p_key, const T& p_value, bool p_singleUse) - { - if (HasShader()) - { - if (m_properties.find(p_key) != m_properties.end()) - { - m_properties[p_key] = { std::any(p_value), p_singleUse }; - } - } - else - { - OVLOG_ERROR("Material Set failed: No attached shader"); - } - } - - template - inline const T& Material::Get(const std::string p_key) const - { - if (HasShader()) - { - if (m_properties.find(p_key) != m_properties.end()) - { - return std::any_cast(m_properties.at(p_key).value); - } - else - { - OVLOG_ERROR("Material Get failed: Uniform not found"); - } - } - else - { - OVLOG_ERROR("Material Get failed: No attached shader"); - } - } -} \ No newline at end of file diff --git a/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp b/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp index 353e6eb5c..97d33f6d2 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Core/ABaseRenderer.cpp @@ -137,7 +137,7 @@ void OvRendering::Core::ABaseRenderer::Blit( { const auto colorTex = p_src.GetAttachment(Settings::EFramebufferAttachment::COLOR); OVASSERT(colorTex.has_value(), "Invalid color attachment"); - p_material.Set("_InputTexture", colorTex); + p_material.SetProperty("_InputTexture", &colorTex.value()); } OvRendering::Entities::Drawable blit; @@ -204,8 +204,8 @@ void OvRendering::Core::ABaseRenderer::DrawEntity( } } - material->Bind(m_emptyTexture); + material->Bind(&m_emptyTexture->GetTexture()); m_driver.Draw(p_pso, mesh.value(), p_drawable.primitiveMode, gpuInstances); - material->UnBind(); + material->Unbind(); } } diff --git a/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp b/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp index 39f6b9b0b..4ef01b443 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Data/Material.cpp @@ -4,13 +4,57 @@ * @licence: MIT */ -#include "OvRendering/Data/Material.h" -#include "OvRendering/HAL/UniformBuffer.h" -#include "OvRendering/HAL/TextureHandle.h" -#include "OvRendering/Resources/Texture.h" +#include +#include + +#include +#include +#include +#include + #include -//TODO: Add constructor with a shader reference +namespace +{ + OvRendering::Data::MaterialPropertyType UniformToPropertyValue(const std::any& p_uniformValue) + { + using namespace OvMaths; + using namespace OvRendering; + + auto as = [&]() -> std::optional { + return + p_uniformValue.type() == typeid(T) ? + std::optional{std::any_cast(p_uniformValue)} : + std::nullopt; + }; + + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + if (auto value = as.operator()()) return *value; + + return std::monostate{}; + } + + void BindTexture( + OvRendering::HAL::ShaderProgram& p_shader, + const std::string& p_uniformName, + OvRendering::HAL::TextureHandle* p_texture, + OvRendering::HAL::TextureHandle* p_fallback, + int& p_textureSlot + ) + { + if (auto target = p_texture ? p_texture : p_fallback) + { + target->Bind(p_textureSlot); + p_shader.SetUniform(p_uniformName, p_textureSlot++); + } + } +} OvRendering::Data::Material::Material(OvRendering::Resources::Shader* p_shader) { @@ -23,8 +67,6 @@ void OvRendering::Data::Material::SetShader(OvRendering::Resources::Shader* p_sh if (m_shader) { - // TODO: Move that line to Engine Material - // OvRendering::HAL::UniformBuffer::BindBlockToShader(*m_shader, "EngineUBO"); FillUniform(); } else @@ -39,91 +81,151 @@ void OvRendering::Data::Material::FillUniform() for (const auto& uniform : m_shader->GetProgram().GetUniforms()) { - m_properties.emplace(uniform.name, MaterialProperty{ uniform.defaultValue, false }); + m_properties.emplace(uniform.name, MaterialProperty{ + .value = UniformToPropertyValue(uniform.defaultValue), + .singleUse = false + }); } } -void OvRendering::Data::Material::Bind(OvRendering::Resources::Texture* p_emptyTexture) +void OvRendering::Data::Material::Bind(OvRendering::HAL::Texture* p_emptyTexture) { - if (HasShader()) - { - using namespace OvMaths; - using namespace OvRendering::Resources; + using namespace OvMaths; + using enum OvRendering::Settings::EUniformType; + + OVASSERT(IsValid(), "Attempting to bind an invalid material."); - m_shader->GetProgram().Bind(); + auto& program = m_shader->GetProgram(); + program.Bind(); - int textureSlot = 0; + int textureSlot = 0; + + for (auto& [name, prop] : m_properties) + { + const auto uniformData = program.GetUniformInfo(name); - for (auto& [name, prop] : m_properties) + // Skip this property if the current program isn't using its associated uniform + if (!uniformData) { - auto& value = prop.value; + continue; + } + + auto& value = prop.value; + auto uniformType = uniformData->type; - const auto uniformData = m_shader->GetProgram().GetUniformInfo(name); + // Visitor to handle each variant type + auto visitor = [&](auto&& arg) { + using PropertyType = std::decay_t; - if (uniformData) + if constexpr (std::same_as) + { + if (uniformType == BOOL) + { + program.SetUniform(name, arg); + } + } + else if constexpr (std::same_as) { - switch (uniformData->type) + if (uniformType == INT) { - case OvRendering::Settings::EUniformType::BOOL: if (value.type() == typeid(bool)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::INT: if (value.type() == typeid(int)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::FLOAT: if (value.type() == typeid(float)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::FLOAT_VEC2: if (value.type() == typeid(FVector2)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::FLOAT_VEC3: if (value.type() == typeid(FVector3)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::FLOAT_VEC4: if (value.type() == typeid(FVector4)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::FLOAT_MAT4: if (value.type() == typeid(FMatrix4)) m_shader->GetProgram().SetUniform(name, std::any_cast(value)); break; - case OvRendering::Settings::EUniformType::SAMPLER_2D: + program.SetUniform(name, arg); + } + } + else if constexpr (std::same_as) + { + if (uniformType == FLOAT) { - if (value.type() == typeid(HAL::TextureHandle)) - { - auto tex = std::any_cast(value); - tex.Bind(textureSlot); - m_shader->GetProgram().SetUniform(uniformData->name, textureSlot++); - } - else if (value.type() == typeid(HAL::Texture)) - { - auto tex = std::any_cast(value); - tex.Bind(textureSlot); - m_shader->GetProgram().SetUniform(uniformData->name, textureSlot++); - } - else if (value.type() == typeid(Resources::Texture*)) - { - if (auto tex = std::any_cast(value); tex) - { - tex->GetTexture().Bind(textureSlot); - m_shader->GetProgram().SetUniform(uniformData->name, textureSlot++); - } - else if (p_emptyTexture) - { - p_emptyTexture->GetTexture().Bind(textureSlot); - m_shader->GetProgram().SetUniform(uniformData->name, textureSlot++); - } - } - else if (value.type() == typeid(OvTools::Utils::OptRef)) - { - if (const auto tex = std::any_cast>(value); tex) - { - tex->Bind(textureSlot); - m_shader->GetProgram().SetUniform(uniformData->name, textureSlot++); - } - } + program.SetUniform(name, arg); } + } + else if constexpr (std::same_as) + { + if (uniformType == FLOAT_VEC2) + { + program.SetUniform(name, arg); } - - if (prop.singleUse) + } + else if constexpr (std::same_as) + { + if (uniformType == FLOAT_VEC3) + { + program.SetUniform(name, arg); + } + } + else if constexpr (std::same_as) + { + if (uniformType == FLOAT_VEC4) { - value = uniformData->defaultValue; + program.SetUniform(name, arg); } } + else if constexpr (std::same_as) + { + if (uniformType == FLOAT_MAT4) + { + program.SetUniform(name, arg); + } + } + else if constexpr (std::same_as) + { + if (uniformType == SAMPLER_2D) + { + BindTexture(program, name, arg, p_emptyTexture, textureSlot); + } + } + else if constexpr (std::same_as) + { + if (uniformType == SAMPLER_2D) + { + BindTexture(program, name, arg ? &arg->GetTexture() : nullptr, p_emptyTexture, textureSlot); + } + } + }; + + std::visit(visitor, value); + + if (prop.singleUse) + { + value = UniformToPropertyValue(uniformData->defaultValue); } } } -void OvRendering::Data::Material::UnBind() const +void OvRendering::Data::Material::Unbind() const +{ + OVASSERT(IsValid(), "Attempting to unbind an invalid material."); + m_shader->GetProgram().Unbind(); +} + +void OvRendering::Data::Material::SetProperty(const std::string p_name, const MaterialPropertyType& p_value, bool p_singleUse) +{ + OVASSERT(IsValid(), "Attempting to SetProperty on an invalid material."); + + if (m_properties.find(p_name) != m_properties.end()) + { + const auto property = MaterialProperty{ + p_value, + p_singleUse + }; + + m_properties[p_name] = property; + } + else + { + OVLOG_ERROR("Material Set failed: Uniform not found"); + } +} + +OvTools::Utils::OptRef OvRendering::Data::Material::GetProperty(const std::string p_key) const { - if (HasShader()) + OVASSERT(IsValid(), "Attempting to GetProperty on an invalid material."); + + if (m_properties.find(p_key) != m_properties.end()) { - m_shader->GetProgram().Unbind(); + return m_properties.at(p_key); } + + return std::nullopt; } OvRendering::Resources::Shader*& OvRendering::Data::Material::GetShader() diff --git a/Sources/Overload/OvRendering/src/OvRendering/Features/DebugShapeRenderFeature.cpp b/Sources/Overload/OvRendering/src/OvRendering/Features/DebugShapeRenderFeature.cpp index 3c8ed9149..5870e2d59 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/Features/DebugShapeRenderFeature.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/Features/DebugShapeRenderFeature.cpp @@ -80,7 +80,7 @@ void OvRendering::Features::DebugShapeRenderFeature::OnBeginFrame(const Data::Fr p_frameDescriptor.camera->GetProjectionMatrix() * p_frameDescriptor.camera->GetViewMatrix(); - m_lineMaterial->Set("viewProjection", viewProjection); + m_lineMaterial->SetProperty("viewProjection", viewProjection); } void OvRendering::Features::DebugShapeRenderFeature::DrawLine( @@ -93,9 +93,9 @@ void OvRendering::Features::DebugShapeRenderFeature::DrawLine( { m_lineMaterial->SetBackfaceCulling(false); m_lineMaterial->SetFrontfaceCulling(false); - m_lineMaterial->Set("start", p_start); - m_lineMaterial->Set("end", p_end); - m_lineMaterial->Set("color", p_color); + m_lineMaterial->SetProperty("start", p_start); + m_lineMaterial->SetProperty("end", p_end); + m_lineMaterial->SetProperty("color", p_color); p_pso.rasterizationMode = Settings::ERasterizationMode::LINE; diff --git a/Sources/Overload/OvRendering/src/OvRendering/HAL/OpenGL/GLShaderProgram.cpp b/Sources/Overload/OvRendering/src/OvRendering/HAL/OpenGL/GLShaderProgram.cpp index be7ddf0c3..cfb4fd69d 100644 --- a/Sources/Overload/OvRendering/src/OvRendering/HAL/OpenGL/GLShaderProgram.cpp +++ b/Sources/Overload/OvRendering/src/OvRendering/HAL/OpenGL/GLShaderProgram.cpp @@ -23,10 +23,9 @@ namespace } template<> -OvRendering::HAL::GLShaderProgram::TShaderProgram() : m_context{ - .id = glCreateProgram() -} +OvRendering::HAL::GLShaderProgram::TShaderProgram() : m_context{ .id = glCreateProgram() } { + } template<> @@ -113,7 +112,6 @@ OvRendering::Settings::ShaderLinkingResult OvRendering::HAL::GLShaderProgram::Li }; } - #define DECLARE_GET_UNIFORM_FUNCTION(type, glType, func) \ template<> \ template<> \ @@ -194,27 +192,30 @@ void OvRendering::HAL::GLShaderProgram::QueryUniforms() if (!IsEngineUBOMember(name)) { - std::any defaultValue; - - switch (uniformType) - { - case Settings::EUniformType::BOOL: defaultValue = GetUniform(name); break; - case Settings::EUniformType::INT: defaultValue = GetUniform(name); break; - case Settings::EUniformType::FLOAT: defaultValue = GetUniform(name); break; - case Settings::EUniformType::FLOAT_VEC2: defaultValue = GetUniform(name); break; - case Settings::EUniformType::FLOAT_VEC3: defaultValue = GetUniform(name); break; - case Settings::EUniformType::FLOAT_VEC4: defaultValue = GetUniform(name); break; - case Settings::EUniformType::FLOAT_MAT4: defaultValue = GetUniform(name); break; - case Settings::EUniformType::SAMPLER_2D: defaultValue = std::make_any(nullptr); break; - } - - if (defaultValue.has_value()) + const std::any uniformValue = [&]() -> std::any { + switch (uniformType) + { + using enum Settings::EUniformType; + case BOOL: return GetUniform(name); + case INT: return GetUniform(name); + case FLOAT: return GetUniform(name); + case FLOAT_VEC2: return GetUniform(name); + case FLOAT_VEC3: return GetUniform(name); + case FLOAT_VEC4: return GetUniform(name); + case FLOAT_MAT4: return GetUniform(name); + case SAMPLER_2D: return std::make_any(nullptr); + default: return std::nullopt; + } + }(); + + // Only add the uniform if it has a value (unsupported uniform types will be ignored) + if (uniformValue.has_value()) { m_context.uniforms.push_back(Settings::UniformInfo{ .type = uniformType, .name = name, .location = m_context.GetUniformLocation(name), - .defaultValue = defaultValue + .defaultValue = uniformValue }); } }