Browse Source

Trade: allow storing 64bit ints and pointers in MaterialData.

Suited mainly for custom app-specific material properties (e.g., actual
texture pointers and handles), not really planning on using this in
Magnum itself.
pull/459/head
Vladimír Vondruš 6 years ago
parent
commit
c59fa42e7b
  1. 10
      src/Magnum/Trade/MaterialData.cpp
  2. 60
      src/Magnum/Trade/MaterialData.h
  3. 122
      src/Magnum/Trade/Test/MaterialDataTest.cpp

10
src/Magnum/Trade/MaterialData.cpp

@ -68,6 +68,8 @@ std::size_t materialAttributeTypeSize(const MaterialAttributeType type) {
case MaterialAttributeType::Int:
return 4;
case MaterialAttributeType::UnsignedLong:
case MaterialAttributeType::Long:
case MaterialAttributeType::Vector2:
case MaterialAttributeType::Vector2ui:
case MaterialAttributeType::Vector2i:
@ -98,6 +100,10 @@ std::size_t materialAttributeTypeSize(const MaterialAttributeType type) {
case MaterialAttributeType::Matrix3x4:
case MaterialAttributeType::Matrix4x3:
return 48;
case MaterialAttributeType::Pointer:
case MaterialAttributeType::MutablePointer:
return sizeof(void*);
}
CORRADE_ASSERT_UNREACHABLE("Trade::materialAttributeTypeSize(): invalid type" << type, {});
@ -328,6 +334,8 @@ Debug& operator<<(Debug& debug, const MaterialAttributeType value) {
_c(Rad)
_c(UnsignedInt)
_c(Int)
_c(UnsignedLong)
_c(Long)
_c(Vector2)
_c(Vector2ui)
_c(Vector2i)
@ -345,6 +353,8 @@ Debug& operator<<(Debug& debug, const MaterialAttributeType value) {
_c(Matrix3x4)
_c(Matrix4x2)
_c(Matrix4x3)
_c(Pointer)
_c(MutablePointer)
#undef _c
/* LCOV_EXCL_STOP */
}

60
src/Magnum/Trade/MaterialData.h

@ -291,6 +291,8 @@ enum class MaterialAttributeType: UnsignedByte {
Rad, /**< @ref Magnum::Rad "Rad" */
UnsignedInt, /**< @ref Magnum::UnsignedInt "UnsignedInt" */
Int, /**< @ref Magnum::Int "Int" */
UnsignedLong, /**< @ref Magnum::UnsignedLong "UnsignedLong" */
Long, /**< @ref Magnum::Long "Long" */
Vector2, /**< @ref Magnum::Vector2 "Vector2" */
Vector2ui, /**< @ref Magnum::Vector2ui "Vector2ui" */
@ -316,6 +318,20 @@ enum class MaterialAttributeType: UnsignedByte {
Matrix4x3, /**< @ref Magnum::Matrix4x3 "Matrix4x3" */
/* Matrix4x4 not present */
/**
* @cpp const void* @ce, type is not preserved. For convenience it's
* possible to retrieve the value by calling @cpp attribute<const T>() @ce
* with an arbitrary `T` but the user has to ensure the type is correct.
*/
Pointer,
/**
* @cpp void* @ce, type is not preserved. For convenience it's possible to
* retrieve the value by calling @cpp attribute<T>() @ce with an arbitrary
* `T` but the user has to ensure the type is correct.
*/
MutablePointer,
};
/**
@ -427,7 +443,10 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData {
/**
* @brief Type-erased attribute value
*
* Cast the pointer to a concrete type based on @ref type().
* Cast the pointer to a concrete type based on @ref type(). Note that
* in case of a @ref MaterialAttributeType::Pointer or a
* @ref MaterialAttributeType::MutablePointer, returns a
* *pointer to a pointer*, not the pointer value itself.
*/
const void* value() const;
@ -476,6 +495,13 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData {
UnsignedInt u;
Int i;
};
union ErasedLongScalar {
constexpr explicit ErasedLongScalar(UnsignedLong value): u{value} {}
constexpr explicit ErasedLongScalar(Long value): i{value} {}
UnsignedLong u;
Long i;
};
template<std::size_t size> union ErasedVector {
constexpr explicit ErasedVector(const Math::Vector<size, Float>& value): f{value} {}
constexpr explicit ErasedVector(const Math::Vector<size, UnsignedInt>& value): u{value} {}
@ -504,8 +530,10 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData {
constexpr explicit Storage() noexcept: data{} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 1, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _1{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 4, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _4{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 8, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _8{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 4 && !std::is_pointer<T>::value, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _4{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 8 && !Math::IsVector<T>::value && !std::is_pointer<T>::value, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _8{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 8 && Math::IsVector<T>::value && !std::is_pointer<T>::value, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _8v{type, name, value} {}
constexpr explicit Storage(MaterialAttributeType type, Containers::StringView name, const void* value) noexcept: p{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 12, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _12{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 16 && Math::IsVector<T>::value, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _16{type, name, value} {}
template<class T> constexpr explicit Storage(typename std::enable_if<sizeof(T) == 16 && !Math::IsVector<T>::value, MaterialAttributeType>::type type, Containers::StringView name, const T& value) noexcept: _16m{type, name, value} {}
@ -517,8 +545,10 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData {
MaterialAttributeType type;
char data[Implementation::MaterialAttributeDataSize];
Data<bool> _1;
Data<const void*> p;
Data<ErasedScalar> _4;
Data<ErasedVector<2>> _8;
Data<ErasedLongScalar> _8;
Data<ErasedVector<2>> _8v;
Data<ErasedVector<3>> _12;
Data<ErasedVector<4>> _16;
Data<Math::RectangularMatrix<2, 2, Float>> _16m;
@ -776,7 +806,10 @@ class MAGNUM_TRADE_EXPORT MaterialData {
* @brief Type-erased attribute value
*
* The @p id is expected to be smaller than @ref attributeCount() const.
* Cast the pointer to a concrete type based on @ref type().
* Cast the pointer to a concrete type based on @ref type(). Note that
* in case of a @ref MaterialAttributeType::Pointer or a
* @ref MaterialAttributeType::MutablePointer, returns a
* *pointer to a pointer*, not the pointer value itself.
*/
const void* attribute(UnsignedInt id) const;
@ -784,7 +817,10 @@ class MAGNUM_TRADE_EXPORT MaterialData {
* @brief Type-erased value of a named attribute
*
* The @p name is expected to exist. Cast the pointer to a concrete
* type based on @ref attributeType().
* type based on @ref attributeType(). Note that
* in case of a @ref MaterialAttributeType::Pointer or a
* @ref MaterialAttributeType::MutablePointer, returns a
* *pointer to a pointer*, not the pointer value itself.
* @see @ref hasAttribute(), @ref tryAttribute(), @ref attributeOr()
*/
const void* attribute(Containers::StringView name) const;
@ -950,6 +986,16 @@ namespace Implementation {
return MaterialAttributeType::Bool;
}
};
template<class T> struct MaterialAttributeTypeFor<const T*> {
constexpr static MaterialAttributeType type() {
return MaterialAttributeType::Pointer;
}
};
template<class T> struct MaterialAttributeTypeFor<T*> {
constexpr static MaterialAttributeType type() {
return MaterialAttributeType::MutablePointer;
}
};
#ifndef DOXYGEN_GENERATING_OUTPUT
#define _c(type_) template<> struct MaterialAttributeTypeFor<type_> { \
constexpr static MaterialAttributeType type() { \
@ -961,6 +1007,8 @@ namespace Implementation {
_c(Rad)
_c(UnsignedInt)
_c(Int)
_c(UnsignedLong)
_c(Long)
_c(Vector2)
_c(Vector2ui)
_c(Vector2i)

122
src/Magnum/Trade/Test/MaterialDataTest.cpp

@ -55,11 +55,15 @@ class MaterialDataTest: public TestSuite::Tester {
template<class T> void constructAttributeStringConstexpr();
void constructAttributePointer();
void constructAttributeMutablePointer();
void constructAttributeInvalidName();
void constructAttributeWrongTypeForName();
void constructAttributeInvalidType();
void constructAttributeTooLarge();
void constructAttributeWrongAccessType();
void constructAttributeWrongAccessPointerType();
void construct();
void constructEmptyAttribute();
@ -75,11 +79,13 @@ class MaterialDataTest: public TestSuite::Tester {
void constructMove();
void access();
void accessPointer();
void accessOptional();
void accessOutOfBounds();
void accessInvalidAttributeName();
void accessNotFound();
void accessWrongType();
void accessWrongPointerType();
void release();
@ -134,6 +140,8 @@ MaterialDataTest::MaterialDataTest() {
&MaterialDataTest::constructAttributeStringConstexpr<Rad>,
&MaterialDataTest::constructAttributeStringConstexpr<UnsignedInt>,
&MaterialDataTest::constructAttributeStringConstexpr<Int>,
&MaterialDataTest::constructAttributeStringConstexpr<UnsignedLong>,
&MaterialDataTest::constructAttributeStringConstexpr<Long>,
&MaterialDataTest::constructAttributeStringConstexpr<Vector2>,
&MaterialDataTest::constructAttributeStringConstexpr<Vector2ui>,
&MaterialDataTest::constructAttributeStringConstexpr<Vector2i>,
@ -152,11 +160,15 @@ MaterialDataTest::MaterialDataTest() {
&MaterialDataTest::constructAttributeStringConstexpr<Matrix4x2>,
&MaterialDataTest::constructAttributeStringConstexpr<Matrix4x3>,
&MaterialDataTest::constructAttributePointer,
&MaterialDataTest::constructAttributeMutablePointer,
&MaterialDataTest::constructAttributeInvalidName,
&MaterialDataTest::constructAttributeWrongTypeForName,
&MaterialDataTest::constructAttributeInvalidType,
&MaterialDataTest::constructAttributeTooLarge,
&MaterialDataTest::constructAttributeWrongAccessType,
&MaterialDataTest::constructAttributeWrongAccessPointerType,
&MaterialDataTest::construct,
&MaterialDataTest::constructEmptyAttribute});
@ -175,11 +187,13 @@ MaterialDataTest::MaterialDataTest() {
&MaterialDataTest::constructMove,
&MaterialDataTest::access,
&MaterialDataTest::accessPointer,
&MaterialDataTest::accessOptional,
&MaterialDataTest::accessOutOfBounds,
&MaterialDataTest::accessInvalidAttributeName,
&MaterialDataTest::accessNotFound,
&MaterialDataTest::accessWrongType,
&MaterialDataTest::accessWrongPointerType,
&MaterialDataTest::release,
@ -377,6 +391,54 @@ template<class T> void MaterialDataTest::constructAttributeStringConstexpr() {
CORRADE_COMPARE(attribute.value<T>(), T(15));
}
constexpr Int SomeData = 3;
void MaterialDataTest::constructAttributePointer() {
MaterialAttributeData attribute{"pointer!", &SomeData};
CORRADE_COMPARE(attribute.name(), "pointer!");
CORRADE_COMPARE(attribute.type(), MaterialAttributeType::Pointer);
CORRADE_COMPARE(*static_cast<const Int* const*>(attribute.value()), &SomeData);
CORRADE_COMPARE(attribute.value<const Int*>(), &SomeData);
/* Any type works */
CORRADE_COMPARE(attribute.value<const void*>(), &SomeData);
constexpr MaterialAttributeData cattribute{"pointer!"_s, &SomeData};
CORRADE_COMPARE(cattribute.name(), "pointer!");
CORRADE_COMPARE(cattribute.type(), MaterialAttributeType::Pointer);
CORRADE_COMPARE(*static_cast<const Int* const*>(cattribute.value()), &SomeData);
CORRADE_COMPARE(cattribute.value<const Int*>(), &SomeData);
/* Type-erased variant */
const Int* pointer = &SomeData;
MaterialAttributeData typeErased{"pointer!", MaterialAttributeType::Pointer, &pointer};
CORRADE_COMPARE(typeErased.name(), "pointer!");
CORRADE_COMPARE(typeErased.type(), MaterialAttributeType::Pointer);
CORRADE_COMPARE(typeErased.value<const Int*>(), &SomeData);
/* Any type works */
CORRADE_COMPARE(typeErased.value<const void*>(), &SomeData);
}
void MaterialDataTest::constructAttributeMutablePointer() {
Float data = 85.1f;
MaterialAttributeData attribute{"pointer!", &data};
CORRADE_COMPARE(attribute.name(), "pointer!");
CORRADE_COMPARE(attribute.type(), MaterialAttributeType::MutablePointer);
CORRADE_COMPARE(*static_cast<Float* const*>(attribute.value()), &data);
CORRADE_COMPARE(attribute.value<Float*>(), &data);
/* Any type works */
CORRADE_COMPARE(attribute.value<void*>(), &data);
/* Type-erased variant */
Float* pointer = &data;
MaterialAttributeData typeErased{"pointer!", MaterialAttributeType::MutablePointer, &pointer};
CORRADE_COMPARE(typeErased.name(), "pointer!");
CORRADE_COMPARE(typeErased.type(), MaterialAttributeType::MutablePointer);
CORRADE_COMPARE(typeErased.value<Float*>(), &data);
/* Any type works */
CORRADE_COMPARE(typeErased.value<void*>(), &data);
}
void MaterialDataTest::constructAttributeInvalidName() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
@ -444,6 +506,23 @@ void MaterialDataTest::constructAttributeWrongAccessType() {
CORRADE_COMPARE(out.str(), "Trade::MaterialAttributeData::value(): improper type requested for thing3 of Trade::MaterialAttributeType::Matrix4x3\n");
}
void MaterialDataTest::constructAttributeWrongAccessPointerType() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
Int a = 3;
const Float b = 57.0f;
std::ostringstream out;
Error redirectError{&out};
MaterialAttributeData{"thing3", &a}.value<Int>();
MaterialAttributeData{"boom", &b}.value<Float>();
CORRADE_COMPARE(out.str(),
"Trade::MaterialAttributeData::value(): improper type requested for thing3 of Trade::MaterialAttributeType::MutablePointer\n"
"Trade::MaterialAttributeData::value(): improper type requested for boom of Trade::MaterialAttributeType::Pointer\n");
}
void MaterialDataTest::construct() {
int state;
MaterialData data{MaterialType::Phong, {
@ -722,6 +801,23 @@ void MaterialDataTest::access() {
CORRADE_COMPARE(c.alphaMask(), 0.5f);
}
void MaterialDataTest::accessPointer() {
const Float a = 3.0f;
Long b = -4;
MaterialData data{{}, {
{"pointer", &a},
{"mutable", &b}
}};
CORRADE_COMPARE(data.attributeType("pointer"), MaterialAttributeType::Pointer);
CORRADE_COMPARE(data.attributeType("mutable"), MaterialAttributeType::MutablePointer);
CORRADE_COMPARE(*static_cast<const Float* const*>(data.attribute("pointer")), &a);
CORRADE_COMPARE(*static_cast<Long* const*>(data.attribute("mutable")), &b);
CORRADE_COMPARE(data.attribute<const Float*>("pointer"), &a);
CORRADE_COMPARE(data.attribute<Long*>("mutable"), &b);
}
void MaterialDataTest::accessOptional() {
MaterialData data{{}, {
{MaterialAttribute::AlphaMask, 0.5f},
@ -868,6 +964,32 @@ void MaterialDataTest::accessWrongType() {
"Trade::MaterialData::attribute(): improper type requested for DiffuseColor of Trade::MaterialAttributeType::Vector4\n");
}
void MaterialDataTest::accessWrongPointerType() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
Int a = 3;
const Double b = 57.0;
MaterialData data{{}, {
{"mutablePointer", &a},
{"pointer", &b}
}};
/* These are fine (type is not checked) */
data.attribute<Byte*>("mutablePointer");
data.attribute<const Float*>("pointer");
std::ostringstream out;
Error redirectError{&out};
data.attribute<const Int*>("mutablePointer");
data.attribute<Double*>("pointer");
CORRADE_COMPARE(out.str(),
"Trade::MaterialData::attribute(): improper type requested for mutablePointer of Trade::MaterialAttributeType::MutablePointer\n"
"Trade::MaterialData::attribute(): improper type requested for pointer of Trade::MaterialAttributeType::Pointer\n");
}
void MaterialDataTest::release() {
MaterialData data{{}, {
{"DiffuseColor", 0xff3366aa_rgbaf},

Loading…
Cancel
Save