NazaraEngine/include/Nazara/Graphics/MaterialSettings.inl

330 lines
14 KiB
C++

// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <NazaraUtils/TypeTraits.hpp>
#include <stdexcept>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
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 void MaterialSettings::AddPropertyHandler(std::unique_ptr<PropertyHandler> propertyHandler)
{
m_propertyHandlers.emplace_back(std::move(propertyHandler));
}
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType)
{
auto& textureProperty = m_textureProperties.emplace_back();
textureProperty.name = std::move(propertyName);
textureProperty.type = propertyType;
}
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture)
{
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 void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture, const TextureSamplerInfo& defaultSamplerInfo)
{
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)
{
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 InvalidPropertyIndex;
}
inline std::size_t MaterialSettings::FindValueProperty(std::string_view propertyName) const
{
for (std::size_t i = 0; i < m_valueProperties.size(); ++i)
{
if (m_valueProperties[i].name == propertyName)
return i;
}
return InvalidPropertyIndex;
}
inline const MaterialPass* MaterialSettings::GetPass(std::size_t passIndex) const
{
if (passIndex > m_materialPasses.size() || !m_materialPasses[passIndex].has_value())
return nullptr;
return &m_materialPasses[passIndex].value();
}
inline const std::vector<std::optional<MaterialPass>>& MaterialSettings::GetPasses() const
{
return m_materialPasses;
}
inline const std::vector<std::unique_ptr<PropertyHandler>>& MaterialSettings::GetPropertyHandlers() const
{
return m_propertyHandlers;
}
inline auto MaterialSettings::GetTextureProperty(std::size_t texturePropertyIndex) const -> const TextureProperty&
{
assert(texturePropertyIndex < m_textureProperties.size());
return m_textureProperties[texturePropertyIndex];
}
inline std::size_t MaterialSettings::GetTexturePropertyCount() const
{
return m_textureProperties.size();
}
inline auto MaterialSettings::GetValueProperty(std::size_t valuePropertyIndex) const -> const ValueProperty&
{
assert(valuePropertyIndex < m_valueProperties.size());
return m_valueProperties[valuePropertyIndex];
}
inline std::size_t MaterialSettings::GetValuePropertyCount() const
{
return m_valueProperties.size();
}
template<typename T>
void MaterialSettings::AddValueProperty(std::string propertyName)
{
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));
}
}
#include <Nazara/Graphics/DebugOff.hpp>