Refactor material system (#382)
This commit is contained in:
@@ -3,186 +3,327 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/MaterialSettings.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <cassert>
|
||||
#include <Nazara/Utils/Algorithm.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline MaterialSettings::MaterialSettings() :
|
||||
MaterialSettings(Builder{})
|
||||
template<typename T> class Vector2;
|
||||
template<typename T> class Vector3;
|
||||
template<typename T> class Vector4;
|
||||
|
||||
template<typename T>
|
||||
struct TypeToMaterialPropertyType
|
||||
{
|
||||
static_assert(AlwaysFalse<T>(), "T is not a valid type for material property");
|
||||
};
|
||||
|
||||
template<> struct TypeToMaterialPropertyType<bool> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector2<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool2; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector3<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool3; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector4<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool4; };
|
||||
|
||||
template<> struct TypeToMaterialPropertyType<Color> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Color; };
|
||||
|
||||
template<> struct TypeToMaterialPropertyType<float> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector2<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float2; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector3<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float3; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector4<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float4; };
|
||||
|
||||
template<> struct TypeToMaterialPropertyType<Int32> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector2<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int2; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector3<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int3; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector4<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int4; };
|
||||
|
||||
template<> struct TypeToMaterialPropertyType<UInt32> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector2<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt2; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector3<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt3; };
|
||||
template<> struct TypeToMaterialPropertyType<Vector4<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt4; };
|
||||
|
||||
template<MaterialPropertyType P>
|
||||
struct MaterialPropertyTypeInfo
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MaterialPropertyTypeInfoPrimitive
|
||||
{
|
||||
using Type = T;
|
||||
using BufferType = T;
|
||||
using OptionType = T;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return value; }
|
||||
static Type DecodeFromOption(OptionType value) { return value; }
|
||||
static BufferType EncodeToBuffer(Type value) { return value; }
|
||||
static OptionType EncodeToOption(Type value) { return value; }
|
||||
};
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
struct MaterialPropertyTypeInfoVector;
|
||||
|
||||
template<typename T>
|
||||
struct MaterialPropertyTypeInfoVector<T, 2>
|
||||
{
|
||||
using Type = Vector2<T>;
|
||||
using BufferType = nzsl::Vector2<T>;
|
||||
using OptionType = nzsl::Vector2<T>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y() }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y }; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MaterialPropertyTypeInfoVector<T, 3>
|
||||
{
|
||||
using Type = Vector3<T>;
|
||||
using BufferType = nzsl::Vector3<T>;
|
||||
using OptionType = nzsl::Vector3<T>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z() }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z }; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MaterialPropertyTypeInfoVector<T, 4>
|
||||
{
|
||||
using Type = Vector4<T>;
|
||||
using BufferType = nzsl::Vector4<T>;
|
||||
using OptionType = nzsl::Vector4<T>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z(), value.w() }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z, value.w }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z, value.w }; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool>
|
||||
{
|
||||
using Type = bool;
|
||||
using BufferType = UInt32;
|
||||
using OptionType = bool;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return value != 0; }
|
||||
static Type DecodeFromOption(OptionType value) { return value; }
|
||||
static BufferType EncodeToBuffer(Type value) { return value; }
|
||||
static OptionType EncodeToOption(Type value) { return value; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool2>
|
||||
{
|
||||
using Type = Vector2<bool>;
|
||||
using BufferType = nzsl::Vector2u32;
|
||||
using OptionType = nzsl::Vector2<bool>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0 }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y }; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool3>
|
||||
{
|
||||
using Type = Vector3<bool>;
|
||||
using BufferType = nzsl::Vector3u32;
|
||||
using OptionType = nzsl::Vector3<bool>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0, value.z() != 0 }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z }; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool4>
|
||||
{
|
||||
using Type = Vector4<bool>;
|
||||
using BufferType = nzsl::Vector4u32;
|
||||
using OptionType = nzsl::Vector4<bool>;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0, value.z() != 0, value.w() != 0}; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z, value.w }; }
|
||||
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z, value.w }; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MaterialPropertyTypeInfo<MaterialPropertyType::Color>
|
||||
{
|
||||
using Type = Color;
|
||||
using BufferType = nzsl::Vector4f32;
|
||||
using OptionType = nzsl::Vector4f32;
|
||||
|
||||
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z(), value.w() }; }
|
||||
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
|
||||
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.r, value.g, value.b, value.a }; }
|
||||
static OptionType EncodeToOption(Type value) { return BufferType{ value.r, value.g, value.b, value.a }; }
|
||||
};
|
||||
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float> : MaterialPropertyTypeInfoPrimitive<float> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float2> : MaterialPropertyTypeInfoVector<float, 2> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float3> : MaterialPropertyTypeInfoVector<float, 3> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float4> : MaterialPropertyTypeInfoVector<float, 4> {};
|
||||
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int> : MaterialPropertyTypeInfoPrimitive<Int32> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int2> : MaterialPropertyTypeInfoVector<Int32, 2> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int3> : MaterialPropertyTypeInfoVector<Int32, 3> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int4> : MaterialPropertyTypeInfoVector<Int32, 4> {};
|
||||
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt> : MaterialPropertyTypeInfoPrimitive<UInt32> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt2> : MaterialPropertyTypeInfoVector<UInt32, 2> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt3> : MaterialPropertyTypeInfoVector<UInt32, 3> {};
|
||||
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt4> : MaterialPropertyTypeInfoVector<UInt32, 4> {};
|
||||
|
||||
|
||||
inline void MaterialSettings::AddPass(std::size_t passIndex, MaterialPass materialPass)
|
||||
{
|
||||
if (passIndex >= m_materialPasses.size())
|
||||
m_materialPasses.resize(passIndex + 1);
|
||||
|
||||
m_materialPasses[passIndex] = std::move(materialPass);
|
||||
}
|
||||
|
||||
inline MaterialSettings::MaterialSettings(Builder data) :
|
||||
m_data(std::move(data))
|
||||
inline void MaterialSettings::AddPropertyHandler(std::unique_ptr<PropertyHandler> propertyHandler)
|
||||
{
|
||||
RenderPipelineLayoutInfo info;
|
||||
|
||||
for (const Texture& textureInfo : m_data.textures)
|
||||
{
|
||||
info.bindings.push_back({
|
||||
0,
|
||||
textureInfo.bindingIndex,
|
||||
ShaderBindingType::Texture,
|
||||
textureInfo.shaderStages
|
||||
});
|
||||
}
|
||||
|
||||
for (const UniformBlock& ubo : m_data.uniformBlocks)
|
||||
{
|
||||
info.bindings.push_back({
|
||||
0,
|
||||
ubo.bindingIndex,
|
||||
ShaderBindingType::UniformBuffer,
|
||||
ubo.shaderStages
|
||||
});
|
||||
}
|
||||
|
||||
for (const SharedUniformBlock& ubo : m_data.sharedUniformBlocks)
|
||||
{
|
||||
info.bindings.push_back({
|
||||
0,
|
||||
ubo.bindingIndex,
|
||||
ShaderBindingType::UniformBuffer,
|
||||
ubo.shaderStages
|
||||
});
|
||||
}
|
||||
|
||||
m_pipelineLayout = Graphics::Instance()->GetRenderDevice()->InstantiateRenderPipelineLayout(std::move(info));
|
||||
m_propertyHandlers.emplace_back(std::move(propertyHandler));
|
||||
}
|
||||
|
||||
inline auto MaterialSettings::GetBuilderData() const -> const Builder&
|
||||
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType)
|
||||
{
|
||||
return m_data;
|
||||
auto& textureProperty = m_textureProperties.emplace_back();
|
||||
textureProperty.name = std::move(propertyName);
|
||||
textureProperty.type = propertyType;
|
||||
}
|
||||
|
||||
inline auto MaterialSettings::GetOptions() const -> const std::vector<Option>&
|
||||
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture)
|
||||
{
|
||||
return m_data.options;
|
||||
if (defaultTexture && defaultTexture->GetType() != propertyType)
|
||||
throw std::runtime_error("default texture type doesn't match property image type");
|
||||
|
||||
auto& textureProperty = m_textureProperties.emplace_back();
|
||||
textureProperty.name = std::move(propertyName);
|
||||
textureProperty.type = propertyType;
|
||||
textureProperty.defaultTexture = std::move(defaultTexture);
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetOptionIndex(const std::string_view& name) const
|
||||
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture, const TextureSamplerInfo& defaultSamplerInfo)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_data.options.size(); ++i)
|
||||
if (defaultTexture && defaultTexture->GetType() != propertyType)
|
||||
throw std::runtime_error("default texture type doesn't match property image type");
|
||||
|
||||
auto& textureProperty = m_textureProperties.emplace_back();
|
||||
textureProperty.name = std::move(propertyName);
|
||||
textureProperty.type = propertyType;
|
||||
textureProperty.defaultTexture = std::move(defaultTexture);
|
||||
textureProperty.defaultSamplerInfo = defaultSamplerInfo;
|
||||
}
|
||||
|
||||
inline void MaterialSettings::AddValueProperty(std::string propertyName, MaterialPropertyType propertyType, Value defaultValue)
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
if (m_data.options[i].name == name)
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (!std::is_same_v<T, MaterialPropertyNoValue>)
|
||||
{
|
||||
constexpr MaterialPropertyType valueType = TypeToMaterialPropertyType_v<T>;
|
||||
if (propertyType != valueType)
|
||||
throw std::runtime_error("default value type doesn't match property type");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("value properties must have a default value");
|
||||
}, defaultValue);
|
||||
|
||||
auto& valueProperty = m_valueProperties.emplace_back();
|
||||
valueProperty.name = std::move(propertyName);
|
||||
valueProperty.type = propertyType;
|
||||
valueProperty.defaultValue = std::move(defaultValue);
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::FindTextureProperty(std::string_view propertyName) const
|
||||
{
|
||||
for (std::size_t i = 0; i < m_textureProperties.size(); ++i)
|
||||
{
|
||||
if (m_textureProperties[i].name == propertyName)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
return InvalidPropertyIndex;
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetPredefinedBinding(PredefinedShaderBinding shaderBinding) const
|
||||
inline std::size_t MaterialSettings::FindValueProperty(std::string_view propertyName) const
|
||||
{
|
||||
return m_data.predefinedBindings[UnderlyingCast(shaderBinding)];
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<RenderPipelineLayout>& MaterialSettings::GetRenderPipelineLayout() const
|
||||
{
|
||||
return m_pipelineLayout;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<UberShader>& MaterialSettings::GetShader(nzsl::ShaderStageType stage) const
|
||||
{
|
||||
return m_data.shaders[UnderlyingCast(stage)];
|
||||
}
|
||||
|
||||
inline const std::vector<std::shared_ptr<UberShader>>& MaterialSettings::GetShaders() const
|
||||
{
|
||||
return m_data.shaders;
|
||||
}
|
||||
|
||||
inline auto MaterialSettings::GetSharedUniformBlocks() const -> const std::vector<SharedUniformBlock>&
|
||||
{
|
||||
return m_data.sharedUniformBlocks;
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetSharedUniformBlockIndex(const std::string_view& name) const
|
||||
{
|
||||
for (std::size_t i = 0; i < m_data.sharedUniformBlocks.size(); ++i)
|
||||
for (std::size_t i = 0; i < m_valueProperties.size(); ++i)
|
||||
{
|
||||
if (m_data.sharedUniformBlocks[i].name == name)
|
||||
if (m_valueProperties[i].name == propertyName)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
return InvalidPropertyIndex;
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
|
||||
inline const MaterialPass* MaterialSettings::GetPass(std::size_t passIndex) const
|
||||
{
|
||||
assert(uniformBlockIndex < m_data.sharedUniformBlocks.size());
|
||||
if (passIndex > m_materialPasses.size() || !m_materialPasses[passIndex].has_value())
|
||||
return nullptr;
|
||||
|
||||
const std::vector<UniformVariable>& variables = m_data.sharedUniformBlocks[uniformBlockIndex].uniforms;
|
||||
for (std::size_t i = 0; i < variables.size(); ++i)
|
||||
{
|
||||
if (variables[i].name == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
return &m_materialPasses[passIndex].value();
|
||||
}
|
||||
|
||||
inline auto MaterialSettings::GetTextures() const -> const std::vector<Texture>&
|
||||
inline const std::vector<std::optional<MaterialPass>>& MaterialSettings::GetPasses() const
|
||||
{
|
||||
return m_data.textures;
|
||||
return m_materialPasses;
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetTextureIndex(const std::string_view& name) const
|
||||
inline const std::vector<std::unique_ptr<PropertyHandler>>& MaterialSettings::GetPropertyHandlers() const
|
||||
{
|
||||
for (std::size_t i = 0; i < m_data.textures.size(); ++i)
|
||||
{
|
||||
if (m_data.textures[i].name == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
return m_propertyHandlers;
|
||||
}
|
||||
|
||||
inline auto MaterialSettings::GetUniformBlocks() const -> const std::vector<UniformBlock>&
|
||||
inline auto MaterialSettings::GetTextureProperty(std::size_t texturePropertyIndex) const -> const TextureProperty&
|
||||
{
|
||||
return m_data.uniformBlocks;
|
||||
assert(texturePropertyIndex < m_textureProperties.size());
|
||||
return m_textureProperties[texturePropertyIndex];
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetUniformBlockIndex(const std::string_view& name) const
|
||||
inline std::size_t MaterialSettings::GetTexturePropertyCount() const
|
||||
{
|
||||
for (std::size_t i = 0; i < m_data.uniformBlocks.size(); ++i)
|
||||
{
|
||||
if (m_data.uniformBlocks[i].name == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
return m_textureProperties.size();
|
||||
}
|
||||
|
||||
inline std::size_t MaterialSettings::GetUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
|
||||
inline auto MaterialSettings::GetValueProperty(std::size_t valuePropertyIndex) const -> const ValueProperty&
|
||||
{
|
||||
assert(uniformBlockIndex < m_data.uniformBlocks.size());
|
||||
|
||||
const std::vector<UniformVariable>& variables = m_data.uniformBlocks[uniformBlockIndex].uniforms;
|
||||
for (std::size_t i = 0; i < variables.size(); ++i)
|
||||
{
|
||||
if (variables[i].name == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return InvalidIndex;
|
||||
assert(valuePropertyIndex < m_valueProperties.size());
|
||||
return m_valueProperties[valuePropertyIndex];
|
||||
}
|
||||
|
||||
inline void MaterialSettings::BuildOption(std::vector<Option>& options, std::string optionName, const std::string& shaderOptionName)
|
||||
inline std::size_t MaterialSettings::GetValuePropertyCount() const
|
||||
{
|
||||
UInt32 optionHash = CRC32(shaderOptionName);
|
||||
|
||||
options.push_back({
|
||||
std::move(optionName),
|
||||
optionHash
|
||||
});
|
||||
return m_valueProperties.size();
|
||||
}
|
||||
|
||||
inline MaterialSettings::Builder::Builder()
|
||||
template<typename T>
|
||||
void MaterialSettings::AddValueProperty(std::string propertyName)
|
||||
{
|
||||
predefinedBindings.fill(InvalidIndex);
|
||||
return AddValueProperty(std::move(propertyName), TypeToMaterialPropertyType_v<T>);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void MaterialSettings::AddValueProperty(std::string propertyName, U&& defaultValue)
|
||||
{
|
||||
constexpr std::size_t TypeIndex = TypeListFind<MaterialPropertyTypeList, T>;
|
||||
|
||||
auto& valueProperty = m_valueProperties.emplace_back();
|
||||
valueProperty.name = std::move(propertyName);
|
||||
valueProperty.type = TypeToMaterialPropertyType_v<T>;
|
||||
valueProperty.defaultValue.emplace<TypeIndex>(std::forward<U>(defaultValue));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user