From 106de5fa154541227e05f3144b52b0f7e5e397bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 9 Aug 2020 01:03:19 +0200 Subject: [PATCH] Trade: add named material layer support and a first layer. This is a bit huge because of all the new overloads that take a MaterialLayer instead of a string, but all that is just boring boilerplate. Additionally this: * exposes glTF clear coat parameters (which, interestingly enough, reuse existing attributes and don't introduce any new) * provides a convenience wrapper in PbrClearCoatMaterialData * and a convenience base for material layer wrappers that redirect all APIs with implicit layer argument to desired layer instead of the base material --- doc/changelog.dox | 8 +- src/Magnum/Trade/CMakeLists.txt | 3 + .../materialLayerProperties.hpp | 29 ++ src/Magnum/Trade/MaterialData.cpp | 159 +++++- src/Magnum/Trade/MaterialData.h | 133 ++++- src/Magnum/Trade/MaterialLayerData.h | 255 ++++++++++ src/Magnum/Trade/PbrClearCoatMaterialData.cpp | 110 +++++ src/Magnum/Trade/PbrClearCoatMaterialData.h | 193 ++++++++ src/Magnum/Trade/Test/MaterialDataTest.cpp | 457 +++++++++++++++++- src/Magnum/Trade/Trade.h | 2 + 10 files changed, 1341 insertions(+), 8 deletions(-) create mode 100644 src/Magnum/Trade/Implementation/materialLayerProperties.hpp create mode 100644 src/Magnum/Trade/MaterialLayerData.h create mode 100644 src/Magnum/Trade/PbrClearCoatMaterialData.cpp create mode 100644 src/Magnum/Trade/PbrClearCoatMaterialData.h diff --git a/doc/changelog.dox b/doc/changelog.dox index 412efeb4f..5ebad732e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -77,10 +77,10 @@ See also: - A new, redesigned @ref Trade::MaterialData class allowing to store custom material attributes as well as more material types together in a single instance; plus new @ref Trade::FlatMaterialData, - @ref Trade::PbrMetallicRoughnessMaterialData and - @ref Trade::PbrSpecularGlossinessMaterialData convenience accessor APIs - similar to @ref Trade::PhongMaterialData. See - [mosra/magnum#459](https://github.com/mosra/magnum/pull/459). + @ref Trade::PbrMetallicRoughnessMaterialData, + @ref Trade::PbrSpecularGlossinessMaterialData and + @ref Trade::PbrClearCoatMaterialData convenience accessor APIs similar to + @ref Trade::PhongMaterialData. See [mosra/magnum#459](https://github.com/mosra/magnum/pull/459). - Added @ref Trade::PhongMaterialData::hasSpecularTexture(), @ref Trade::PhongMaterialData::specularTextureSwizzle() and @ref Trade::PhongMaterialData::normalTextureSwizzle() to make new features diff --git a/src/Magnum/Trade/CMakeLists.txt b/src/Magnum/Trade/CMakeLists.txt index 699bdaad8..d15b58eb8 100644 --- a/src/Magnum/Trade/CMakeLists.txt +++ b/src/Magnum/Trade/CMakeLists.txt @@ -46,6 +46,7 @@ set(MagnumTrade_GracefulAssert_SRCS MeshData.cpp ObjectData2D.cpp ObjectData3D.cpp + PbrClearCoatMaterialData.cpp PbrMetallicRoughnessMaterialData.cpp PbrSpecularGlossinessMaterialData.cpp PhongMaterialData.cpp) @@ -62,11 +63,13 @@ set(MagnumTrade_HEADERS ImageData.h LightData.h MaterialData.h + MaterialLayerData.h MeshData.h MeshObjectData2D.h MeshObjectData3D.h ObjectData2D.h ObjectData3D.h + PbrClearCoatMaterialData.h PbrMetallicRoughnessMaterialData.h PbrSpecularGlossinessMaterialData.h PhongMaterialData.h diff --git a/src/Magnum/Trade/Implementation/materialLayerProperties.hpp b/src/Magnum/Trade/Implementation/materialLayerProperties.hpp new file mode 100644 index 000000000..2541a090e --- /dev/null +++ b/src/Magnum/Trade/Implementation/materialLayerProperties.hpp @@ -0,0 +1,29 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* See Magnum/Trade/MaterialData.cpp and Magnum/Trade/Test/MaterialDataTest.cpp */ +#ifdef _c +_c(ClearCoat) +#endif diff --git a/src/Magnum/Trade/MaterialData.cpp b/src/Magnum/Trade/MaterialData.cpp index fe7e21ea9..88f08df4f 100644 --- a/src/Magnum/Trade/MaterialData.cpp +++ b/src/Magnum/Trade/MaterialData.cpp @@ -42,6 +42,12 @@ namespace { using namespace Containers::Literals; #ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */ +constexpr Containers::StringView LayerMap[]{ + #define _c(name) #name ## _s, + #include "Magnum/Trade/Implementation/materialLayerProperties.hpp" + #undef _c +}; + constexpr struct { Containers::StringView name; MaterialAttributeType type; @@ -168,6 +174,12 @@ MaterialAttributeData::MaterialAttributeData(const MaterialAttribute name, const } } +/* Interestingly enough, [[ is an invalid syntax in C++11? */ +MaterialAttributeData::MaterialAttributeData(const MaterialLayer layerName) noexcept: MaterialAttributeData{MaterialAttribute::LayerName, LayerMap[([](const MaterialLayer layerName){ + CORRADE_ASSERT(UnsignedInt(layerName) - 1 < Containers::arraySize(LayerMap), "Trade::MaterialAttributeData: invalid name" << layerName, UnsignedInt{}); + return UnsignedInt(layerName) - 1; +}(layerName))]} {} + const void* MaterialAttributeData::value() const { if(_data.type == MaterialAttributeType::String) return _data.s.nameValue + Implementation::MaterialAttributeDataSize - _data.s.size - 3; @@ -263,6 +275,14 @@ MaterialData::~MaterialData() = default; MaterialData& MaterialData::operator=(MaterialData&&) noexcept = default; +Containers::StringView MaterialData::layerString(const MaterialLayer name) { + #ifndef CORRADE_NO_ASSERT + if(UnsignedInt(name) - 1 >= Containers::arraySize(LayerMap)) + return nullptr; + #endif + return LayerMap[UnsignedInt(name) - 1]; +} + Containers::StringView MaterialData::attributeString(const MaterialAttribute name) { #ifndef CORRADE_NO_ASSERT if(UnsignedInt(name) - 1 >= Containers::arraySize(AttributeMap)) @@ -285,6 +305,12 @@ bool MaterialData::hasLayer(const Containers::StringView layer) const { return layerFor(layer) != ~UnsignedInt{}; } +bool MaterialData::hasLayer(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::hasLayer(): invalid name" << layer, {}); + return hasLayer(string); +} + UnsignedInt MaterialData::layerId(const Containers::StringView layer) const { const UnsignedInt id = layerFor(layer); CORRADE_ASSERT(id != ~UnsignedInt{}, @@ -292,6 +318,12 @@ UnsignedInt MaterialData::layerId(const Containers::StringView layer) const { return id; } +UnsignedInt MaterialData::layerId(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerId(): invalid name" << layer, {}); + return layerId(string); +} + Containers::StringView MaterialData::layerName(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::layerName(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -314,6 +346,12 @@ Float MaterialData::layerFactor(const Containers::StringView layer) const { return layerFactor(layerId); } +Float MaterialData::layerFactor(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerFactor(): invalid name" << layer, {}); + return layerFactor(string); +} + UnsignedInt MaterialData::layerFactorTexture(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::layerFactorTexture(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -329,6 +367,12 @@ UnsignedInt MaterialData::layerFactorTexture(const Containers::StringView layer) return attribute(layer, MaterialAttribute::LayerFactorTexture); } +UnsignedInt MaterialData::layerFactorTexture(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerFactorTexture(): invalid name" << layer, {}); + return layerFactorTexture(string); +} + MaterialTextureSwizzle MaterialData::layerFactorTextureSwizzle(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::layerFactorTextureSwizzle(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -348,6 +392,12 @@ MaterialTextureSwizzle MaterialData::layerFactorTextureSwizzle(const Containers: return attributeOr(layer, MaterialAttribute::LayerFactorTextureSwizzle, MaterialTextureSwizzle::R); } +MaterialTextureSwizzle MaterialData::layerFactorTextureSwizzle(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerFactorTextureSwizzle(): invalid name" << layer, {}); + return layerFactorTextureSwizzle(string); +} + Matrix3 MaterialData::layerFactorTextureMatrix(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::layerFactorTextureMatrix(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -375,6 +425,12 @@ Matrix3 MaterialData::layerFactorTextureMatrix(const Containers::StringView laye return attributeOr(0, MaterialAttribute::TextureMatrix, Matrix3{}); } +Matrix3 MaterialData::layerFactorTextureMatrix(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerFactorTextureMatrix(): invalid name" << layer, {}); + return layerFactorTextureMatrix(string); +} + UnsignedInt MaterialData::layerFactorTextureCoordinates(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::layerFactorTextureCoordinates(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -402,6 +458,12 @@ UnsignedInt MaterialData::layerFactorTextureCoordinates(const Containers::String return attributeOr(0, MaterialAttribute::TextureCoordinates, 0u); } +UnsignedInt MaterialData::layerFactorTextureCoordinates(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::layerFactorTextureCoordinates(): invalid name" << layer, {}); + return layerFactorTextureCoordinates(string); +} + UnsignedInt MaterialData::attributeCount(const UnsignedInt layer) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attributeCount(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -417,6 +479,12 @@ UnsignedInt MaterialData::attributeCount(const Containers::StringView layer) con return attributeCount(layerId); } +UnsignedInt MaterialData::attributeCount(const MaterialLayer layer) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeCount(): invalid name" << layer, {}); + return attributeCount(string); +} + UnsignedInt MaterialData::attributeFor(const UnsignedInt layer, const Containers::StringView name) const { const MaterialAttributeData* begin = _data.begin() + (layer && _layerOffsets ? _layerOffsets[layer - 1] : 0); @@ -454,6 +522,18 @@ bool MaterialData::hasAttribute(const Containers::StringView layer, const Materi return hasAttribute(layer, string); } +bool MaterialData::hasAttribute(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::hasAttribute(): invalid name" << layer, {}); + return hasAttribute(string, name); +} + +bool MaterialData::hasAttribute(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::hasAttribute(): invalid name" << layer, {}); + return hasAttribute(string, name); +} + UnsignedInt MaterialData::attributeId(const UnsignedInt layer, const Containers::StringView name) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attributeId(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -485,6 +565,18 @@ UnsignedInt MaterialData::attributeId(const Containers::StringView layer, const return attributeId(layer, string); } +UnsignedInt MaterialData::attributeId(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeId(): invalid name" << layer, {}); + return attributeId(string, name); +} + +UnsignedInt MaterialData::attributeId(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeId(): invalid name" << layer, {}); + return attributeId(string, name); +} + Containers::StringView MaterialData::attributeName(const UnsignedInt layer, const UnsignedInt id) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attributeName(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -502,6 +594,12 @@ Containers::StringView MaterialData::attributeName(const Containers::StringView return _data[layerOffset(layerId) + id]._data.data + 1; } +Containers::StringView MaterialData::attributeName(const MaterialLayer layer, const UnsignedInt id) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeName(): invalid name" << layer, {}); + return attributeName(string, id); +} + MaterialAttributeType MaterialData::attributeType(const UnsignedInt layer, const UnsignedInt id) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attributeType(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -550,6 +648,24 @@ MaterialAttributeType MaterialData::attributeType(const Containers::StringView l return attributeType(layer, string); } +MaterialAttributeType MaterialData::attributeType(const MaterialLayer layer, const UnsignedInt id) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeType(): invalid name" << layer, {}); + return attributeType(string, id); +} + +MaterialAttributeType MaterialData::attributeType(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeType(): invalid name" << layer, {}); + return attributeType(string, name); +} + +MaterialAttributeType MaterialData::attributeType(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeType(): invalid name" << layer, {}); + return attributeType(string, name); +} + const void* MaterialData::attribute(const UnsignedInt layer, const UnsignedInt id) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attribute(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -598,6 +714,24 @@ const void* MaterialData::attribute(const Containers::StringView layer, const Ma return attribute(layer, string); } +const void* MaterialData::attribute(const MaterialLayer layer, const UnsignedInt id) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, id); +} + +const void* MaterialData::attribute(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, name); +} + +const void* MaterialData::attribute(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, name); +} + #ifndef DOXYGEN_GENERATING_OUTPUT /* On Windows (MSVC, clang-cl and MinGw) it needs an explicit export otherwise the symbol doesn't get exported. */ @@ -644,6 +778,18 @@ const void* MaterialData::tryAttribute(const Containers::StringView layer, const return tryAttribute(layer, string); } +const void* MaterialData::tryAttribute(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::tryAttribute(): invalid name" << layer, {}); + return tryAttribute(string, name); +} + +const void* MaterialData::tryAttribute(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::tryAttribute(): invalid name" << layer, {}); + return tryAttribute(string, name); +} + #ifdef MAGNUM_BUILD_DEPRECATED CORRADE_IGNORE_DEPRECATED_PUSH MaterialData::Flags MaterialData::flags() const { @@ -679,6 +825,15 @@ Containers::Array MaterialData::releaseAttributeData() { return std::move(_data); } +Debug& operator<<(Debug& debug, const MaterialLayer value) { + debug << "Trade::MaterialLayer" << Debug::nospace; + + if(UnsignedInt(value) - 1 >= Containers::arraySize(LayerMap)) + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; + + return debug << "::" << Debug::nospace << LayerMap[UnsignedInt(value) - 1]; +} + Debug& operator<<(Debug& debug, const MaterialAttribute value) { debug << "Trade::MaterialAttribute" << Debug::nospace; @@ -753,6 +908,7 @@ Debug& operator<<(Debug& debug, const MaterialType value) { _c(Phong) _c(PbrMetallicRoughness) _c(PbrSpecularGlossiness) + _c(PbrClearCoat) #undef _c /* LCOV_EXCL_STOP */ } @@ -765,7 +921,8 @@ Debug& operator<<(Debug& debug, const MaterialTypes value) { MaterialType::Flat, MaterialType::Phong, MaterialType::PbrMetallicRoughness, - MaterialType::PbrSpecularGlossiness + MaterialType::PbrSpecularGlossiness, + MaterialType::PbrClearCoat }); } diff --git a/src/Magnum/Trade/MaterialData.h b/src/Magnum/Trade/MaterialData.h index 3df96010d..9b5dd48d0 100644 --- a/src/Magnum/Trade/MaterialData.h +++ b/src/Magnum/Trade/MaterialData.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Trade::MaterialData, @ref Magnum::Trade::MaterialAttributeData, enum @ref Magnum::Trade::MaterialAttribute, @ref Magnum::Trade::MaterialTextureSwizzle, @ref Magnum::Trade::MaterialAttributeType + * @brief Class @ref Magnum::Trade::MaterialData, @ref Magnum::Trade::MaterialAttributeData, enum @ref Magnum::Trade::MaterialLayer, @ref Magnum::Trade::MaterialAttribute, @ref Magnum::Trade::MaterialTextureSwizzle, @ref Magnum::Trade::MaterialAttributeType * @m_since_latest */ @@ -43,6 +43,48 @@ namespace Magnum { namespace Trade { +/** +@brief Material layer name +@m_since_latest + +Convenience aliases to actual layer name strings. The alias is in the same form +and capitalization --- so for example @ref MaterialLayer::ClearCoat is an alias +for @cpp "ClearCoat" @ce. Each layer is expected to contain (a subset of) the +@ref MaterialAttribute::LayerName, @ref MaterialAttribute::LayerFactor, +@ref MaterialAttribute::LayerFactorTexture, +@ref MaterialAttribute::LayerFactorTextureSwizzle, +@ref MaterialAttribute::LayerFactorTextureMatrix, +@ref MaterialAttribute::LayerFactorTextureCoordinates attributes in addition to +what's specified for a particular named layer. +@see @ref MaterialData, @ref MaterialData::layerName(), @ref MaterialLayerData +*/ +enum class MaterialLayer: UnsignedInt { + /* Zero used for an invalid value */ + + /** + * Clear coat material layer. + * + * Expected to contain (a subset of) the + * @ref MaterialAttribute::Roughness, + * @ref MaterialAttribute::RoughnessTexture, + * @ref MaterialAttribute::RoughnessTextureSwizzle, + * @ref MaterialAttribute::RoughnessTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureCoordinates, + * @ref MaterialAttribute::NormalTexture, + * @ref MaterialAttribute::NormalTextureSwizzle, + * @ref MaterialAttribute::NormalTextureMatrix and + * @ref MaterialAttribute::NormalTextureCoordinates attributes. + * @see @ref PbrClearCoatMaterialData + */ + ClearCoat = 1, +}; + +/** +@debugoperatorenum{MaterialLayer} +@m_since_latest +*/ +MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, MaterialLayer value); + /** @brief Material attribute name @m_since_latest @@ -1055,6 +1097,16 @@ class MAGNUM_TRADE_EXPORT MaterialAttributeData { */ /*implicit*/ MaterialAttributeData(MaterialAttribute name, MaterialAttributeType type, const void* value) noexcept; + /** + * @brief Construct a layer name attribute + * @param layerName Material layer name + * + * Equivalent to calling @ref MaterialAttributeData(MaterialAttribute, Containers::StringView) + * with @ref MaterialAttribute::LayerName and a string corresponding to + * @p layerName. + */ + /*implicit*/ MaterialAttributeData(MaterialLayer layerName) noexcept; + /** @brief Attribute type */ MaterialAttributeType type() const { return _data.type; } @@ -1232,7 +1284,13 @@ enum class MaterialType: UnsignedInt { * PBR specular/glossiness. Use @ref PbrSpecularGlossinessMaterialData for * convenience attribute access. */ - PbrSpecularGlossiness = 1 << 3 + PbrSpecularGlossiness = 1 << 3, + + /** + * PBR clear coat layer. Use @ref PbrClearCoatMaterialData for convenience + * attribute access. + */ + PbrClearCoat = 1 << 4 }; /** @debugoperatorenum{MaterialType} */ @@ -1516,6 +1574,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasAttribute() */ bool hasLayer(Containers::StringView layer) const; + bool hasLayer(MaterialLayer layer) const; /**< @overload */ /** * @brief ID of a named layer @@ -1524,6 +1583,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ UnsignedInt layerId(Containers::StringView layer) const; + UnsignedInt layerId(MaterialLayer layer) const; /**< @overload */ /** * @brief Layer name @@ -1564,6 +1624,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ Float layerFactor(Containers::StringView layer) const; + Float layerFactor(MaterialLayer layer) const; /**< @overload */ /** * @brief Factor texture ID for given layer @@ -1584,6 +1645,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer(), @ref hasAttribute() */ UnsignedInt layerFactorTexture(Containers::StringView layer) const; + UnsignedInt layerFactorTexture(MaterialLayer layer) const; /**< @overload */ /** * @brief Factor texture swizzle for given layer @@ -1607,6 +1669,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer(), @ref hasAttribute() */ MaterialTextureSwizzle layerFactorTextureSwizzle(Containers::StringView layer) const; + MaterialTextureSwizzle layerFactorTextureSwizzle(MaterialLayer layer) const; /**< @overload */ /** * @brief Factor texture coordinate transformation matrix for given layer @@ -1634,6 +1697,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer(), @ref hasAttribute() */ Matrix3 layerFactorTextureMatrix(Containers::StringView layer) const; + Matrix3 layerFactorTextureMatrix(MaterialLayer layer) const; /**< @overload */ /** * @brief Factor texture coordinate set for given layer @@ -1661,6 +1725,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer(), @ref hasAttribute() */ UnsignedInt layerFactorTextureCoordinates(Containers::StringView layer) const; + UnsignedInt layerFactorTextureCoordinates(MaterialLayer layer) const; /**< @overload */ /** * @brief Attribute count in given layer @@ -1676,6 +1741,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ UnsignedInt attributeCount(Containers::StringView layer) const; + UnsignedInt attributeCount(MaterialLayer layer) const; /**< @overload */ /** * @brief Attribute count in the base material @@ -1702,6 +1768,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ bool hasAttribute(Containers::StringView layer, Containers::StringView name) const; bool hasAttribute(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + bool hasAttribute(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + bool hasAttribute(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Whether the base material has given attribute @@ -1736,6 +1804,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ UnsignedInt attributeId(Containers::StringView layer, Containers::StringView name) const; UnsignedInt attributeId(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + UnsignedInt attributeId(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + UnsignedInt attributeId(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief ID of a named attribute in the base material @@ -1769,6 +1839,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ Containers::StringView attributeName(Containers::StringView layer, UnsignedInt id) const; + Containers::StringView attributeName(MaterialLayer layer, UnsignedInt id) const; /**< @overload */ /** * @brief Name of an attribute in the base material @@ -1809,6 +1880,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ MaterialAttributeType attributeType(Containers::StringView layer, UnsignedInt id) const; + MaterialAttributeType attributeType(MaterialLayer layer, UnsignedInt id) const; /**< @overload */ /** * @brief Type of a named attribute in a named material layer @@ -1819,6 +1891,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ MaterialAttributeType attributeType(Containers::StringView layer, Containers::StringView name) const; MaterialAttributeType attributeType(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + MaterialAttributeType attributeType(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + MaterialAttributeType attributeType(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Type of an attribute in the base material @@ -1900,6 +1974,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ const void* attribute(Containers::StringView layer, UnsignedInt id) const; + const void* attribute(MaterialLayer layer, UnsignedInt id) const; /**< @overload */ /** * @brief Type-erased value of a named attribute in a named material layer @@ -1920,6 +1995,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ const void* attribute(Containers::StringView layer, Containers::StringView name) const; const void* attribute(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + const void* attribute(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + const void* attribute(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Type-erased value of an attribute in the base material @@ -1984,6 +2061,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { * @see @ref hasLayer() */ template T attribute(Containers::StringView layer, UnsignedInt id) const; + template T attribute(MaterialLayer layer, UnsignedInt id) const; /**< @overload */ /** * @brief Value of a named attribute in a named material layer @@ -1998,6 +2076,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ template T attribute(Containers::StringView layer, Containers::StringView name) const; template T attribute(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + template T attribute(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + template T attribute(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Value of an attribute in the base material @@ -2045,6 +2125,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ const void* tryAttribute(Containers::StringView layer, Containers::StringView name) const; const void* tryAttribute(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + const void* tryAttribute(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + const void* tryAttribute(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Value of a named attribute in given material layer, if exists @@ -2071,6 +2153,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ template Containers::Optional tryAttribute(Containers::StringView layer, Containers::StringView name) const; template Containers::Optional tryAttribute(Containers::StringView layer, MaterialAttribute name) const; /**< @overload */ + template Containers::Optional tryAttribute(MaterialLayer layer, Containers::StringView name) const; /**< @overload */ + template Containers::Optional tryAttribute(MaterialLayer layer, MaterialAttribute name) const; /**< @overload */ /** * @brief Type-erased attribute value in the base material, if exists @@ -2123,6 +2207,8 @@ class MAGNUM_TRADE_EXPORT MaterialData { */ template T attributeOr(Containers::StringView layer, Containers::StringView name, const T& defaultValue) const; template T attributeOr(Containers::StringView layer, MaterialAttribute name, const T& defaultValue) const; /**< @overload */ + template T attributeOr(MaterialLayer layer, Containers::StringView name, const T& defaultValue) const; /**< @overload */ + template T attributeOr(MaterialLayer layer, MaterialAttribute name, const T& defaultValue) const; /**< @overload */ /** * @brief Value of a named attribute in the base material or a default @@ -2225,6 +2311,7 @@ class MAGNUM_TRADE_EXPORT MaterialData { implementations. */ friend AbstractImporter; + static Containers::StringView layerString(MaterialLayer name); static Containers::StringView attributeString(MaterialAttribute name); /* Internal helpers that don't assert, unlike layerId() / attributeId() */ UnsignedInt layerFor(Containers::StringView layer) const; @@ -2407,6 +2494,24 @@ template T MaterialData::attribute(const Containers::StringView layer, return attribute(layer, string); } +template T MaterialData::attribute(const MaterialLayer layer, const UnsignedInt id) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, id); +} + +template T MaterialData::attribute(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, name); +} + +template T MaterialData::attribute(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {}); + return attribute(string, name); +} + template Containers::Optional MaterialData::tryAttribute(const UnsignedInt layer, const Containers::StringView name) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::tryAttribute(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -2434,6 +2539,18 @@ template Containers::Optional MaterialData::tryAttribute(const Conta return tryAttribute(layer, string); } +template Containers::Optional MaterialData::tryAttribute(const MaterialLayer layer, const Containers::StringView name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::tryAttribute(): invalid name" << layer, {}); + return tryAttribute(string, name); +} + +template Containers::Optional MaterialData::tryAttribute(const MaterialLayer layer, const MaterialAttribute name) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::tryAttribute(): invalid name" << layer, {}); + return tryAttribute(string, name); +} + template T MaterialData::attributeOr(const UnsignedInt layer, const Containers::StringView name, const T& defaultValue) const { CORRADE_ASSERT(layer < layerCount(), "Trade::MaterialData::attributeOr(): index" << layer << "out of range for" << layerCount() << "layers", {}); @@ -2461,6 +2578,18 @@ template T MaterialData::attributeOr(const Containers::StringView layer return attributeOr(layer, string, defaultValue); } +template T MaterialData::attributeOr(const MaterialLayer layer, const Containers::StringView name, const T& defaultValue) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeOr(): invalid name" << layer, {}); + return attributeOr(string, name, defaultValue); +} + +template T MaterialData::attributeOr(const MaterialLayer layer, const MaterialAttribute name, const T& defaultValue) const { + const Containers::StringView string = layerString(layer); + CORRADE_ASSERT(string.data(), "Trade::MaterialData::attributeOr(): invalid name" << layer, {}); + return attributeOr(string, name, defaultValue); +} + }} #endif diff --git a/src/Magnum/Trade/MaterialLayerData.h b/src/Magnum/Trade/MaterialLayerData.h new file mode 100644 index 000000000..b0dad741f --- /dev/null +++ b/src/Magnum/Trade/MaterialLayerData.h @@ -0,0 +1,255 @@ +#ifndef Magnum_Trade_MaterialLayerData_h +#define Magnum_Trade_MaterialLayerData_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Trade::MaterialLayerData + * @m_since_latest + */ + +#include "Magnum/Math/Matrix3.h" +#include "Magnum/Trade/MaterialData.h" + +namespace Magnum { namespace Trade { + +/** +@brief Material layer data +@m_since_latest + +Convenience wrapper that re-routes all @ref MaterialData base material layer +and attribute accessors APIS from to a layer specified in the @p layer template +parameter. All APIs expect that given layer exists. +*/ +template class MaterialLayerData: public MaterialData { + public: + /* Allow constructing subclasses directly. While not used in the + general Importer workflow, it allows users to create instances with + desired convenience APIs easier (and simplifies testing) */ + using MaterialData::MaterialData; + + /* Bring in all other overloads as well and override just the ones + with implicit layers */ + using MaterialData::layerName; + using MaterialData::layerFactor; + using MaterialData::layerFactorTexture; + using MaterialData::layerFactorTextureSwizzle; + using MaterialData::layerFactorTextureMatrix; + using MaterialData::layerFactorTextureCoordinates; + using MaterialData::attributeCount; + using MaterialData::hasAttribute; + using MaterialData::attributeId; + using MaterialData::attributeName; + using MaterialData::attributeType; + using MaterialData::attribute; + using MaterialData::tryAttribute; + using MaterialData::attributeOr; + + /** + * @brief Layer name + * + * Same as calling @ref MaterialData::layerName() with @ref layerId() + * for @p layer. + */ + Containers::StringView layerName() const { + return MaterialData::layerName(layerId(layer)); + } + + /** + * @brief Layer factor + * + * Same as calling @ref MaterialData::layerFactor() with @p layer. + */ + Float layerFactor() const { + return MaterialData::layerFactor(layer); + } + + /** + * @brief Layer factor texture ID + * + * Same as calling @ref MaterialData::layerFactorTexture() with + * @p layer. + */ + UnsignedInt layerFactorTexture() const { + return MaterialData::layerFactorTexture(layer); + } + + /** + * @brief Layer factor texture swizzle + * + * Same as calling @ref MaterialData::layerFactorTextureSwizzle() with + * @p layer. + */ + MaterialTextureSwizzle layerFactorTextureSwizzle() const { + return MaterialData::layerFactorTextureSwizzle(layer); + } + + /** + * @brief Layer factor texture coordinate transformation matrix + * + * Same as calling @ref MaterialData::layerFactorTextureMatrix() with + * @p layer. + */ + Matrix3 layerFactorTextureMatrix() const { + return MaterialData::layerFactorTextureMatrix(layer); + } + + /** + * @brief Layer factor texture coordinate set + * + * Same as calling @ref MaterialData::layerFactorTextureCoordinates() + * with @p layer. + */ + UnsignedInt layerFactorTextureCoordinates() const { + return MaterialData::layerFactorTextureCoordinates(layer); + } + + /** + * @brief Attribute count in this layer + * + * Same as calling @ref MaterialData::attributeCount() with @p layer. + */ + UnsignedInt attributeCount() const { + return MaterialData::attributeCount(layer); + } + + /** + * @brief Whether this layer has given attribute + * + * Same as calling @ref MaterialData::hasAttribute() with @p layer. + */ + bool hasAttribute(Containers::StringView name) const { + return MaterialData::hasAttribute(layer, name); + } + bool hasAttribute(MaterialAttribute name) const { + return MaterialData::hasAttribute(layer, name); + } /**< @overload */ + + /** + * @brief ID of a named attribute in this layer + * + * Same as calling @ref MaterialData::attributeId() with @p layer. + */ + UnsignedInt attributeId(Containers::StringView name) const { + return MaterialData::attributeId(layer, name); + } + UnsignedInt attributeId(MaterialAttribute name) const { + return MaterialData::attributeId(layer, name); + } /**< @overload */ + + /** + * @brief Name of an attribute in this layer + * + * Same as calling @ref MaterialData::attributeName() with @p layer. + */ + Containers::StringView attributeName(UnsignedInt id) const { + return MaterialData::attributeName(layer, id); + } + + /** + * @brief Type of an attribute in this layer + * + * Same as calling @ref MaterialData::attributeType() with @p layer. + */ + MaterialAttributeType attributeType(UnsignedInt id) const { + return MaterialData::attributeType(layer, id); + } + MaterialAttributeType attributeType(Containers::StringView name) const { + return MaterialData::attributeType(layer, name); + } /**< @overload */ + MaterialAttributeType attributeType(MaterialAttribute name) const { + return MaterialData::attributeType(layer, name); + } /**< @overload */ + + /** + * @brief Type-erased value of an attribute in this layer + * + * Same as calling @ref MaterialData::attribute() with @p layer. + */ + const void* attribute(UnsignedInt id) const { + return MaterialData::attribute(layer, id); + } + const void* attribute(Containers::StringView name) const { + return MaterialData::attribute(layer, name); + } /**< @overload */ + const void* attribute(MaterialAttribute name) const { + return MaterialData::attribute(layer, name); + } /**< @overload */ + + /** + * @brief Value of an attribute in this layer + * + * Same as calling @ref MaterialData::attribute() with @p layer. + */ + template T attribute(UnsignedInt id) const { + return MaterialData::attribute(layer, id); + } + template T attribute(Containers::StringView name) const { + return MaterialData::attribute(layer, name); + } /**< @overload */ + template T attribute(MaterialAttribute name) const { + return MaterialData::attribute(layer, name); + } /**< @overload */ + + /** + * @brief Type-erased attribute value in this layer, if exists + * + * Same as calling @ref MaterialData::tryAttribute() with @p layer. + */ + const void* tryAttribute(Containers::StringView name) const { + return MaterialData::tryAttribute(layer, name); + } + const void* tryAttribute(MaterialAttribute name) const { + return MaterialData::tryAttribute(layer, name); + } /**< @overload */ + + /** + * @brief Value of a named attribute in this layer, if exists + * + * Same as calling @ref MaterialData::tryAttribute() with @p layer. + */ + template Containers::Optional tryAttribute(Containers::StringView name) const { + return MaterialData::tryAttribute(layer, name); + } + template Containers::Optional tryAttribute(MaterialAttribute name) const { + return MaterialData::tryAttribute(layer, name); + } /**< @overload */ + + /** + * @brief Value of a named attribute in this layer or a default + * + * Same as calling @ref MaterialData::attributeOr() with @p layer. + */ + template T attributeOr(Containers::StringView name, const T& defaultValue) const { + return MaterialData::attributeOr(layer, name, defaultValue); + } + template T attributeOr(MaterialAttribute name, const T& defaultValue) const { + return MaterialData::attributeOr(layer, name, defaultValue); + } /**< @overload */ +}; + +}} + +#endif diff --git a/src/Magnum/Trade/PbrClearCoatMaterialData.cpp b/src/Magnum/Trade/PbrClearCoatMaterialData.cpp new file mode 100644 index 000000000..0ff45bbd3 --- /dev/null +++ b/src/Magnum/Trade/PbrClearCoatMaterialData.cpp @@ -0,0 +1,110 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "PbrClearCoatMaterialData.h" + +namespace Magnum { namespace Trade { + +bool PbrClearCoatMaterialData::hasTextureTransformation() const { + return hasAttribute(MaterialAttribute::LayerFactorTextureMatrix) || + hasAttribute(MaterialAttribute::RoughnessTextureMatrix) || + hasAttribute(MaterialAttribute::NormalTextureMatrix) || + hasAttribute(MaterialAttribute::TextureMatrix) || + hasAttribute(0, MaterialAttribute::TextureMatrix); +} + +bool PbrClearCoatMaterialData::hasTextureCoordinates() const { + return hasAttribute(MaterialAttribute::LayerFactorTextureCoordinates) || + hasAttribute(MaterialAttribute::RoughnessTextureCoordinates) || + hasAttribute(MaterialAttribute::NormalTextureCoordinates) || + hasAttribute(MaterialAttribute::TextureCoordinates) || + hasAttribute(0, MaterialAttribute::TextureCoordinates); +} + +Float PbrClearCoatMaterialData::roughness() const { + return attributeOr(MaterialAttribute::Roughness, 0.0f); +} + +UnsignedInt PbrClearCoatMaterialData::roughnessTexture() const { + return attribute(MaterialAttribute::RoughnessTexture); +} + +MaterialTextureSwizzle PbrClearCoatMaterialData::roughnessTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::RoughnessTexture), + "Trade::PbrClearCoatMaterialData::roughnessTextureSwizzle(): the layer doesn't have a roughness texture", {}); + return attributeOr(MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrClearCoatMaterialData::roughnessTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::RoughnessTexture), + "Trade::PbrClearCoatMaterialData::roughnessTextureMatrix(): the layer doesn't have a roughness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::RoughnessTextureMatrix)) + return *value; + if(Containers::Optional value = tryAttribute(MaterialAttribute::TextureMatrix)) + return *value; + return attributeOr(0, MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrClearCoatMaterialData::roughnessTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::RoughnessTexture), + "Trade::PbrClearCoatMaterialData::roughnessTextureCoordinates(): the layer doesn't have a roughness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::RoughnessTextureCoordinates)) + return *value; + if(Containers::Optional value = tryAttribute(MaterialAttribute::TextureCoordinates)) + return *value; + return attributeOr(0, MaterialAttribute::TextureCoordinates, 0u); +} + +UnsignedInt PbrClearCoatMaterialData::normalTexture() const { + return attribute(MaterialAttribute::NormalTexture); +} + +MaterialTextureSwizzle PbrClearCoatMaterialData::normalTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrClearCoatMaterialData::normalTextureSwizzle(): the layer doesn't have a normal texture", {}); + return attributeOr(MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RGB); +} + +Matrix3 PbrClearCoatMaterialData::normalTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrClearCoatMaterialData::normalTextureMatrix(): the layer doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureMatrix)) + return *value; + if(Containers::Optional value = tryAttribute(MaterialAttribute::TextureMatrix)) + return *value; + return attributeOr(0, MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrClearCoatMaterialData::normalTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrClearCoatMaterialData::normalTextureCoordinates(): the layer doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureCoordinates)) + return *value; + if(Containers::Optional value = tryAttribute(MaterialAttribute::TextureCoordinates)) + return *value; + return attributeOr(0, MaterialAttribute::TextureCoordinates, 0u); +} + +}} diff --git a/src/Magnum/Trade/PbrClearCoatMaterialData.h b/src/Magnum/Trade/PbrClearCoatMaterialData.h new file mode 100644 index 000000000..be3a0c145 --- /dev/null +++ b/src/Magnum/Trade/PbrClearCoatMaterialData.h @@ -0,0 +1,193 @@ +#ifndef Magnum_Trade_PbrClearCoatMaterialData_h +#define Magnum_Trade_PbrClearCoatMaterialData_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Trade::PbrClearCoatMaterialData + * @m_since_latest + */ + +#include "Magnum/Trade/MaterialLayerData.h" + +namespace Magnum { namespace Trade { + +/** +@brief Clear coat material layer data +@m_since_latest + +Exposes properties of a @ref MaterialLayer::ClearCoat layer. All APIs expect +that the layer is present in the material. +@see @ref AbstractImporter::material(), @ref MaterialType::PbrClearCoat +*/ +class MAGNUM_TRADE_EXPORT PbrClearCoatMaterialData: public MaterialLayerData { + public: + #ifndef DOXYGEN_GENERATING_OUTPUT + /* Allow constructing subclasses directly. While not used in the + general Importer workflow, it allows users to create instances with + desired convenience APIs easier (and simplifies testing). It's + however hidden from the docs as constructing instances this way + isn't really common and it would add a lot of noise. */ + using MaterialLayerData::MaterialLayerData; + #endif + + /** + * @brief Whether the material has texture transformation + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::LayerFactorTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureMatrix, + * @ref MaterialAttribute::NormalTextureMatrix or + * @ref MaterialAttribute::TextureMatrix attributes are present in this + * layer or if @ref MaterialAttribute::TextureMatrix is present in the + * base material, @cpp false @ce otherwise + */ + bool hasTextureTransformation() const; + + /** + * @brief Whether the material uses extra texture coordinate sets + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::LayerFactorTextureCoordinates, + * @ref MaterialAttribute::RoughnessTextureCoordinates, + * @ref MaterialAttribute::NormalTextureCoordinates or + * @ref MaterialAttribute::TextureCoordinates attributes are present in + * this material or if @ref MaterialAttribute::TextureCoordinates is + * present in the base material, @cpp false @ce otherwise. + */ + bool hasTextureCoordinates() const; + + /** + * @brief Roughness factor + * + * Convenience access to the @ref MaterialAttribute::Roughness + * attribute in this layer. If not present, the default is @cpp 1.0f @ce. + * + * If the layer has a @ref MaterialAttribute::RoughnessTexture, the + * factor and texture is meant to be multiplied together. + */ + Float roughness() const; + + /** + * @brief Roughness texture ID + * + * Available only if @ref MaterialAttribute::RoughnessTexture is + * present in this layer. Meant to be multiplied with @ref roughness(). + * @see @ref AbstractImporter::texture() + */ + UnsignedInt roughnessTexture() const; + + /** + * @brief Roughness texture swizzle + * + * Convenience access to the @ref MaterialAttribute::RoughnessTextureSwizzle + * attribute in this layer. If not present, the default is @cpp 1.0f @ce. + * Available only if @ref MaterialAttribute::RoughnessTexture is + * present in this layer. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle roughnessTextureSwizzle() const; + + /** + * @brief Roughness texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::RoughnessTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes in this layer or + * a @ref MaterialAttribute::TextureMatrix attribute in the base + * material. If neither is present, the default is an identity matrix. + * Available only if @ref MaterialAttribute::RoughnessTexture is + * present in this layer. + * @see @ref hasAttribute() + */ + Matrix3 roughnessTextureMatrix() const; + + /** + * @brief Roughness texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::RoughnessTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes in this + * layer or a @ref MaterialAttribute::TextureCoordinates attribute in + * the base material. If neither is present, the default is @cpp 0 @ce. + * Available only if @ref MaterialAttribute::RoughnessTexture is + * present in this layer. + * @see @ref hasAttribute() + */ + UnsignedInt roughnessTextureCoordinates() const; + + /** + * @brief Normal texture ID + * + * Available only if @ref MaterialAttribute::NormalTexture is present + * in this layer. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt normalTexture() const; + + /** + * @brief Normal texture swizzle + * + * Convenience access to the + * @ref MaterialAttribute::NormalTextureSwizzle attribute in this + * layer. If not present, the default is + * @ref MaterialTextureSwizzle::RGB. Available only if + * @ref MaterialAttribute::NormalTexture is present in this layer. + * + * The texture can be also just two-component, in which case the + * remaining component is implicit and calculated as + * @f$ z = \sqrt{1 - x^2 - y^2} @f$. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle normalTextureSwizzle() const; + + /** + * @brief Normal texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::NormalTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes in this layer or + * a @ref MaterialAttribute::TextureMatrix attribute in the base + * material. If neither is present, the default is an identity matrix. + * Available only if @ref MaterialAttribute::NormalTexture is present + * in this layer. + * @see @ref hasAttribute() + */ + Matrix3 normalTextureMatrix() const; + + /** + * @brief Normal texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::NormalTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes in this + * layer or a @ref MaterialAttribute::TextureCoordinates attribute in + * the base material. If neither is present, the default is @cpp 0 @ce. + * Available only if @ref MaterialAttribute::NormalTexture is present + * in this layer. + * @see @ref hasAttribute() + */ + UnsignedInt normalTextureCoordinates() const; +}; + +}} + +#endif diff --git a/src/Magnum/Trade/Test/MaterialDataTest.cpp b/src/Magnum/Trade/Test/MaterialDataTest.cpp index 2864bc092..ee5703c71 100644 --- a/src/Magnum/Trade/Test/MaterialDataTest.cpp +++ b/src/Magnum/Trade/Test/MaterialDataTest.cpp @@ -35,6 +35,7 @@ #include "Magnum/Math/Matrix3.h" #include "Magnum/Trade/FlatMaterialData.h" #include "Magnum/Trade/MaterialData.h" +#include "Magnum/Trade/PbrClearCoatMaterialData.h" #include "Magnum/Trade/PbrMetallicRoughnessMaterialData.h" #include "Magnum/Trade/PbrSpecularGlossinessMaterialData.h" #include "Magnum/Trade/PhongMaterialData.h" @@ -49,6 +50,7 @@ class MaterialDataTest: public TestSuite::Tester { void attributeTypeSizeInvalid(); void attributeMap(); + void layerMap(); void constructAttributeDefault(); void constructAttributeString(); @@ -63,8 +65,10 @@ class MaterialDataTest: public TestSuite::Tester { void constructAttributeStringNameStringValue(); void constructAttributeNameStringValue(); void constructAttributeTextureSwizzle(); + void constructAttributeLayer(); void constructAttributeInvalidName(); + void constructAttributeInvalidLayerName(); void constructAttributeWrongTypeForName(); void constructAttributeInvalidType(); void constructAttributeTooLarge(); @@ -120,9 +124,11 @@ class MaterialDataTest: public TestSuite::Tester { void accessLayerLayerNameInBaseMaterial(); void accessLayerEmptyLayer(); void accessLayerIndexOptional(); + void accessLayerNameOptional(); void accessLayerStringOptional(); void accessLayerOutOfBounds(); void accessLayerNotFound(); + void accessInvalidLayerName(); void accessOutOfBoundsInLayerIndex(); void accessOutOfBoundsInLayerString(); void accessNotFoundInLayerIndex(); @@ -181,6 +187,17 @@ class MaterialDataTest: public TestSuite::Tester { void flatAccessTexturedMismatchedMatrixCoordinates(); void flatAccessInvalidTextures(); + void templateLayerAccess(); + + void pbrClearCoatAccess(); + void pbrClearCoatAccessDefaults(); + void pbrClearCoatAccessTextured(); + void pbrClearCoatAccessTexturedDefaults(); + void pbrClearCoatAccessTexturedSingleMatrixCoordinates(); + void pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates(); + void pbrClearCoatAccessInvalidTextures(); + + void debugLayer(); void debugAttribute(); void debugTextureSwizzle(); void debugAttributeType(); @@ -203,6 +220,7 @@ MaterialDataTest::MaterialDataTest() { addTests({&MaterialDataTest::attributeTypeSize, &MaterialDataTest::attributeTypeSizeInvalid, &MaterialDataTest::attributeMap, + &MaterialDataTest::layerMap, &MaterialDataTest::constructAttributeDefault, &MaterialDataTest::constructAttributeString, @@ -241,8 +259,10 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::constructAttributeStringNameStringValue, &MaterialDataTest::constructAttributeNameStringValue, &MaterialDataTest::constructAttributeTextureSwizzle, + &MaterialDataTest::constructAttributeLayer, &MaterialDataTest::constructAttributeInvalidName, + &MaterialDataTest::constructAttributeInvalidLayerName, &MaterialDataTest::constructAttributeWrongTypeForName, &MaterialDataTest::constructAttributeInvalidType, &MaterialDataTest::constructAttributeTooLarge, @@ -301,9 +321,11 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::accessLayerLayerNameInBaseMaterial, &MaterialDataTest::accessLayerEmptyLayer, &MaterialDataTest::accessLayerIndexOptional, + &MaterialDataTest::accessLayerNameOptional, &MaterialDataTest::accessLayerStringOptional, &MaterialDataTest::accessLayerOutOfBounds, &MaterialDataTest::accessLayerNotFound, + &MaterialDataTest::accessInvalidLayerName, &MaterialDataTest::accessOutOfBoundsInLayerIndex, &MaterialDataTest::accessOutOfBoundsInLayerString, &MaterialDataTest::accessNotFoundInLayerIndex, @@ -362,6 +384,17 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::flatAccessTexturedMismatchedMatrixCoordinates, &MaterialDataTest::flatAccessInvalidTextures, + &MaterialDataTest::templateLayerAccess, + + &MaterialDataTest::pbrClearCoatAccess, + &MaterialDataTest::pbrClearCoatAccessDefaults, + &MaterialDataTest::pbrClearCoatAccessTextured, + &MaterialDataTest::pbrClearCoatAccessTexturedDefaults, + &MaterialDataTest::pbrClearCoatAccessTexturedSingleMatrixCoordinates, + &MaterialDataTest::pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates, + &MaterialDataTest::pbrClearCoatAccessInvalidTextures, + + &MaterialDataTest::debugLayer, &MaterialDataTest::debugAttribute, &MaterialDataTest::debugTextureSwizzle, &MaterialDataTest::debugAttributeType, @@ -456,6 +489,35 @@ void MaterialDataTest::attributeMap() { } } +void MaterialDataTest::layerMap() { + /* Ensure all layer names are: + - present in the map, + - and that their translated string name corresponds to the enum value + name + This goes through the first 16 bits, which should be enough. Going + through 32 bits takes 8 seconds, too much. */ + for(UnsignedInt i = 1; i <= 0xffff; ++i) { + /* Attribute 0 reserved for an invalid value */ + + const auto attribute = MaterialLayer(i); + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic error "-Wswitch" + #endif + switch(attribute) { + #define _c(name_) \ + case MaterialLayer::name_: \ + CORRADE_COMPARE((MaterialAttributeData{MaterialLayer::name_}.value()), #name_); \ + break; + #include "Magnum/Trade/Implementation/materialLayerProperties.hpp" + #undef _c + } + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif + } +} + void MaterialDataTest::constructAttributeDefault() { MaterialAttributeData attribute; CORRADE_COMPARE(attribute.name(), ""); @@ -678,6 +740,13 @@ void MaterialDataTest::constructAttributeTextureSwizzle() { CORRADE_COMPARE(typeErased.value(), MaterialTextureSwizzle::GBA); } +void MaterialDataTest::constructAttributeLayer() { + MaterialAttributeData attribute{MaterialLayer::ClearCoat}; + CORRADE_COMPARE(attribute.name(), "$LayerName"); + CORRADE_COMPARE(attribute.type(), MaterialAttributeType::String); + CORRADE_COMPARE(attribute.value(), "ClearCoat"); +} + void MaterialDataTest::constructAttributeInvalidName() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -692,6 +761,20 @@ void MaterialDataTest::constructAttributeInvalidName() { "Trade::MaterialAttributeData: invalid name Trade::MaterialAttribute(0xfefe)\n"); } +void MaterialDataTest::constructAttributeInvalidLayerName() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + MaterialAttributeData{MaterialLayer(0x0)}; + MaterialAttributeData{MaterialLayer(0xfefe)}; + CORRADE_COMPARE(out.str(), + "Trade::MaterialAttributeData: invalid name Trade::MaterialLayer(0x0)\n" + "Trade::MaterialAttributeData: invalid name Trade::MaterialLayer(0xfefe)\n"); +} + void MaterialDataTest::constructAttributeWrongTypeForName() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -952,7 +1035,7 @@ void MaterialDataTest::constructLayers() { /* Layer name gets sorted first by the constructor */ {"highlightColor", 0x335566ff_rgbaf}, {MaterialAttribute::AlphaBlend, true}, - {MaterialAttribute::LayerName, "ClearCoat"}, + {MaterialLayer::ClearCoat}, /* Empty layer here */ @@ -975,6 +1058,7 @@ void MaterialDataTest::constructLayers() { CORRADE_COMPARE(data.attributeCount(2), 0); CORRADE_COMPARE(data.attributeCount(3), 2); CORRADE_COMPARE(data.attributeCount("ClearCoat"), 3); + CORRADE_COMPARE(data.attributeCount(MaterialLayer::ClearCoat), 3); /* Layer access */ CORRADE_COMPARE(data.layerName(0), ""); @@ -983,10 +1067,12 @@ void MaterialDataTest::constructLayers() { CORRADE_COMPARE(data.layerName(3), ""); CORRADE_VERIFY(data.hasLayer("ClearCoat")); + CORRADE_VERIFY(data.hasLayer(MaterialLayer::ClearCoat)); CORRADE_VERIFY(!data.hasLayer("")); CORRADE_VERIFY(!data.hasLayer("DoubleSided")); CORRADE_COMPARE(data.layerId("ClearCoat"), 1); + CORRADE_COMPARE(data.layerId(MaterialLayer::ClearCoat), 1); /* Verify sorting in each layer */ CORRADE_COMPARE(data.attributeName(0, 0), "DiffuseTextureCoordinates"); @@ -1070,6 +1156,51 @@ void MaterialDataTest::constructLayers() { CORRADE_COMPARE(static_cast(data.attribute(1, "$LayerName")), "ClearCoat"_s); CORRADE_COMPARE(*static_cast(data.attribute(3, "NormalTexture")), 3); + /* Access by layer name and attribute ID */ + CORRADE_COMPARE(data.attributeName(MaterialLayer::ClearCoat, 1), "AlphaBlend"); + CORRADE_COMPARE(data.attributeName(MaterialLayer::ClearCoat, 2), "highlightColor"); + + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, 1), MaterialAttributeType::Bool); + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, 2), MaterialAttributeType::Vector4); + + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, 1), true); + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, 2), 0x335566ff_rgbaf); + + CORRADE_COMPARE(*static_cast(data.attribute(MaterialLayer::ClearCoat, 1)), true); + CORRADE_COMPARE(*static_cast(data.attribute(MaterialLayer::ClearCoat, 2)), 0x335566ff_rgbaf); + + /* Access by layer name and attribute name */ + CORRADE_VERIFY(data.hasAttribute(MaterialLayer::ClearCoat, MaterialAttribute::AlphaBlend)); + CORRADE_VERIFY(data.hasAttribute(MaterialLayer::ClearCoat, MaterialAttribute::LayerName)); + + CORRADE_COMPARE(data.attributeId(MaterialLayer::ClearCoat, MaterialAttribute::AlphaBlend), 1); + CORRADE_COMPARE(data.attributeId(MaterialLayer::ClearCoat, MaterialAttribute::LayerName), 0); + + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, MaterialAttribute::AlphaBlend), MaterialAttributeType::Bool); + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, MaterialAttribute::LayerName), MaterialAttributeType::String); + + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, MaterialAttribute::LayerName), "ClearCoat"); + + CORRADE_COMPARE(*static_cast(data.attribute(MaterialLayer::ClearCoat, MaterialAttribute::AlphaBlend)), true); + CORRADE_COMPARE(static_cast(data.attribute(MaterialLayer::ClearCoat, MaterialAttribute::LayerName)), "ClearCoat"_s); + + /* Access by layer name and attribute string */ + CORRADE_VERIFY(data.hasAttribute(MaterialLayer::ClearCoat, "highlightColor")); + CORRADE_VERIFY(data.hasAttribute(MaterialLayer::ClearCoat, "$LayerName")); + + CORRADE_COMPARE(data.attributeId(MaterialLayer::ClearCoat, "highlightColor"), 2); + CORRADE_COMPARE(data.attributeId(MaterialLayer::ClearCoat, "$LayerName"), 0); + + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, "highlightColor"), MaterialAttributeType::Vector4); + CORRADE_COMPARE(data.attributeType(MaterialLayer::ClearCoat, "$LayerName"), MaterialAttributeType::String); + + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, "highlightColor"), 0x335566ff_rgbaf); + CORRADE_COMPARE(data.attribute(MaterialLayer::ClearCoat, "$LayerName"), "ClearCoat"); + + CORRADE_COMPARE(*static_cast(data.attribute(MaterialLayer::ClearCoat, "highlightColor")), 0x335566ff_rgbaf); + CORRADE_COMPARE(static_cast(data.attribute(MaterialLayer::ClearCoat, "$LayerName")), "ClearCoat"_s); + /* Access by layer string and attribute ID */ CORRADE_COMPARE(data.attributeName("ClearCoat", 1), "AlphaBlend"); CORRADE_COMPARE(data.attributeName("ClearCoat", 2), "highlightColor"); @@ -1678,6 +1809,7 @@ void MaterialDataTest::accessLayers() { CORRADE_COMPARE(data.layerFactor(2), 0.5f); CORRADE_COMPARE(data.layerFactor("ClearCoat"), 0.5f); + CORRADE_COMPARE(data.layerFactor(MaterialLayer::ClearCoat), 0.5f); } void MaterialDataTest::accessLayersDefaults() { @@ -1691,6 +1823,7 @@ void MaterialDataTest::accessLayersDefaults() { CORRADE_COMPARE(data.layerFactor(1), 1.0f); CORRADE_COMPARE(data.layerFactor("ClearCoat"), 1.0f); + CORRADE_COMPARE(data.layerFactor(MaterialLayer::ClearCoat), 1.0f); } void MaterialDataTest::accessLayersTextured() { @@ -1711,18 +1844,23 @@ void MaterialDataTest::accessLayersTextured() { CORRADE_COMPARE(data.layerFactor(2), 0.5f); CORRADE_COMPARE(data.layerFactor("ClearCoat"), 0.5f); + CORRADE_COMPARE(data.layerFactor(MaterialLayer::ClearCoat), 0.5f); CORRADE_COMPARE(data.layerFactorTexture(2), 4u); CORRADE_COMPARE(data.layerFactorTexture("ClearCoat"), 4u); + CORRADE_COMPARE(data.layerFactorTexture(MaterialLayer::ClearCoat), 4u); CORRADE_COMPARE(data.layerFactorTextureSwizzle(2), MaterialTextureSwizzle::A); CORRADE_COMPARE(data.layerFactorTextureSwizzle("ClearCoat"), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.layerFactorTextureSwizzle(MaterialLayer::ClearCoat), MaterialTextureSwizzle::A); CORRADE_COMPARE(data.layerFactorTextureMatrix(2), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureMatrix("ClearCoat"), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.layerFactorTextureMatrix(MaterialLayer::ClearCoat), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureCoordinates(2), 2u); CORRADE_COMPARE(data.layerFactorTextureCoordinates("ClearCoat"), 2u); + CORRADE_COMPARE(data.layerFactorTextureCoordinates(MaterialLayer::ClearCoat), 2u); } void MaterialDataTest::accessLayersTexturedDefault() { @@ -1739,18 +1877,23 @@ void MaterialDataTest::accessLayersTexturedDefault() { CORRADE_COMPARE(data.layerFactor(2), 1.0f); CORRADE_COMPARE(data.layerFactor("ClearCoat"), 1.0f); + CORRADE_COMPARE(data.layerFactor(MaterialLayer::ClearCoat), 1.0f); CORRADE_COMPARE(data.layerFactorTexture(2), 3u); CORRADE_COMPARE(data.layerFactorTexture("ClearCoat"), 3u); + CORRADE_COMPARE(data.layerFactorTexture(MaterialLayer::ClearCoat), 3u); CORRADE_COMPARE(data.layerFactorTextureSwizzle(2), MaterialTextureSwizzle::R); CORRADE_COMPARE(data.layerFactorTextureSwizzle("ClearCoat"), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.layerFactorTextureSwizzle(MaterialLayer::ClearCoat), MaterialTextureSwizzle::R); CORRADE_COMPARE(data.layerFactorTextureMatrix(2), Matrix3{}); CORRADE_COMPARE(data.layerFactorTextureMatrix("ClearCoat"), Matrix3{}); + CORRADE_COMPARE(data.layerFactorTextureMatrix(MaterialLayer::ClearCoat), Matrix3{}); CORRADE_COMPARE(data.layerFactorTextureCoordinates(2), 0); CORRADE_COMPARE(data.layerFactorTextureCoordinates("ClearCoat"), 0); + CORRADE_COMPARE(data.layerFactorTextureCoordinates(MaterialLayer::ClearCoat), 0); } void MaterialDataTest::accessLayersTexturedSingleMatrixCoordinates() { @@ -1765,9 +1908,11 @@ void MaterialDataTest::accessLayersTexturedSingleMatrixCoordinates() { CORRADE_COMPARE(data.layerFactorTextureMatrix(1), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureMatrix("ClearCoat"), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.layerFactorTextureMatrix(MaterialLayer::ClearCoat), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureCoordinates(1), 2u); CORRADE_COMPARE(data.layerFactorTextureCoordinates("ClearCoat"), 2u); + CORRADE_COMPARE(data.layerFactorTextureCoordinates(MaterialLayer::ClearCoat), 2u); } void MaterialDataTest::accessLayersTexturedBaseMaterialMatrixCoordinates() { @@ -1783,9 +1928,11 @@ void MaterialDataTest::accessLayersTexturedBaseMaterialMatrixCoordinates() { CORRADE_COMPARE(data.layerFactorTextureMatrix(1), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureMatrix("ClearCoat"), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.layerFactorTextureMatrix(MaterialLayer::ClearCoat), Matrix3::scaling({0.5f, 1.0f})); CORRADE_COMPARE(data.layerFactorTextureCoordinates(1), 2u); CORRADE_COMPARE(data.layerFactorTextureCoordinates("ClearCoat"), 2u); + CORRADE_COMPARE(data.layerFactorTextureCoordinates(MaterialLayer::ClearCoat), 2u); } void MaterialDataTest::accessLayersInvalidTextures() { @@ -1801,20 +1948,28 @@ void MaterialDataTest::accessLayersInvalidTextures() { Error redirectError{&out}; data.layerFactorTexture(1); data.layerFactorTexture("ClearCoat"); + data.layerFactorTexture(MaterialLayer::ClearCoat); data.layerFactorTextureSwizzle(1); data.layerFactorTextureSwizzle("ClearCoat"); + data.layerFactorTextureSwizzle(MaterialLayer::ClearCoat); data.layerFactorTextureMatrix(1); data.layerFactorTextureMatrix("ClearCoat"); + data.layerFactorTextureMatrix(MaterialLayer::ClearCoat); data.layerFactorTextureCoordinates(1); data.layerFactorTextureCoordinates("ClearCoat"); + data.layerFactorTextureCoordinates(MaterialLayer::ClearCoat); CORRADE_COMPARE(out.str(), "Trade::MaterialData::attribute(): attribute LayerFactorTexture not found in layer 1\n" "Trade::MaterialData::attribute(): attribute LayerFactorTexture not found in layer ClearCoat\n" + "Trade::MaterialData::attribute(): attribute LayerFactorTexture not found in layer ClearCoat\n" "Trade::MaterialData::layerFactorTextureSwizzle(): layer 1 doesn't have a factor texture\n" "Trade::MaterialData::layerFactorTextureSwizzle(): layer ClearCoat doesn't have a factor texture\n" + "Trade::MaterialData::layerFactorTextureSwizzle(): layer ClearCoat doesn't have a factor texture\n" "Trade::MaterialData::layerFactorTextureMatrix(): layer 1 doesn't have a factor texture\n" "Trade::MaterialData::layerFactorTextureMatrix(): layer ClearCoat doesn't have a factor texture\n" + "Trade::MaterialData::layerFactorTextureMatrix(): layer ClearCoat doesn't have a factor texture\n" "Trade::MaterialData::layerFactorTextureCoordinates(): layer 1 doesn't have a factor texture\n" + "Trade::MaterialData::layerFactorTextureCoordinates(): layer ClearCoat doesn't have a factor texture\n" "Trade::MaterialData::layerFactorTextureCoordinates(): layer ClearCoat doesn't have a factor texture\n"); } @@ -1873,6 +2028,33 @@ void MaterialDataTest::accessLayerIndexOptional() { CORRADE_COMPARE(data.attributeOr(1, MaterialAttribute::DiffuseTexture, 5u), 5); } +void MaterialDataTest::accessLayerNameOptional() { + MaterialData data{{}, { + {MaterialAttribute::DiffuseColor, 0x335566ff_rgbaf}, + {MaterialLayer::ClearCoat}, + {MaterialAttribute::AlphaMask, 0.5f}, + {MaterialAttribute::SpecularTexture, 3u} + }, {1, 4}}; + + /* This exists */ + CORRADE_VERIFY(data.tryAttribute(MaterialLayer::ClearCoat, "SpecularTexture")); + CORRADE_VERIFY(data.tryAttribute(MaterialLayer::ClearCoat, MaterialAttribute::SpecularTexture)); + CORRADE_COMPARE(*static_cast(data.tryAttribute(MaterialLayer::ClearCoat, "SpecularTexture")), 3); + CORRADE_COMPARE(*static_cast(data.tryAttribute(MaterialLayer::ClearCoat, MaterialAttribute::SpecularTexture)), 3); + CORRADE_COMPARE(data.tryAttribute(MaterialLayer::ClearCoat, "SpecularTexture"), 3); + CORRADE_COMPARE(data.tryAttribute(MaterialLayer::ClearCoat, MaterialAttribute::SpecularTexture), 3); + CORRADE_COMPARE(data.attributeOr(MaterialLayer::ClearCoat, "SpecularTexture", 5u), 3); + CORRADE_COMPARE(data.attributeOr(MaterialLayer::ClearCoat, MaterialAttribute::SpecularTexture, 5u), 3); + + /* This doesn't */ + CORRADE_VERIFY(!data.tryAttribute(MaterialLayer::ClearCoat, "DiffuseTexture")); + CORRADE_VERIFY(!data.tryAttribute(MaterialLayer::ClearCoat, MaterialAttribute::DiffuseTexture)); + CORRADE_VERIFY(!data.tryAttribute(MaterialLayer::ClearCoat, "DiffuseTexture")); + CORRADE_VERIFY(!data.tryAttribute(MaterialLayer::ClearCoat, MaterialAttribute::DiffuseTexture)); + CORRADE_COMPARE(data.attributeOr(MaterialLayer::ClearCoat, "DiffuseTexture", 5u), 5); + CORRADE_COMPARE(data.attributeOr(MaterialLayer::ClearCoat, MaterialAttribute::DiffuseTexture, 5u), 5); +} + void MaterialDataTest::accessLayerStringOptional() { MaterialData data{{}, { {MaterialAttribute::DiffuseColor, 0x335566ff_rgbaf}, @@ -2042,6 +2224,76 @@ void MaterialDataTest::accessLayerNotFound() { "Trade::MaterialData::attributeOr(): layer ClearCoat not found\n"); } +void MaterialDataTest::accessInvalidLayerName() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + MaterialData data{{}, {}}; + + std::ostringstream out; + Error redirectError{&out}; + data.layerId(MaterialLayer(0x0)); + data.layerId(MaterialLayer(0xfefe)); + data.layerFactor(MaterialLayer(0xfefe)); + data.layerFactorTexture(MaterialLayer(0xfefe)); + data.layerFactorTextureSwizzle(MaterialLayer(0xfefe)); + data.layerFactorTextureMatrix(MaterialLayer(0xfefe)); + data.layerFactorTextureCoordinates(MaterialLayer(0xfefe)); + data.attributeCount(MaterialLayer(0xfefe)); + data.hasAttribute(MaterialLayer(0xfefe), "AlphaMask"); + data.hasAttribute(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attributeId(MaterialLayer(0xfefe), "AlphaMask"); + data.attributeId(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attributeName(MaterialLayer(0xfefe), 0); + data.attributeType(MaterialLayer(0xfefe), 0); + data.attributeType(MaterialLayer(0xfefe), "AlphaMask"); + data.attributeType(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attribute(MaterialLayer(0xfefe), 0); + data.attribute(MaterialLayer(0xfefe), "AlphaMask"); + data.attribute(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attribute(MaterialLayer(0xfefe), 0); + data.attribute(MaterialLayer(0xfefe), "AlphaMask"); + data.attribute(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attribute(MaterialLayer(0xfefe), 0); + data.tryAttribute(MaterialLayer(0xfefe), "AlphaMask"); + data.tryAttribute(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.tryAttribute(MaterialLayer(0xfefe), "AlphaMask"); + data.tryAttribute(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask); + data.attributeOr(MaterialLayer(0xfefe), "AlphaMask", false); + data.attributeOr(MaterialLayer(0xfefe), MaterialAttribute::AlphaMask, false); + CORRADE_COMPARE(out.str(), + "Trade::MaterialData::layerId(): invalid name Trade::MaterialLayer(0x0)\n" + "Trade::MaterialData::layerId(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::layerFactor(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::layerFactorTexture(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::layerFactorTextureSwizzle(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::layerFactorTextureMatrix(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::layerFactorTextureCoordinates(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeCount(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::hasAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::hasAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeId(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeId(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeName(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeType(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeType(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeType(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::tryAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::tryAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::tryAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::tryAttribute(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeOr(): invalid name Trade::MaterialLayer(0xfefe)\n" + "Trade::MaterialData::attributeOr(): invalid name Trade::MaterialLayer(0xfefe)\n"); +} + void MaterialDataTest::accessOutOfBoundsInLayerIndex() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -3801,6 +4053,209 @@ void MaterialDataTest::flatAccessInvalidTextures() { "Trade::FlatMaterialData::textureCoordinates(): the material doesn't have a texture\n"); } +void MaterialDataTest::templateLayerAccess() { + MaterialLayerData data{{}, { + {MaterialAttribute::BaseColor, 0x335566ff_rgbaf}, + + {MaterialLayer::ClearCoat}, + {MaterialAttribute::LayerFactor, 0.35f}, + {MaterialAttribute::LayerFactorTexture, 3u}, + {MaterialAttribute::LayerFactorTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::LayerFactorTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::LayerFactorTextureCoordinates, 4u}, + }, {1, 7}}; + + CORRADE_COMPARE(data.layerName(), "ClearCoat"); + CORRADE_COMPARE(data.layerFactor(), 0.35f); + CORRADE_COMPARE(data.layerFactorTexture(), 3u); + CORRADE_COMPARE(data.layerFactorTextureSwizzle(), MaterialTextureSwizzle::B); + CORRADE_COMPARE(data.layerFactorTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.layerFactorTextureCoordinates(), 4u); + + CORRADE_COMPARE(data.attributeCount(), 6); + CORRADE_VERIFY(data.hasAttribute(MaterialAttribute::LayerFactor)); + CORRADE_VERIFY(data.hasAttribute("LayerFactorTexture")); + CORRADE_VERIFY(!data.hasAttribute(MaterialAttribute::BaseColor)); + CORRADE_VERIFY(!data.hasAttribute("BaseColor")); + CORRADE_VERIFY(data.hasAttribute(0, MaterialAttribute::BaseColor)); + CORRADE_VERIFY(data.hasAttribute(0, "BaseColor")); + + CORRADE_COMPARE(data.attributeId(MaterialAttribute::LayerFactorTexture), 2); + CORRADE_COMPARE(data.attributeId("LayerFactorTexture"), 2); + + CORRADE_COMPARE(data.attributeName(2), "LayerFactorTexture"); + + CORRADE_COMPARE(data.attributeType(2), MaterialAttributeType::UnsignedInt); + CORRADE_COMPARE(data.attributeType(MaterialAttribute::LayerFactorTexture), MaterialAttributeType::UnsignedInt); + CORRADE_COMPARE(data.attributeType("LayerFactorTexture"), MaterialAttributeType::UnsignedInt); + + CORRADE_COMPARE(*static_cast(data.attribute(2)), 3); + CORRADE_COMPARE(*static_cast(data.attribute(MaterialAttribute::LayerFactorTexture)), 3); + CORRADE_COMPARE(*static_cast(data.attribute("LayerFactorTexture")), 3); + + CORRADE_COMPARE(data.attribute(2), 3); + CORRADE_COMPARE(data.attribute(MaterialAttribute::LayerFactorTexture), 3); + CORRADE_COMPARE(data.attribute("LayerFactorTexture"), 3); + + CORRADE_COMPARE(*static_cast(data.tryAttribute(MaterialAttribute::LayerFactorTexture)), 3); + CORRADE_COMPARE(*static_cast(data.tryAttribute("LayerFactorTexture")), 3); + + CORRADE_COMPARE(data.tryAttribute(MaterialAttribute::LayerFactorTexture), 3); + CORRADE_COMPARE(data.tryAttribute("LayerFactorTexture"), 3); + + CORRADE_COMPARE(data.attributeOr(MaterialAttribute::LayerFactorTexture, 5u), 3); + CORRADE_COMPARE(data.attributeOr("LayerFactorTexture", 5u), 3); +} + +void MaterialDataTest::pbrClearCoatAccess() { + MaterialData base{MaterialType::PbrClearCoat, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::Roughness, 0.7f} + }, {0, 2}}; + + CORRADE_COMPARE(base.types(), MaterialType::PbrClearCoat); + const auto& data = base.as(); + + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.roughness(), 0.7f); +} + +void MaterialDataTest::pbrClearCoatAccessDefaults() { + MaterialData base{{}, { + /* Needs to have at least the layer name, otherwise the queries will + blow up */ + {MaterialLayer::ClearCoat} + }, {0, 1}}; + + CORRADE_COMPARE(base.types(), MaterialTypes{}); + const auto& data = base.as(); + + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.layerFactor(), 1.0f); + CORRADE_COMPARE(data.roughness(), 0.0f); +} + +void MaterialDataTest::pbrClearCoatAccessTextured() { + PbrClearCoatMaterialData data{{}, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::Roughness, 0.7f}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::translation({2.0f, 1.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 6u}, + {MaterialAttribute::NormalTexture, 3u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::NormalTextureMatrix, Matrix3::translation({0.0f, 0.5f})}, + {MaterialAttribute::NormalTextureCoordinates, 7u}, + }, {0, 10}}; + + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.roughness(), 0.7f); + CORRADE_COMPARE(data.roughnessTexture(), 2u); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::translation({2.0f, 1.5f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 6u); + CORRADE_COMPARE(data.normalTexture(), 3u); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::B); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 7u); +} + +void MaterialDataTest::pbrClearCoatAccessTexturedDefaults() { + PbrClearCoatMaterialData data{{}, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::NormalTexture, 3u}, + }, {0, 3}}; + + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.roughness(), 0.0f); + CORRADE_COMPARE(data.roughnessTexture(), 2u); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 0u); + CORRADE_COMPARE(data.normalTexture(), 3u); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.normalTextureCoordinates(), 0u); +} + +void MaterialDataTest::pbrClearCoatAccessTexturedSingleMatrixCoordinates() { + PbrClearCoatMaterialData data{{}, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::NormalTexture, 3u}, + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.0f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u}, + }, {0, 5}}; + + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 7u); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 7u); +} + +void MaterialDataTest::pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates() { + PbrClearCoatMaterialData data{{}, { + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.0f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u}, + + {MaterialLayer::ClearCoat}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::NormalTexture, 3u}, + }, {2, 5}}; + + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 7u); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 7u); +} + +void MaterialDataTest::pbrClearCoatAccessInvalidTextures() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrClearCoatMaterialData data{{}, { + {MaterialLayer::ClearCoat}, + }, {0, 1}}; + + std::ostringstream out; + Error redirectError{&out}; + data.roughnessTexture(); + data.roughnessTextureSwizzle(); + data.roughnessTextureMatrix(); + data.roughnessTextureCoordinates(); + data.normalTexture(); + data.normalTextureSwizzle(); + data.normalTextureMatrix(); + data.normalTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::MaterialData::attribute(): attribute RoughnessTexture not found in layer ClearCoat\n" + "Trade::PbrClearCoatMaterialData::roughnessTextureSwizzle(): the layer doesn't have a roughness texture\n" + "Trade::PbrClearCoatMaterialData::roughnessTextureMatrix(): the layer doesn't have a roughness texture\n" + "Trade::PbrClearCoatMaterialData::roughnessTextureCoordinates(): the layer doesn't have a roughness texture\n" + "Trade::MaterialData::attribute(): attribute NormalTexture not found in layer ClearCoat\n" + "Trade::PbrClearCoatMaterialData::normalTextureSwizzle(): the layer doesn't have a normal texture\n" + "Trade::PbrClearCoatMaterialData::normalTextureMatrix(): the layer doesn't have a normal texture\n" + "Trade::PbrClearCoatMaterialData::normalTextureCoordinates(): the layer doesn't have a normal texture\n"); +} + +void MaterialDataTest::debugLayer() { + std::ostringstream out; + + Debug{&out} << MaterialLayer::ClearCoat << MaterialLayer(0xfefe) << MaterialLayer{}; + CORRADE_COMPARE(out.str(), "Trade::MaterialLayer::ClearCoat Trade::MaterialLayer(0xfefe) Trade::MaterialLayer(0x0)\n"); +} + void MaterialDataTest::debugAttribute() { std::ostringstream out; diff --git a/src/Magnum/Trade/Trade.h b/src/Magnum/Trade/Trade.h index 0b0e07cdd..dac3bb738 100644 --- a/src/Magnum/Trade/Trade.h +++ b/src/Magnum/Trade/Trade.h @@ -51,6 +51,7 @@ typedef CORRADE_DEPRECATED("use InputFileCallbackPolicy instead") InputFileCallb enum class MaterialAttribute: UnsignedInt; enum class MaterialTextureSwizzle: UnsignedInt; enum class MaterialAttributeType: UnsignedByte; +enum class MaterialLayer: UnsignedInt; enum class MaterialType: UnsignedInt; enum class MaterialAlphaMode: UnsignedByte; class MaterialAttributeData; @@ -92,6 +93,7 @@ class MeshObjectData2D; class MeshObjectData3D; class ObjectData2D; class ObjectData3D; +class PbrClearCoatMaterialData; class PbrMetallicRoughnessMaterialData; class PbrSpecularGlossinessMaterialData; class PhongMaterialData;