Browse Source

Trade: add a type enum *set* to MaterialData.

Compared to previous AbstractMaterialData, which was always just a
single type, the new data can describe several different materials at
once. This is the case for example with glTF, where a material can be
metallic/roughness but also have an alternative description using
specular/glossiness.

Currently the usage is undocumented, but when everything is in place, if
a material advertises given type, it can be then cast to one of
its convenience subclasses.
pull/459/head
Vladimír Vondruš 6 years ago
parent
commit
f250e7a4c9
  1. 14
      src/Magnum/Trade/AbstractMaterialData.cpp
  2. 17
      src/Magnum/Trade/AbstractMaterialData.h
  3. 27
      src/Magnum/Trade/MaterialData.cpp
  4. 45
      src/Magnum/Trade/MaterialData.h
  5. 45
      src/Magnum/Trade/Test/MaterialDataTest.cpp
  6. 2
      src/Magnum/Trade/Trade.h

14
src/Magnum/Trade/AbstractMaterialData.cpp

@ -38,20 +38,6 @@ AbstractMaterialData::AbstractMaterialData(const MaterialType type, const Flags
AbstractMaterialData::~AbstractMaterialData() = default;
Debug& operator<<(Debug& debug, const MaterialType value) {
debug << "Trade::MaterialType" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(value) case MaterialType::value: return debug << "::" #value;
_c(Phong)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const AbstractMaterialData::Flag value) {
debug << "Trade::AbstractMaterialData::Flag" << Debug::nospace;

17
src/Magnum/Trade/AbstractMaterialData.h

@ -29,22 +29,10 @@
* @brief Class @ref Magnum::Trade::AbstractMaterialData, enum @ref Magnum::Trade::MaterialType
*/
#include <Corrade/Containers/EnumSet.h>
#include "Magnum/Magnum.h"
#include "Magnum/Trade/visibility.h"
#include "Magnum/Trade/MaterialData.h"
namespace Magnum { namespace Trade {
/**
@brief Material type
@see @ref AbstractMaterialData::type()
*/
enum class MaterialType: UnsignedByte {
Phong /**< Phong shading (see @ref PhongMaterialData) */
};
/**
@brief Material alpha mode
@ -165,9 +153,6 @@ class MAGNUM_TRADE_EXPORT AbstractMaterialData {
const void* _importerState;
};
/** @debugoperatorenum{MaterialType} */
MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, MaterialType value);
/** @debugoperatorenum{MaterialAlphaMode} */
MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, MaterialAlphaMode value);

27
src/Magnum/Trade/MaterialData.cpp

@ -27,6 +27,7 @@
#include <cstring>
#include <algorithm>
#include <Corrade/Containers/EnumSet.hpp>
#include "Magnum/Math/Vector4.h"
#include "Magnum/Math/Matrix.h"
@ -126,7 +127,7 @@ const void* MaterialAttributeData::value() const {
return _data.data + Implementation::MaterialAttributeDataSize - materialAttributeTypeSize(_data.type);
}
MaterialData::MaterialData(Containers::Array<MaterialAttributeData>&& data, const void* const importerState) noexcept: _data{std::move(data)}, _importerState{importerState} {
MaterialData::MaterialData(const MaterialTypes types, Containers::Array<MaterialAttributeData>&& data, const void* const importerState) noexcept: _data{std::move(data)}, _types{types}, _importerState{importerState} {
#ifndef CORRADE_NO_ASSERT
/* Not checking what's already done in MaterialAttributeData constructor.
Done before sorting so the index refers to the actual input index. */
@ -155,9 +156,9 @@ MaterialData::MaterialData(Containers::Array<MaterialAttributeData>&& data, cons
}
}
MaterialData::MaterialData(const std::initializer_list<MaterialAttributeData> data, const void* const importerState): MaterialData{Implementation::initializerListToArrayWithDefaultDeleter(data), importerState} {}
MaterialData::MaterialData(const MaterialTypes types, const std::initializer_list<MaterialAttributeData> data, const void* const importerState): MaterialData{types, Implementation::initializerListToArrayWithDefaultDeleter(data), importerState} {}
MaterialData::MaterialData(DataFlags, const Containers::ArrayView<const MaterialAttributeData> data, const void* const importerState) noexcept: _data{Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(data.data()), data.size(), [](MaterialAttributeData*, std::size_t){}}}, _importerState{importerState} {
MaterialData::MaterialData(const MaterialTypes types, DataFlags, const Containers::ArrayView<const MaterialAttributeData> data, const void* const importerState) noexcept: _data{Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(data.data()), data.size(), [](MaterialAttributeData*, std::size_t){}}}, _types{types}, _importerState{importerState} {
#ifndef CORRADE_NO_ASSERT
/* Not checking what's already done in MaterialAttributeData constructor */
for(std::size_t i = 0; i != _data.size(); ++i)
@ -323,4 +324,24 @@ Debug& operator<<(Debug& debug, const MaterialAttributeType value) {
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedShort(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const MaterialType value) {
debug << "Trade::MaterialType" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(value) case MaterialType::value: return debug << "::" #value;
_c(Phong)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const MaterialTypes value) {
return Containers::enumSetDebugOutput(debug, value, "Trade::MaterialTypes{}", {
MaterialType::Phong
});
}
}}

45
src/Magnum/Trade/MaterialData.h

@ -507,6 +507,32 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData {
static_assert(sizeof(Storage) == Implementation::MaterialAttributeDataSize, "something is off, huh");
};
/**
@brief Material type
@see @ref MaterialTypes, @ref MaterialData::types(),
@ref AbstractMaterialData::type()
*/
enum class MaterialType: UnsignedInt {
Phong = 1 << 0 /**< Phong shading */
};
/** @debugoperatorenum{MaterialType} */
MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, MaterialType value);
/**
@brief Material types
@m_since_latest
@see @ref MaterialData::types()
*/
typedef Containers::EnumSet<MaterialType> MaterialTypes;
CORRADE_ENUMSET_OPERATORS(MaterialTypes)
/** @debugoperatorenum{MaterialTypes} */
MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, MaterialTypes value);
/**
@brief Material data
@m_since_latest
@ -543,19 +569,23 @@ class MAGNUM_TRADE_EXPORT MaterialData {
public:
/**
* @brief Construct
* @param types Which material types are described by this
* data. Can be an empty set.
* @param data Attribute data
* @param importerState Importer-specific state
*
* The @p data gets sorted by name internally, expecting no duplicates.
*/
explicit MaterialData(Containers::Array<MaterialAttributeData>&& data, const void* importerState = nullptr) noexcept;
explicit MaterialData(MaterialTypes types, Containers::Array<MaterialAttributeData>&& data, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MaterialData(std::initializer_list<MaterialAttributeData> data, const void* importerState = nullptr);
explicit MaterialData(MaterialTypes types, std::initializer_list<MaterialAttributeData> data, const void* importerState = nullptr);
/**
* @brief Construct a non-owned material data
* @param types Which material types are described by this
* data. Can be an empty set.
* @param dataFlags Ignored. Used only for a safer distinction
* from the owning constructor.
* @param data Attribute data
@ -564,7 +594,7 @@ class MAGNUM_TRADE_EXPORT MaterialData {
* The @p data is expected to be already sorted by name, without
* duplicates.
*/
explicit MaterialData(DataFlags dataFlags, Containers::ArrayView<const MaterialAttributeData> data, const void* importerState = nullptr) noexcept;
explicit MaterialData(MaterialTypes types, DataFlags dataFlags, Containers::ArrayView<const MaterialAttributeData> data, const void* importerState = nullptr) noexcept;
~MaterialData();
@ -580,6 +610,14 @@ class MAGNUM_TRADE_EXPORT MaterialData {
/** @brief Move assignment */
MaterialData& operator=(MaterialData&&) noexcept;
/**
* @brief Material types
*
* Each type indicates that the material data can be interpreted as
* given type. For custom materials the set can also be empty.
*/
MaterialTypes types() const { return _types; }
/**
* @brief Raw attribute data
*
@ -731,6 +769,7 @@ class MAGNUM_TRADE_EXPORT MaterialData {
UnsignedInt attributeFor(Containers::StringView name) const;
Containers::Array<MaterialAttributeData> _data;
MaterialTypes _types;
const void* _importerState;
};

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

@ -97,6 +97,7 @@ class MaterialDataTest: public TestSuite::Tester {
void debugAttributeType();
void debugType();
void debugTypes();
void debugFlag();
void debugFlags();
void debugAlphaMode();
@ -186,6 +187,7 @@ MaterialDataTest::MaterialDataTest() {
&MaterialDataTest::debugAttributeType,
&MaterialDataTest::debugType,
&MaterialDataTest::debugTypes,
&MaterialDataTest::debugFlag,
&MaterialDataTest::debugFlags,
&MaterialDataTest::debugAlphaMode,
@ -422,13 +424,14 @@ void MaterialDataTest::constructAttributeWrongAccessType() {
void MaterialDataTest::construct() {
int state;
MaterialData data{{
MaterialData data{MaterialType::Phong, {
{MaterialAttribute::DoubleSided, true},
{MaterialAttribute::DiffuseTextureCoordinates, 5u},
{"highlightColor", 0x335566ff_rgbaf},
{MaterialAttribute::AmbientTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}
}, &state};
CORRADE_COMPARE(data.types(), MaterialType::Phong);
CORRADE_COMPARE(data.attributeCount(), 4);
CORRADE_COMPARE(data.data().size(), 4);
CORRADE_COMPARE(data.importerState(), &state);
@ -509,7 +512,7 @@ void MaterialDataTest::constructEmptyAttribute() {
std::ostringstream out;
Error redirectError{&out};
MaterialData{{
MaterialData{{}, {
{"DiffuseTexture"_s, 12u},
MaterialAttributeData{}
}};
@ -537,7 +540,7 @@ void MaterialDataTest::constructDuplicateAttribute() {
std::ostringstream out;
Error redirectError{&out};
MaterialData data{std::move(attributes)};
MaterialData data{{}, std::move(attributes)};
/* Because with graceful asserts it doesn't exit on error, the assertion
might get printed multiple times */
CORRADE_COMPARE(Utility::String::partition(out.str(), '\n')[0], "Trade::MaterialData: duplicate attribute DiffuseTextureCoordinates");
@ -549,7 +552,7 @@ void MaterialDataTest::constructFromImmutableSortedArray() {
{"yay this is last"_s, Vector4{0.2f, 0.6f, 0.4f, 1.0f}}
};
MaterialData data{Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(attributes), Containers::arraySize(attributes), [](MaterialAttributeData*, std::size_t) {}}};
MaterialData data{{}, Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(attributes), Containers::arraySize(attributes), [](MaterialAttributeData*, std::size_t) {}}};
CORRADE_COMPARE(data.attributeCount(), 2);
CORRADE_COMPARE(data.attributeName(0), "hello this is first");
@ -567,9 +570,10 @@ void MaterialDataTest::constructNonOwned() {
};
int state;
MaterialData data{{}, attributes, &state};
MaterialData data{MaterialType::Phong, {}, attributes, &state};
/* Expecting the same output as in construct() */
CORRADE_COMPARE(data.types(), MaterialType::Phong);
CORRADE_COMPARE(data.attributeCount(), 4);
CORRADE_COMPARE(data.data().size(), 4);
CORRADE_COMPARE(data.data().data(), attributes);
@ -598,7 +602,7 @@ void MaterialDataTest::constructNonOwnedEmptyAttribute() {
std::ostringstream out;
Error redirectError{&out};
/* nullptr to avoid attributes interpreted as importerState */
MaterialData{{}, attributes, nullptr};
MaterialData{{}, {}, attributes, nullptr};
CORRADE_COMPARE(out.str(), "Trade::MaterialData: attribute 1 doesn't specify anything\n");
}
@ -615,7 +619,7 @@ void MaterialDataTest::constructNonOwnedNotSorted() {
std::ostringstream out;
Error redirectError{&out};
/* nullptr to avoid attributes interpreted as importerState */
MaterialData{{}, attributes, nullptr};
MaterialData{{}, {}, attributes, nullptr};
CORRADE_COMPARE(out.str(), "Trade::MaterialData: DiffuseTexture has to be sorted before DiffuseTextureCoordinates if passing non-owned data\n");
}
@ -633,7 +637,7 @@ void MaterialDataTest::constructNonOwnedDuplicateAttribute() {
std::ostringstream out;
Error redirectError{&out};
/* nullptr to avoid attributes interpreted as importerState */
MaterialData{{}, attributes, nullptr};
MaterialData{{}, {}, attributes, nullptr};
CORRADE_COMPARE(out.str(), "Trade::MaterialData: duplicate attribute DiffuseTextureCoordinates\n");
}
@ -644,22 +648,24 @@ void MaterialDataTest::constructCopy() {
void MaterialDataTest::constructMove() {
int state;
MaterialData a{{
MaterialData a{MaterialType::Phong, {
{MaterialAttribute::DoubleSided, true},
{"boredomFactor", 5}
}, &state};
MaterialData b{std::move(a)};
CORRADE_COMPARE(a.attributeCount(), 0);
CORRADE_COMPARE(b.types(), MaterialType::Phong);
CORRADE_COMPARE(b.attributeCount(), 2);
CORRADE_COMPARE(b.attributeName(0), "DoubleSided");
CORRADE_COMPARE(b.importerState(), &state);
MaterialData c{{
MaterialData c{MaterialTypes{}, {
{MaterialAttribute::AlphaMask, 0.5f}
}};
c = std::move(b);
CORRADE_COMPARE(b.attributeCount(), 1);
CORRADE_COMPARE(c.types(), MaterialType::Phong);
CORRADE_COMPARE(c.attributeCount(), 2);
CORRADE_COMPARE(c.attributeName(0), "DoubleSided");
CORRADE_COMPARE(c.importerState(), &state);
@ -669,7 +675,7 @@ void MaterialDataTest::constructMove() {
}
void MaterialDataTest::accessOptional() {
MaterialData data{{
MaterialData data{{}, {
{MaterialAttribute::AlphaMask, 0.5f},
{MaterialAttribute::SpecularTexture, 3u}
}};
@ -698,7 +704,7 @@ void MaterialDataTest::accessOutOfBounds() {
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
MaterialData data{{
MaterialData data{{}, {
{MaterialAttribute::AlphaMask, 0.5f},
{MaterialAttribute::SpecularTexture, 3u}
}};
@ -721,7 +727,7 @@ void MaterialDataTest::accessInvalidAttributeName() {
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
MaterialData data{};
MaterialData data{{}, {}};
std::ostringstream out;
Error redirectError{&out};
@ -765,7 +771,7 @@ void MaterialDataTest::accessNotFound() {
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
MaterialData data{{
MaterialData data{{}, {
{"DiffuseColor", 0xff3366aa_rgbaf}
}};
@ -789,7 +795,7 @@ void MaterialDataTest::accessWrongType() {
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
MaterialData data{{
MaterialData data{{}, {
{"DiffuseColor", 0xff3366aa_rgbaf}
}};
@ -815,7 +821,7 @@ void MaterialDataTest::accessWrongType() {
}
void MaterialDataTest::release() {
MaterialData data{{
MaterialData data{{}, {
{"DiffuseColor", 0xff3366aa_rgbaf},
{MaterialAttribute::NormalTexture, 0u}
}};
@ -1103,6 +1109,13 @@ void MaterialDataTest::debugType() {
CORRADE_COMPARE(out.str(), "Trade::MaterialType::Phong Trade::MaterialType(0xbe)\n");
}
void MaterialDataTest::debugTypes() {
std::ostringstream out;
Debug{&out} << (MaterialType::Phong|MaterialType(0xe0)) << MaterialTypes{};
CORRADE_COMPARE(out.str(), "Trade::MaterialType::Phong|Trade::MaterialType(0xe0) Trade::MaterialTypes{}\n");
}
void MaterialDataTest::debugFlag() {
std::ostringstream out;

2
src/Magnum/Trade/Trade.h

@ -50,7 +50,7 @@ typedef CORRADE_DEPRECATED("use InputFileCallbackPolicy instead") InputFileCallb
enum class MaterialAttribute: UnsignedInt;
enum class MaterialAttributeType: UnsignedByte;
enum class MaterialType: UnsignedByte;
enum class MaterialType: UnsignedInt;
enum class MaterialAlphaMode: UnsignedByte;
class AbstractMaterialData;
class MaterialAttributeData;

Loading…
Cancel
Save