diff --git a/doc/changelog.dox b/doc/changelog.dox index 1c672a5b9..f86b8a614 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -105,15 +105,17 @@ See also: @subsubsection changelog-latest-changes-trade Trade library - Recognizing TIFF file header magic in @ref Trade::AnyImageImporter "AnyImageImporter" -- Added @ref Trade::PhongMaterialData::ambientTextureMatrix(), +- Added @ref Trade::PhongMaterialData::hasCommonTextureTransformation(), + @ref Trade::PhongMaterialData::ambientTextureMatrix(), @ref Trade::PhongMaterialData::diffuseTextureMatrix(), @ref Trade::PhongMaterialData::specularTextureMatrix() and @ref Trade::PhongMaterialData::normalTextureMatrix() exposing also per-texture coordinate transformation, similarly to per-texture coordinate sets added in 2020.06 -- Added @ref Trade::PhongMaterialData::textureCoordinates() exposing a common - texture coordinate set as a complement to a per-texture property added in - 2020.06 +- Added @ref Trade::PhongMaterialData::hasCommonTextureCoordinates() and + @ref Trade::PhongMaterialData::commonTextureCoordinates() exposing a + common texture coordinate set as a complement to a per-texture property + added in 2020.06 @subsection changelog-latest-buildsystem Build system @@ -151,6 +153,10 @@ See also: and @ref Trade::PhongMaterialData::normalTextureCoordinates() "normalTextureCoordinates()" - @ref Trade::PhongMaterialData constructor is deprecated as the designated way is to populate the @ref Trade::MaterialData class directly instead. +- @cpp Trade::PhongMaterialData::textureMatrix() @ce is deprecated in favor + of @ref Trade::PhongMaterialData::hasCommonTextureTransformation() and + @ref Trade::PhongMaterialData::commonTextureMatrix(), which do proper + checking and fallback in case a per-texture transformation is present - @cpp Trade::MaterialData::type() @ce (coming from the original `AbstractMaterialData` class) is deprecated in favor of @ref Trade::MaterialData::types(), as a material data can now contain diff --git a/doc/snippets/MagnumTrade.cpp b/doc/snippets/MagnumTrade.cpp index 61eb9b3c5..4baf08cd9 100644 --- a/doc/snippets/MagnumTrade.cpp +++ b/doc/snippets/MagnumTrade.cpp @@ -309,29 +309,28 @@ if(data.types() & Trade::MaterialType::PbrSpecularGlossiness) { } { -/* [MaterialData-usage-packing] */ +/* [MaterialData-usage-texture-complexity] */ Trade::PbrSpecularGlossinessMaterialData data = DOXYGEN_IGNORE(Trade::PbrSpecularGlossinessMaterialData{{}, {}}); -/* Use a shader that accepts a single packed metallic/roughness texture. - Querying any texture attributes will give the same values for both metalness - and roughness. */ -if(data.hasSpecularGlossinessTexture()) { +/* Simple case for diffuse + packed specular/glossiness texture, the default + coordinate set and a common coordinate transformation for all textures */ +if(data.hasAttribute(Trade::MaterialAttribute::DiffuseTexture) && + data.hasSpecularGlossinessTexture() && + data.hasCommonTextureTransformation() && !data.hasTextureCoordinates()) +{ + UnsignedInt diffuse = data.diffuseTexture(); UnsignedInt specularGlossiness = data.specularTexture(); + Matrix3 textureMatrix = data.commonTextureMatrix(); - DOXYGEN_IGNORE(static_cast(specularGlossiness);) + DOXYGEN_IGNORE(static_cast(diffuse), static_cast(specularGlossiness), static_cast(textureMatrix);) -/* Supply texture channels separately */ -} else { - UnsignedInt specular = data.specularTexture(); - UnsignedInt glossiness = data.glossinessTexture(); - Trade::MaterialTextureSwizzle specularSwizzle = - data.specularTextureSwizzle(); - Trade::MaterialTextureSwizzle glossinessSwizzle = - data.glossinessTextureSwizzle(); +/* Extra work needed when using a non-default texture coordinate set */ +} else if(data.hasTextureCoordinates() && data.hasCommonTextureCoordinates()) { + DOXYGEN_IGNORE() - DOXYGEN_IGNORE(static_cast(specular), static_cast(glossiness), static_cast(specularSwizzle), static_cast(glossinessSwizzle);) -} -/* [MaterialData-usage-packing] */ +/* Etc... */ +} else Fatal{} << "Material too complex, giving up"; +/* [MaterialData-usage-texture-complexity] */ } { diff --git a/src/Magnum/Trade/FlatMaterialData.h b/src/Magnum/Trade/FlatMaterialData.h index eb5b4ff18..9e52a4129 100644 --- a/src/Magnum/Trade/FlatMaterialData.h +++ b/src/Magnum/Trade/FlatMaterialData.h @@ -80,6 +80,10 @@ class MAGNUM_TRADE_EXPORT FlatMaterialData: public MaterialData { */ bool hasTextureTransformation() const; + /* Since there's just one texture, no need for any + hasCommonTextureTransformation(), hasCommonTextureCoordinates(), + commonTextureMatrix() or commonTextureCoordinates() APIs */ + /** * @brief Whether the material uses extra texture coordinate sets * diff --git a/src/Magnum/Trade/MaterialData.h b/src/Magnum/Trade/MaterialData.h index 8bd106397..bdc1873e6 100644 --- a/src/Magnum/Trade/MaterialData.h +++ b/src/Magnum/Trade/MaterialData.h @@ -858,9 +858,15 @@ enum class MaterialAttribute: UnsignedInt { * @ref MaterialAttribute::EmissiveTextureMatrix / * @ref MaterialAttribute::LayerFactorTextureMatrix have a precedence over * this attribute for given texture, if present. - * @see @ref PhongMaterialData::textureMatrix(), - * @ref PbrMetallicRoughnessMaterialData::textureMatrix(), - * @ref PbrSpecularGlossinessMaterialData::textureMatrix() + * @see @ref PhongMaterialData::hasCommonTextureTransformation(), + * @ref PbrMetallicRoughnessMaterialData::hasCommonTextureTransformation(), + * @ref PbrSpecularGlossinessMaterialData::hasCommonTextureTransformation(), + * @ref PbrClearCoatMaterialData::hasCommonTextureTransformation(), + * @ref PhongMaterialData::commonTextureMatrix(), + * @ref PbrMetallicRoughnessMaterialData::commonTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::commonTextureMatrix(), + * @ref PbrClearCoatMaterialData::commonTextureMatrix(), + * @ref FlatMaterialData::textureMatrix() */ TextureMatrix, @@ -879,9 +885,15 @@ enum class MaterialAttribute: UnsignedInt { * @ref MaterialAttribute::EmissiveTextureCoordinates / * @ref MaterialAttribute::LayerFactorTextureCoordinates have a precedence * over this attribute for given texture, if present. - * @see @ref PhongMaterialData::textureCoordinates(), - * @ref PbrMetallicRoughnessMaterialData::textureCoordinates(), - * @ref PbrSpecularGlossinessMaterialData::textureCoordinates() + * @see @ref PhongMaterialData::hasCommonTextureCoordinates(), + * @ref PbrMetallicRoughnessMaterialData::hasCommonTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::hasCommonTextureCoordinates(), + * @ref PbrClearCoatMaterialData::hasCommonTextureCoordinates(), + * @ref PhongMaterialData::commonTextureCoordinates(), + * @ref PbrMetallicRoughnessMaterialData::commonTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::commonTextureCoordinates(), + * @ref PbrClearCoatMaterialData::commonTextureCoordinates(), + * @ref FlatMaterialData::textureCoordinates() */ TextureCoordinates, }; @@ -1462,18 +1474,21 @@ in multiple ways: Each @ref MaterialAttribute is exposed through one or more of those convenience APIs, see the documentation of of a particular enum value for more information. -@subsection Trade-MaterialData-usage-packing Texture packing +@subsection Trade-MaterialData-usage-texture-complexity Texture packing, coordinate transformation and coordinate sets -Especially for single- and two-channel texture maps it's common to have more -than one map packed into a single texture. Such packing is expressed through -various @ref MaterialTextureSwizzle attributes such as -@ref MaterialAttribute::MetalnessTextureSwizzle. While this provides an almost -endless variability, real-world textures are in just a few common packing -schemes. For convenience these have dedicated attributes such as -@ref MaterialAttribute::SpecularGlossinessTexture and can also be checked -for with for example @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture(): +The material APIs allow for a lot of flexibility regarding --- texture maps may +be arbitrarily packed together to efficiently use all four channels, each +texture can be using a different set of texture coordinates and there can be +a different coordinate transformation for each texture. -@snippet MagnumTrade.cpp MaterialData-usage-packing +In most cases, however, real-world textures fit into a few well-known packing +schemes and usually have a common transformation and coordinate sets for all. +Checking for all corner cases on the application side would be a headache, so +there are queries like @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture() or +@ref PbrSpecularGlossinessMaterialData::hasCommonTextureTransformation() to +help narrowing the options down: + +@snippet MagnumTrade.cpp MaterialData-usage-texture-complexity @subsection Trade-MaterialData-usage-layers Material layers diff --git a/src/Magnum/Trade/PbrClearCoatMaterialData.cpp b/src/Magnum/Trade/PbrClearCoatMaterialData.cpp index ec9a6bf09..87761a247 100644 --- a/src/Magnum/Trade/PbrClearCoatMaterialData.cpp +++ b/src/Magnum/Trade/PbrClearCoatMaterialData.cpp @@ -35,6 +35,27 @@ bool PbrClearCoatMaterialData::hasTextureTransformation() const { hasAttribute(0, MaterialAttribute::TextureMatrix); } +bool PbrClearCoatMaterialData::hasCommonTextureTransformation() const { + auto check = [](Containers::Optional& transformation, Matrix3 current) { + if(!transformation) { + transformation = current; + return true; + } + return transformation == current; + }; + + Containers::Optional transformation; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::LayerFactorTexture) && !check(transformation, layerFactorTextureMatrix())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasAttribute(MaterialAttribute::RoughnessTexture) && !check(transformation, roughnessTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(transformation, normalTextureMatrix())) + return false; + + return true; +} + bool PbrClearCoatMaterialData::hasTextureCoordinates() const { return hasAttribute(MaterialAttribute::LayerFactorTextureCoordinates) || hasAttribute(MaterialAttribute::RoughnessTextureCoordinates) || @@ -43,6 +64,27 @@ bool PbrClearCoatMaterialData::hasTextureCoordinates() const { hasAttribute(0, MaterialAttribute::TextureCoordinates); } +bool PbrClearCoatMaterialData::hasCommonTextureCoordinates() const { + auto check = [](Containers::Optional& coordinates, UnsignedInt current) { + if(!coordinates) { + coordinates = current; + return true; + } + return coordinates == current; + }; + + Containers::Optional coordinates; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::LayerFactorTexture) && !check(coordinates, layerFactorTextureCoordinates())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasAttribute(MaterialAttribute::RoughnessTexture) && !check(coordinates, roughnessTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(coordinates, normalTextureCoordinates())) + return false; + + return true; +} + Float PbrClearCoatMaterialData::roughness() const { return attributeOr(MaterialAttribute::Roughness, 0.0f); } @@ -113,4 +155,32 @@ UnsignedInt PbrClearCoatMaterialData::normalTextureCoordinates() const { return attributeOr(0, MaterialAttribute::TextureCoordinates, 0u); } +Matrix3 PbrClearCoatMaterialData::commonTextureMatrix() const { + CORRADE_ASSERT(hasCommonTextureTransformation(), + "Trade::PbrClearCoatMaterialData::commonTextureMatrix(): the layer doesn't have a common texture coordinate transformation", {}); + if(hasAttribute(MaterialAttribute::LayerFactorTexture)) + return layerFactorTextureMatrix(); + if(hasAttribute(MaterialAttribute::RoughnessTexture)) + return roughnessTextureMatrix(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureMatrix(); + if(Containers::Optional value = tryAttribute(MaterialAttribute::TextureMatrix)) + return *value; + return attributeOr(0, MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrClearCoatMaterialData::commonTextureCoordinates() const { + CORRADE_ASSERT(hasCommonTextureCoordinates(), + "Trade::PbrClearCoatMaterialData::commonTextureCoordinates(): the layer doesn't have a common texture coordinate set", {}); + if(hasAttribute(MaterialAttribute::LayerFactorTexture)) + return layerFactorTextureCoordinates(); + if(hasAttribute(MaterialAttribute::RoughnessTexture)) + return roughnessTextureCoordinates(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureCoordinates(); + 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 index 454d27488..9323581e8 100644 --- a/src/Magnum/Trade/PbrClearCoatMaterialData.h +++ b/src/Magnum/Trade/PbrClearCoatMaterialData.h @@ -69,6 +69,18 @@ class MAGNUM_TRADE_EXPORT PbrClearCoatMaterialData: public MaterialLayerData& transformation, Matrix3 current) { + if(!transformation) { + transformation = current; + return true; + } + return transformation == current; + }; + + Containers::Optional transformation; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::BaseColorTexture) && !check(transformation, baseColorTextureMatrix())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasMetalnessTexture() && !check(transformation, metalnessTextureMatrix())) + return false; + if(hasRoughnessTexture() && !check(transformation, roughnessTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(transformation, normalTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::OcclusionTexture) && !check(transformation, occlusionTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::EmissiveTexture) && !check(transformation, emissiveTextureMatrix())) + return false; + + return true; +} + bool PbrMetallicRoughnessMaterialData::hasTextureCoordinates() const { return hasAttribute(MaterialAttribute::TextureCoordinates) || hasAttribute(MaterialAttribute::BaseColorTextureCoordinates) || @@ -123,6 +150,33 @@ bool PbrMetallicRoughnessMaterialData::hasTextureCoordinates() const { hasAttribute(MaterialAttribute::EmissiveTextureCoordinates); } +bool PbrMetallicRoughnessMaterialData::hasCommonTextureCoordinates() const { + auto check = [](Containers::Optional& coordinates, UnsignedInt current) { + if(!coordinates) { + coordinates = current; + return true; + } + return coordinates == current; + }; + + Containers::Optional coordinates; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::BaseColorTexture) && !check(coordinates, baseColorTextureCoordinates())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasMetalnessTexture() && !check(coordinates, metalnessTextureCoordinates())) + return false; + if(hasRoughnessTexture() && !check(coordinates, roughnessTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(coordinates, normalTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::OcclusionTexture) && !check(coordinates, occlusionTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::EmissiveTexture) && !check(coordinates, emissiveTextureCoordinates())) + return false; + + return true; +} + Color4 PbrMetallicRoughnessMaterialData::baseColor() const { return attributeOr(MaterialAttribute::BaseColor, 0xffffffff_rgbaf); } @@ -311,11 +365,39 @@ UnsignedInt PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates() const return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } -Matrix3 PbrMetallicRoughnessMaterialData::textureMatrix() const { +Matrix3 PbrMetallicRoughnessMaterialData::commonTextureMatrix() const { + CORRADE_ASSERT(hasCommonTextureTransformation(), + "Trade::PbrMetallicRoughnessMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation", {}); + if(hasAttribute(MaterialAttribute::BaseColorTexture)) + return baseColorTextureMatrix(); + if(hasMetalnessTexture()) + return metalnessTextureMatrix(); + if(hasRoughnessTexture()) + return roughnessTextureMatrix(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureMatrix(); + if(hasAttribute(MaterialAttribute::OcclusionTexture)) + return occlusionTextureMatrix(); + if(hasAttribute(MaterialAttribute::EmissiveTexture)) + return emissiveTextureMatrix(); return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); } -UnsignedInt PbrMetallicRoughnessMaterialData::textureCoordinates() const { +UnsignedInt PbrMetallicRoughnessMaterialData::commonTextureCoordinates() const { + CORRADE_ASSERT(hasCommonTextureCoordinates(), + "Trade::PbrMetallicRoughnessMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set", {}); + if(hasAttribute(MaterialAttribute::BaseColorTexture)) + return baseColorTextureCoordinates(); + if(hasMetalnessTexture()) + return metalnessTextureCoordinates(); + if(hasRoughnessTexture()) + return roughnessTextureCoordinates(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureCoordinates(); + if(hasAttribute(MaterialAttribute::OcclusionTexture)) + return occlusionTextureCoordinates(); + if(hasAttribute(MaterialAttribute::EmissiveTexture)) + return emissiveTextureCoordinates(); return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } diff --git a/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h index 0d5bd67d1..328212ed3 100644 --- a/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h +++ b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h @@ -246,9 +246,23 @@ class MAGNUM_TRADE_EXPORT PbrMetallicRoughnessMaterialData: public MaterialData * @ref MaterialAttribute::EmissiveTextureMatrix or * @ref MaterialAttribute::TextureMatrix attributes is present, * @cpp false @ce otherwise. + * @see @ref hasCommonTextureTransformation() */ bool hasTextureTransformation() const; + /** + * @brief Whether the material has a common transformation for all textures + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref baseColorTextureMatrix(), @ref metalnessTextureMatrix(), + * @ref roughnessTextureMatrix(), @ref normalTextureMatrix(), + * @ref occlusionTextureMatrix() and @ref emissiveTextureMatrix() have + * the same value, @cpp false @ce otherwise. In particular, returns + * @cpp true @ce also if there's no texture transformation at all. Use + * @ref hasTextureTransformation() to distinguish that case. + */ + bool hasCommonTextureTransformation() const; + /** * @brief Whether the material uses extra texture coordinate sets * @@ -261,9 +275,24 @@ class MAGNUM_TRADE_EXPORT PbrMetallicRoughnessMaterialData: public MaterialData * @ref MaterialAttribute::EmissiveTextureCoordinates or * @ref MaterialAttribute::TextureCoordinates attributes is present and * has a non-zero value, @cpp false @ce otherwise. + * @see @ref hasCommonTextureCoordinates() */ bool hasTextureCoordinates() const; + /** + * @brief Whether the material has a common coordinate set for all textures + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref baseColorTextureCoordinates(), @ref metalnessTextureCoordinates(), + * @ref roughnessTextureCoordinates(), @ref normalTextureCoordinates(), + * @ref occlusionTextureCoordinates() and @ref emissiveTextureCoordinates() + * have the same value, @cpp false @ce otherwise. In particular, + * returns @cpp true @ce also if there's no extra texture coordinate + * set used at all. Use @ref hasTextureCoordinates() to distinguish + * that case. + */ + bool hasCommonTextureCoordinates() const; + /** * @brief Base color * @@ -570,44 +599,28 @@ class MAGNUM_TRADE_EXPORT PbrMetallicRoughnessMaterialData: public MaterialData /** * @brief Common texture coordinate transformation matrix for all textures * - * Convenience access to the @ref MaterialAttribute::TextureMatrix - * attribute. If not present, the default is an identity matrix. Note - * that the material may also define per-texture transformation using - * the @ref MaterialAttribute::BaseColorTextureMatrix, - * @ref MaterialAttribute::MetalnessTextureMatrix, - * @ref MaterialAttribute::RoughnessTextureMatrix, - * @ref MaterialAttribute::NormalTextureMatrix, - * @ref MaterialAttribute::OcclusionTextureMatrix and - * @ref MaterialAttribute::EmissiveTextureMatrix attributes, which then - * take precedence over the common one. - * @see @ref hasAttribute(), @ref baseColorTextureMatrix(), - * @ref metalnessTextureMatrix(), @ref roughnessTextureMatrix(), - * @ref normalTextureMatrix(), @ref occlusionTextureMatrix(), - * @ref emissiveTextureMatrix() + * Expects that @ref hasCommonTextureTransformation() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref baseColorTextureMatrix(), @ref metalnessTextureMatrix(), + * @ref roughnessTextureMatrix(), @ref normalTextureMatrix(), + * @ref occlusionTextureMatrix() and @ref emissiveTextureMatrix() where + * a texture is present. If no texture is present, returns an identity + * matrix. */ - Matrix3 textureMatrix() const; + Matrix3 commonTextureMatrix() const; /** * @brief Common texture coordinate set index for all textures * - * Convenience access to the @ref MaterialAttribute::TextureCoordinates - * attribute. If not present, the default is @cpp 0 @ce. Note that the - * material may also define per-texture coordinate set using the - * @ref MaterialAttribute::BaseColorTextureCoordinates, - * @ref MaterialAttribute::MetalnessTextureCoordinates, - * @ref MaterialAttribute::RoughnessTextureCoordinates, - * @ref MaterialAttribute::NormalTextureCoordinates, - * @ref MaterialAttribute::OcclusionTextureCoordinates and - * @ref MaterialAttribute::EmissiveTextureCoordinates attributes, which - * then take precedence over the common one. - * @see @ref hasAttribute(), @ref baseColorTextureCoordinates(), - * @ref metalnessTextureCoordinates(), - * @ref roughnessTextureCoordinates(), - * @ref normalTextureCoordinates(), - * @ref occlusionTextureCoordinates(), - * @ref emissiveTextureCoordinates() - */ - UnsignedInt textureCoordinates() const; + * Expects that @ref hasCommonTextureCoordinates() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref baseColorTextureCoordinates(), @ref metalnessTextureCoordinates(), + * @ref roughnessTextureCoordinates(), @ref normalTextureCoordinates(), + * @ref occlusionTextureCoordinates() and @ref emissiveTextureCoordinates() + * where a texture is present. If no texture is present, returns + * @cpp 0 @ce. + */ + UnsignedInt commonTextureCoordinates() const; }; }} diff --git a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp index d137882c1..083cdc171 100644 --- a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp +++ b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp @@ -62,6 +62,33 @@ bool PbrSpecularGlossinessMaterialData::hasTextureTransformation() const { hasAttribute(MaterialAttribute::EmissiveTextureMatrix); } +bool PbrSpecularGlossinessMaterialData::hasCommonTextureTransformation() const { + auto check = [](Containers::Optional& transformation, Matrix3 current) { + if(!transformation) { + transformation = current; + return true; + } + return transformation == current; + }; + + Containers::Optional transformation; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::DiffuseTexture) && !check(transformation, diffuseTextureMatrix())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasSpecularTexture() && !check(transformation, specularTextureMatrix())) + return false; + if(hasGlossinessTexture() && !check(transformation, glossinessTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(transformation, normalTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::OcclusionTexture) && !check(transformation, occlusionTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::EmissiveTexture) && !check(transformation, emissiveTextureMatrix())) + return false; + + return true; +} + bool PbrSpecularGlossinessMaterialData::hasTextureCoordinates() const { return hasAttribute(MaterialAttribute::TextureCoordinates) || hasAttribute(MaterialAttribute::DiffuseTextureCoordinates) || @@ -72,6 +99,33 @@ bool PbrSpecularGlossinessMaterialData::hasTextureCoordinates() const { hasAttribute(MaterialAttribute::EmissiveTextureCoordinates); } +bool PbrSpecularGlossinessMaterialData::hasCommonTextureCoordinates() const { + auto check = [](Containers::Optional& coordinates, UnsignedInt current) { + if(!coordinates) { + coordinates = current; + return true; + } + return coordinates == current; + }; + + Containers::Optional coordinates; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::DiffuseTexture) && !check(coordinates, diffuseTextureCoordinates())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasSpecularTexture() && !check(coordinates, specularTextureCoordinates())) + return false; + if(hasGlossinessTexture() && !check(coordinates, glossinessTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(coordinates, normalTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::OcclusionTexture) && !check(coordinates, occlusionTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::EmissiveTexture) && !check(coordinates, emissiveTextureCoordinates())) + return false; + + return true; +} + Color4 PbrSpecularGlossinessMaterialData::diffuseColor() const { return attributeOr(MaterialAttribute::DiffuseColor, 0xffffffff_srgbaf); } @@ -260,11 +314,39 @@ UnsignedInt PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates() cons return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } -Matrix3 PbrSpecularGlossinessMaterialData::textureMatrix() const { +Matrix3 PbrSpecularGlossinessMaterialData::commonTextureMatrix() const { + CORRADE_ASSERT(hasCommonTextureTransformation(), + "Trade::PbrSpecularGlossinessMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation", {}); + if(hasAttribute(MaterialAttribute::DiffuseTexture)) + return diffuseTextureMatrix(); + if(hasSpecularTexture()) + return specularTextureMatrix(); + if(hasGlossinessTexture()) + return glossinessTextureMatrix(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureMatrix(); + if(hasAttribute(MaterialAttribute::OcclusionTexture)) + return occlusionTextureMatrix(); + if(hasAttribute(MaterialAttribute::EmissiveTexture)) + return emissiveTextureMatrix(); return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); } -UnsignedInt PbrSpecularGlossinessMaterialData::textureCoordinates() const { +UnsignedInt PbrSpecularGlossinessMaterialData::commonTextureCoordinates() const { + CORRADE_ASSERT(hasCommonTextureCoordinates(), + "Trade::PbrSpecularGlossinessMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set", {}); + if(hasAttribute(MaterialAttribute::DiffuseTexture)) + return diffuseTextureCoordinates(); + if(hasSpecularTexture()) + return specularTextureCoordinates(); + if(hasGlossinessTexture()) + return glossinessTextureCoordinates(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureCoordinates(); + if(hasAttribute(MaterialAttribute::OcclusionTexture)) + return occlusionTextureCoordinates(); + if(hasAttribute(MaterialAttribute::EmissiveTexture)) + return emissiveTextureCoordinates(); return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } diff --git a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h index 753bae0ae..39b6ec6f3 100644 --- a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h +++ b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h @@ -116,9 +116,23 @@ class MAGNUM_TRADE_EXPORT PbrSpecularGlossinessMaterialData: public MaterialData * @ref MaterialAttribute::EmissiveTextureMatrix or * @ref MaterialAttribute::TextureMatrix attributes is present, * @cpp false @ce otherwise. + * @see @ref hasCommonTextureTransformation() */ bool hasTextureTransformation() const; + /** + * @brief Whether the material has a common transformation for all textures + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref diffuseTextureMatrix(), @ref specularTextureMatrix(), + * @ref glossinessTextureMatrix(), @ref normalTextureMatrix(), + * @ref occlusionTextureMatrix() and @ref emissiveTextureMatrix() have + * the same value, @cpp false @ce otherwise. In particular, returns + * @cpp true @ce also if there's no texture transformation at all. Use + * @ref hasTextureTransformation() to distinguish that case. + */ + bool hasCommonTextureTransformation() const; + /** * @brief Whether the material uses extra texture coordinate sets * @@ -134,6 +148,20 @@ class MAGNUM_TRADE_EXPORT PbrSpecularGlossinessMaterialData: public MaterialData */ bool hasTextureCoordinates() const; + /** + * @brief Whether the material has a common coordinate set for all textures + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref diffuseTextureCoordinates(), @ref specularTextureCoordinates(), + * @ref glossinessTextureCoordinates(), @ref normalTextureCoordinates(), + * @ref occlusionTextureCoordinates() and @ref emissiveTextureCoordinates() + * have the same value, @cpp false @ce otherwise. In particular, + * returns @cpp true @ce also if there's no extra texture coordinate + * set used at all. Use @ref hasTextureCoordinates() to distinguish + * that case. + */ + bool hasCommonTextureCoordinates() const; + /** * @brief Base color * @@ -439,44 +467,28 @@ class MAGNUM_TRADE_EXPORT PbrSpecularGlossinessMaterialData: public MaterialData /** * @brief Common texture coordinate transformation matrix for all textures * - * Convenience access to the @ref MaterialAttribute::TextureMatrix - * attribute. If not present, the default is an identity matrix. Note - * that the material may also define per-texture transformation using - * the @ref MaterialAttribute::DiffuseTextureMatrix, - * @ref MaterialAttribute::SpecularTextureMatrix, - * @ref MaterialAttribute::GlossinessTextureMatrix, - * @ref MaterialAttribute::NormalTextureMatrix, - * @ref MaterialAttribute::OcclusionTextureMatrix and - * @ref MaterialAttribute::EmissiveTextureMatrix attributes, which then - * take precedence over the common one. - * @see @ref hasAttribute(), @ref diffuseTextureMatrix(), - * @ref specularTextureMatrix(), @ref glossinessTextureMatrix(), - * @ref normalTextureMatrix(), @ref occlusionTextureMatrix(), - * @ref emissiveTextureMatrix() + * Expects that @ref hasCommonTextureTransformation() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref diffuseTextureMatrix(), @ref specularTextureMatrix(), + * @ref glossinessTextureMatrix(), @ref normalTextureMatrix(), + * @ref occlusionTextureMatrix() and @ref emissiveTextureMatrix() where + * a texture is present. If no texture is present, returns an identity + * matrix. */ - Matrix3 textureMatrix() const; + Matrix3 commonTextureMatrix() const; /** * @brief Common texture coordinate set index for all textures * - * Convenience access to the @ref MaterialAttribute::TextureCoordinates - * attribute. If not present, the default is @cpp 0 @ce. Note that the - * material may also define per-texture coordinate set using the - * @ref MaterialAttribute::DiffuseTextureCoordinates, - * @ref MaterialAttribute::SpecularTextureCoordinates, - * @ref MaterialAttribute::GlossinessTextureCoordinates, - * @ref MaterialAttribute::NormalTextureCoordinates, - * @ref MaterialAttribute::OcclusionTextureCoordinates and - * @ref MaterialAttribute::EmissiveTextureCoordinates attributes, which - * then take precedence over the common one. - * @see @ref hasAttribute(), @ref diffuseTextureCoordinates(), - * @ref specularTextureCoordinates(), - * @ref glossinessTextureCoordinates(), - * @ref normalTextureCoordinates(), - * @ref occlusionTextureCoordinates(), - * @ref emissiveTextureCoordinates() - */ - UnsignedInt textureCoordinates() const; + * Expects that @ref hasCommonTextureCoordinates() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref diffuseTextureCoordinates(), @ref specularTextureCoordinates(), + * @ref glossinessTextureCoordinates(), @ref normalTextureCoordinates(), + * @ref occlusionTextureCoordinates() and @ref emissiveTextureCoordinates() + * where a texture is present. If no texture is present, returns + * @cpp 0 @ce. + */ + UnsignedInt commonTextureCoordinates() const; }; }} diff --git a/src/Magnum/Trade/PhongMaterialData.cpp b/src/Magnum/Trade/PhongMaterialData.cpp index 8e8a5f929..044786256 100644 --- a/src/Magnum/Trade/PhongMaterialData.cpp +++ b/src/Magnum/Trade/PhongMaterialData.cpp @@ -142,6 +142,29 @@ bool PhongMaterialData::hasTextureTransformation() const { hasAttribute(MaterialAttribute::TextureMatrix); } +bool PhongMaterialData::hasCommonTextureTransformation() const { + auto check = [](Containers::Optional& transformation, Matrix3 current) { + if(!transformation) { + transformation = current; + return true; + } + return transformation == current; + }; + + Containers::Optional transformation; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::AmbientTexture) && !check(transformation, ambientTextureMatrix())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasAttribute(MaterialAttribute::DiffuseTexture) && !check(transformation, diffuseTextureMatrix())) + return false; + if(hasSpecularTexture() && !check(transformation, specularTextureMatrix())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(transformation, normalTextureMatrix())) + return false; + + return true; +} + bool PhongMaterialData::hasTextureCoordinates() const { return attributeOr(MaterialAttribute::AmbientTextureCoordinates, 0u) || attributeOr(MaterialAttribute::DiffuseTextureCoordinates, 0u) || @@ -150,6 +173,29 @@ bool PhongMaterialData::hasTextureCoordinates() const { attributeOr(MaterialAttribute::TextureCoordinates, 0u); } +bool PhongMaterialData::hasCommonTextureCoordinates() const { + auto check = [](Containers::Optional& coordinates, UnsignedInt current) { + if(!coordinates) { + coordinates = current; + return true; + } + return coordinates == current; + }; + + Containers::Optional coordinates; + /* First one can't fail */ + if(hasAttribute(MaterialAttribute::AmbientTexture) && !check(coordinates, ambientTextureCoordinates())) + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + if(hasAttribute(MaterialAttribute::DiffuseTexture) && !check(coordinates, diffuseTextureCoordinates())) + return false; + if(hasSpecularTexture() && !check(coordinates, specularTextureCoordinates())) + return false; + if(hasAttribute(MaterialAttribute::NormalTexture) && !check(coordinates, normalTextureCoordinates())) + return false; + + return true; +} + Color4 PhongMaterialData::ambientColor() const { return attributeOr(MaterialAttribute::AmbientColor, hasAttribute(MaterialAttribute::AmbientTexture) ? 0xffffffff_rgbaf : 0x000000ff_rgbaf); @@ -269,11 +315,37 @@ UnsignedInt PhongMaterialData::normalTextureCoordinates() const { return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } +Matrix3 PhongMaterialData::commonTextureMatrix() const { + CORRADE_ASSERT(hasCommonTextureTransformation(), + "Trade::PhongMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation", {}); + if(hasAttribute(MaterialAttribute::AmbientTexture)) + return ambientTextureMatrix(); + if(hasAttribute(MaterialAttribute::DiffuseTexture)) + return diffuseTextureMatrix(); + if(hasSpecularTexture()) + return specularTextureMatrix(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureMatrix(); + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +#ifdef MAGNUM_BUILD_DEPRECATED Matrix3 PhongMaterialData::textureMatrix() const { return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); } +#endif -UnsignedInt PhongMaterialData::textureCoordinates() const { +UnsignedInt PhongMaterialData::commonTextureCoordinates() const { + CORRADE_ASSERT(hasCommonTextureCoordinates(), + "Trade::PhongMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set", {}); + if(hasAttribute(MaterialAttribute::AmbientTexture)) + return ambientTextureCoordinates(); + if(hasAttribute(MaterialAttribute::DiffuseTexture)) + return diffuseTextureCoordinates(); + if(hasSpecularTexture()) + return specularTextureCoordinates(); + if(hasAttribute(MaterialAttribute::NormalTexture)) + return normalTextureCoordinates(); return attributeOr(MaterialAttribute::TextureCoordinates, 0u); } diff --git a/src/Magnum/Trade/PhongMaterialData.h b/src/Magnum/Trade/PhongMaterialData.h index 695f6daa0..0d265908f 100644 --- a/src/Magnum/Trade/PhongMaterialData.h +++ b/src/Magnum/Trade/PhongMaterialData.h @@ -253,9 +253,23 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { * @ref MaterialAttribute::NormalTextureMatrix or * @ref MaterialAttribute::TextureMatrix attributes is present, * @cpp false @ce otherwise. + * @see @ref hasCommonTextureTransformation() */ bool hasTextureTransformation() const; + /** + * @brief Whether the material has a common transformation for all textures + * @m_since_latest + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref ambientTextureMatrix(), @ref diffuseTextureMatrix(), + * @ref specularTextureMatrix() and @ref normalTextureMatrix() have the + * same value, @cpp false @ce otherwise. In particular, returns + * @cpp true @ce also if there's no texture transformation at all. Use + * @ref hasTextureTransformation() to distinguish that case. + */ + bool hasCommonTextureTransformation() const; + /** * @brief Whether the material uses extra texture coordinate sets * @m_since_latest @@ -267,9 +281,24 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { * @ref MaterialAttribute::NormalTextureCoordinates or * @ref MaterialAttribute::TextureCoordinates attributes is present and * has a non-zero value, @cpp false @ce otherwise. + * @see @ref hasCommonTextureCoordinates() */ bool hasTextureCoordinates() const; + /** + * @brief Whether the material has a common coordinate set for all textures + * @m_since_latest + * + * Returns @cpp true @ce if, for each texture that is present, + * @ref ambientTextureCoordinates(), @ref diffuseTextureCoordinates(), + * @ref specularTextureCoordinates() and @ref normalTextureCoordinates() + * have the same value, @cpp false @ce otherwise. In particular, + * returns @cpp true @ce also if there's no extra texture coordinate + * set used at all. Use @ref hasTextureCoordinates() to distinguish + * that case. + */ + bool hasCommonTextureCoordinates() const; + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Material flags @@ -540,40 +569,43 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { /** * @brief Common texture coordinate transformation matrix for all textures - * @m_since{2020,06} + * @m_since_latest * - * Convenience access to the @ref MaterialAttribute::TextureMatrix - * attribute. If not present, the default is an identity matrix. Note - * that the material may also define per-texture transformation using - * the @ref MaterialAttribute::AmbientTextureMatrix, - * @ref MaterialAttribute::DiffuseTextureMatrix, - * @ref MaterialAttribute::SpecularTextureMatrix and - * @ref MaterialAttribute::NormalTextureMatrix attributes, which then - * take precedence over the common one. - * @see @ref hasAttribute(), @ref ambientTextureMatrix(), - * @ref diffuseTextureMatrix(), @ref specularTextureMatrix(), - * @ref normalTextureMatrix() + * Expects that @ref hasCommonTextureTransformation() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref ambientTextureMatrix(), @ref diffuseTextureMatrix(), + * @ref specularTextureMatrix() and @ref normalTextureMatrix() where a + * texture is present. If no texture is present, returns an identity + * matrix. */ - Matrix3 textureMatrix() const; + Matrix3 commonTextureMatrix() const; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Common texture coordinate transformation matrix for all textures + * @m_deprecated_since_latest Because the material may now also define + * per-texture transformations, which take precedence over the + * common one, this value is misleading. Use either + * @ref commonTextureMatrix() or separate + * @ref ambientTextureMatrix(), @ref diffuseTextureMatrix(), + * @ref specularTextureMatrix() and @ref normalTextureMatrix() + * accessors instead. + */ + CORRADE_DEPRECATED("use commonTextureMatrix() or per-texture accessors instead") Matrix3 textureMatrix() const; + #endif /** * @brief Common texture coordinate set index for all textures * @m_since_latest * - * Convenience access to the @ref MaterialAttribute::TextureCoordinates - * attribute. If not present, the default is @cpp 0 @ce. Note that the - * material may also define per-texture coordinate set using the - * @ref MaterialAttribute::AmbientTextureCoordinates, - * @ref MaterialAttribute::DiffuseTextureCoordinates, - * @ref MaterialAttribute::SpecularTextureCoordinates and - * @ref MaterialAttribute::NormalTextureCoordinates attributes, which - * then take precedence over the common one. - * @see @ref hasAttribute(), @ref ambientTextureCoordinates(), - * @ref diffuseTextureCoordinates(), - * @ref specularTextureCoordinates(), - * @ref normalTextureCoordinates() - */ - UnsignedInt textureCoordinates() const; + * Expects that @ref hasCommonTextureCoordinates() is @cpp true @ce; + * returns a coordinate set index that's the same for all of + * @ref ambientTextureCoordinates(), @ref diffuseTextureCoordinates(), + * @ref specularTextureCoordinates() and @ref normalTextureCoordinates() + * where a texture is present. If no texture is present, returns + * @cpp 0 @ce. + */ + UnsignedInt commonTextureCoordinates() const; /** * @brief Shininess diff --git a/src/Magnum/Trade/Test/MaterialDataTest.cpp b/src/Magnum/Trade/Test/MaterialDataTest.cpp index 51fa51bd4..62bce1c65 100644 --- a/src/Magnum/Trade/Test/MaterialDataTest.cpp +++ b/src/Magnum/Trade/Test/MaterialDataTest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -159,6 +160,10 @@ class MaterialDataTest: public TestSuite::Tester { void pbrMetallicRoughnessAccessTexturedExplicitPackedNormalRoughnessMetallic(); void pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates(); void pbrMetallicRoughnessAccessInvalidTextures(); + void pbrMetallicRoughnessAccessCommonTransformationCoordinatesNoTextures(); + void pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneTexture(); + void pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneDifferentTexture(); + void pbrMetallicRoughnessAccessNoCommonTransformationCoordinates(); void pbrSpecularGlossinessAccess(); void pbrSpecularGlossinessAccessDefaults(); @@ -168,6 +173,10 @@ class MaterialDataTest: public TestSuite::Tester { void pbrSpecularGlossinessAccessTexturedExplicitPackedSpecularGlossiness(); void pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinates(); void pbrSpecularGlossinessAccessInvalidTextures(); + void pbrSpecularGlossinessAccessCommonTransformationCoordinatesNoTextures(); + void pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneTexture(); + void pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneDifferentTexture(); + void pbrSpecularGlossinessAccessNoCommonTransformationCoordinates(); void phongAccess(); void phongAccessDefaults(); @@ -176,6 +185,10 @@ class MaterialDataTest: public TestSuite::Tester { void phongAccessTexturedSingleMatrixCoordinates(); void phongAccessTexturedImplicitPackedSpecularGlossiness(); void phongAccessInvalidTextures(); + void phongAccessCommonTransformationCoordinatesNoTextures(); + void phongAccessCommonTransformationCoordinatesOneTexture(); + void phongAccessCommonTransformationCoordinatesOneDifferentTexture(); + void phongAccessNoCommonTransformationCoordinates(); void flatAccessBaseColor(); void flatAccessDiffuseColor(); @@ -197,6 +210,10 @@ class MaterialDataTest: public TestSuite::Tester { void pbrClearCoatAccessTexturedSingleMatrixCoordinates(); void pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates(); void pbrClearCoatAccessInvalidTextures(); + void pbrClearCoatAccessCommonTransformationCoordinatesNoTextures(); + void pbrClearCoatAccessCommonTransformationCoordinatesOneTexture(); + void pbrClearCoatAccessCommonTransformationCoordinatesOneDifferentTexture(); + void pbrClearCoatAccessNoCommonTransformationCoordinates(); void debugLayer(); void debugAttribute(); @@ -217,6 +234,37 @@ class MaterialDataTest: public TestSuite::Tester { #endif }; +const Containers::StringView PbrMetallicRoughnessTextureData[] { + "BaseColorTexture", + "MetalnessTexture", + "RoughnessTexture", + "NormalTexture", + "OcclusionTexture", + "EmissiveTexture" +}; + +const Containers::StringView PbrSpecularGlossinessTextureData[] { + "DiffuseTexture", + "SpecularTexture", + "GlossinessTexture", + "NormalTexture", + "OcclusionTexture", + "EmissiveTexture" +}; + +const Containers::StringView PhongTextureData[] { + "AmbientTexture", + "DiffuseTexture", + "SpecularTexture", + "NormalTexture" +}; + +const Containers::StringView PbrClearCoatTextureData[] { + "LayerFactorTexture", + "RoughnessTexture", + "NormalTexture" +}; + MaterialDataTest::MaterialDataTest() { addTests({&MaterialDataTest::textureSwizzleComponentCount, @@ -358,6 +406,14 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedNormalRoughnessMetallic, &MaterialDataTest::pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates, &MaterialDataTest::pbrMetallicRoughnessAccessInvalidTextures, + &MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesNoTextures}); + + addInstancedTests({ + &MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneTexture, + &MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneDifferentTexture}, + Containers::arraySize(PbrMetallicRoughnessTextureData)); + + addTests({&MaterialDataTest::pbrMetallicRoughnessAccessNoCommonTransformationCoordinates, &MaterialDataTest::pbrSpecularGlossinessAccess, &MaterialDataTest::pbrSpecularGlossinessAccessDefaults, @@ -367,6 +423,14 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::pbrSpecularGlossinessAccessTexturedExplicitPackedSpecularGlossiness, &MaterialDataTest::pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinates, &MaterialDataTest::pbrSpecularGlossinessAccessInvalidTextures, + &MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesNoTextures}); + + addInstancedTests({ + &MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneTexture, + &MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneDifferentTexture}, + Containers::arraySize(PbrSpecularGlossinessTextureData)); + + addTests({&MaterialDataTest::pbrSpecularGlossinessAccessNoCommonTransformationCoordinates, &MaterialDataTest::phongAccess, &MaterialDataTest::phongAccessDefaults, @@ -375,6 +439,14 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::phongAccessTexturedSingleMatrixCoordinates, &MaterialDataTest::phongAccessTexturedImplicitPackedSpecularGlossiness, &MaterialDataTest::phongAccessInvalidTextures, + &MaterialDataTest::phongAccessCommonTransformationCoordinatesNoTextures}); + + addInstancedTests({ + &MaterialDataTest::phongAccessCommonTransformationCoordinatesOneTexture, + &MaterialDataTest::phongAccessCommonTransformationCoordinatesOneDifferentTexture}, + Containers::arraySize(PhongTextureData)); + + addTests({&MaterialDataTest::phongAccessNoCommonTransformationCoordinates, &MaterialDataTest::flatAccessBaseColor, &MaterialDataTest::flatAccessDiffuseColor, @@ -396,6 +468,14 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::pbrClearCoatAccessTexturedSingleMatrixCoordinates, &MaterialDataTest::pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates, &MaterialDataTest::pbrClearCoatAccessInvalidTextures, + &MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesNoTextures}); + + addInstancedTests({ + &MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesOneTexture, + &MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesOneDifferentTexture}, + Containers::arraySize(PbrClearCoatTextureData)); + + addTests({&MaterialDataTest::pbrClearCoatAccessNoCommonTransformationCoordinates, &MaterialDataTest::debugLayer, &MaterialDataTest::debugAttribute, @@ -2522,7 +2602,9 @@ void MaterialDataTest::constructPhongDeprecated() { CORRADE_COMPARE(data.ambientColor(), 0xccffbb_rgbf); CORRADE_COMPARE(data.diffuseColor(), 0xebefbf_rgbf); CORRADE_COMPARE(data.specularColor(), 0xacabad_rgbf); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(data.alphaMode(), MaterialAlphaMode::Mask); CORRADE_COMPARE(data.alphaMask(), 0.3f); CORRADE_COMPARE(data.shininess(), 80.0f); @@ -2552,7 +2634,9 @@ void MaterialDataTest::constructPhongDeprecatedTextured() { CORRADE_COMPARE(data.specularColor(), 0xacabad_rgbf); CORRADE_COMPARE(data.specularTexture(), 17); CORRADE_COMPARE(data.specularTextureCoordinates(), 0); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(data.alphaMode(), MaterialAlphaMode::Blend); CORRADE_COMPARE(data.alphaMask(), 0.37f); CORRADE_COMPARE(data.shininess(), 96.0f); @@ -2581,7 +2665,9 @@ void MaterialDataTest::constructPhongDeprecatedTexturedTextureTransform() { CORRADE_COMPARE(data.diffuseTexture(), 42); CORRADE_COMPARE(data.specularColor(), 0xacabad_rgbf); CORRADE_COMPARE(data.normalTexture(), 17); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(data.textureMatrix(), Matrix3::rotation(90.0_degf)); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(data.alphaMode(), MaterialAlphaMode::Mask); CORRADE_COMPARE(data.alphaMask(), 0.5f); CORRADE_COMPARE(data.shininess(), 96.0f); @@ -2615,7 +2701,9 @@ void MaterialDataTest::constructPhongDeprecatedTexturedCoordinates() { CORRADE_COMPARE(data.specularTextureCoordinates(), 1); CORRADE_COMPARE(data.normalTexture(), 0); CORRADE_COMPARE(data.normalTextureCoordinates(), 8); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(data.ambientTextureCoordinates(), 3); CORRADE_COMPARE(data.alphaMode(), MaterialAlphaMode::Blend); CORRADE_COMPARE(data.alphaMask(), 0.37f); @@ -2722,8 +2810,6 @@ void MaterialDataTest::pbrMetallicRoughnessAccessDefaults() { CORRADE_COMPARE(data.metalness(), 1.0f); CORRADE_COMPARE(data.roughness(), 1.0f); CORRADE_COMPARE(data.emissiveColor(), 0x000000_rgbf); - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::pbrMetallicRoughnessAccessTextured() { @@ -2794,9 +2880,6 @@ void MaterialDataTest::pbrMetallicRoughnessAccessTextured() { CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3::scaling({0.75f, 0.5f})); CORRADE_COMPARE(data.emissiveTexture(), 5); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 7); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::pbrMetallicRoughnessAccessTexturedDefaults() { @@ -2845,9 +2928,6 @@ void MaterialDataTest::pbrMetallicRoughnessAccessTexturedDefaults() { CORRADE_COMPARE(data.emissiveTexture(), 6); CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 0); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates() { @@ -2874,9 +2954,6 @@ void MaterialDataTest::pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates CORRADE_COMPARE(data.occlusionTextureCoordinates(), 7); CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 7); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3::scaling({0.5f, 0.5f})); - CORRADE_COMPARE(data.textureCoordinates(), 7); } void MaterialDataTest::pbrMetallicRoughnessAccessTexturedImplicitPackedMetallicRoughness() { @@ -3315,6 +3392,94 @@ void MaterialDataTest::pbrMetallicRoughnessAccessInvalidTextures() { "Trade::PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture\n"); } +void MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesNoTextures() { + PbrMetallicRoughnessMaterialData a{{}, {}}; + CORRADE_VERIFY(a.hasCommonTextureTransformation()); + CORRADE_VERIFY(a.hasCommonTextureCoordinates()); + CORRADE_COMPARE(a.commonTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(a.commonTextureCoordinates(), 0); + + PbrMetallicRoughnessMaterialData b{{}, { + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u} + }}; + CORRADE_VERIFY(b.hasCommonTextureTransformation()); + CORRADE_VERIFY(b.hasCommonTextureCoordinates()); + CORRADE_COMPARE(b.commonTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(b.commonTextureCoordinates(), 7); +} + +void MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneTexture() { + Containers::StringView textureName = PbrMetallicRoughnessTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrMetallicRoughnessMaterialData data{{}, { + {textureName, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These shouldn't affect the above */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(data.hasCommonTextureTransformation()); + CORRADE_COMPARE(data.commonTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_VERIFY(data.hasCommonTextureCoordinates()); + CORRADE_COMPARE(data.commonTextureCoordinates(), 17u); +} + +void MaterialDataTest::pbrMetallicRoughnessAccessCommonTransformationCoordinatesOneDifferentTexture() { + Containers::StringView textureName = PbrMetallicRoughnessTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::BaseColorTexture, 2u}, + {MaterialAttribute::MetalnessTexture, 3u}, + {MaterialAttribute::RoughnessTexture, 4u}, + {MaterialAttribute::NormalTexture, 5u}, + {MaterialAttribute::OcclusionTexture, 6u}, + {MaterialAttribute::EmissiveTexture, 7u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These are used by all textures except the one above, failing the + check */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); +} + +void MaterialDataTest::pbrMetallicRoughnessAccessNoCommonTransformationCoordinates() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::BaseColorTexture, 3u}, + {MaterialAttribute::BaseColorTextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::BaseColorTextureCoordinates, 3u}, + {MaterialAttribute::MetalnessTexture, 4u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::RoughnessTexture, 5u}, + {MaterialAttribute::RoughnessTextureCoordinates, 17u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); + + std::ostringstream out; + Error redirectError{&out}; + data.commonTextureMatrix(); + data.commonTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::PbrMetallicRoughnessMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation\n" + "Trade::PbrMetallicRoughnessMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set\n"); +} + void MaterialDataTest::pbrSpecularGlossinessAccess() { MaterialData base{MaterialType::PbrSpecularGlossiness, { {MaterialAttribute::DiffuseColor, 0xccffbbff_rgbaf}, @@ -3418,9 +3583,6 @@ void MaterialDataTest::pbrSpecularGlossinessAccessTextured() { CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3::scaling({0.75f, 0.5f})); CORRADE_COMPARE(data.emissiveTexture(), 5); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 7); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::pbrSpecularGlossinessAccessTexturedDefaults() { @@ -3466,9 +3628,6 @@ void MaterialDataTest::pbrSpecularGlossinessAccessTexturedDefaults() { CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.emissiveTexture(), 6); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 0); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinates() { @@ -3497,9 +3656,6 @@ void MaterialDataTest::pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinate CORRADE_COMPARE(data.occlusionTextureCoordinates(), 7); CORRADE_COMPARE(data.emissiveTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); CORRADE_COMPARE(data.emissiveTextureCoordinates(), 7); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3::scaling({0.5f, 0.5f})); - CORRADE_COMPARE(data.textureCoordinates(), 7); } void MaterialDataTest::pbrSpecularGlossinessAccessTexturedImplicitPackedSpecularGlossiness() { @@ -3707,6 +3863,94 @@ void MaterialDataTest::pbrSpecularGlossinessAccessInvalidTextures() { "Trade::PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture\n"); } +void MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesNoTextures() { + PbrSpecularGlossinessMaterialData a{{}, {}}; + CORRADE_VERIFY(a.hasCommonTextureTransformation()); + CORRADE_VERIFY(a.hasCommonTextureCoordinates()); + CORRADE_COMPARE(a.commonTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(a.commonTextureCoordinates(), 0); + + PbrSpecularGlossinessMaterialData b{{}, { + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u} + }}; + CORRADE_VERIFY(b.hasCommonTextureTransformation()); + CORRADE_VERIFY(b.hasCommonTextureCoordinates()); + CORRADE_COMPARE(b.commonTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(b.commonTextureCoordinates(), 7); +} + +void MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneTexture() { + Containers::StringView textureName = PbrSpecularGlossinessTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrSpecularGlossinessMaterialData data{{}, { + {textureName, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These shouldn't affect the above */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(data.hasCommonTextureTransformation()); + CORRADE_COMPARE(data.commonTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_VERIFY(data.hasCommonTextureCoordinates()); + CORRADE_COMPARE(data.commonTextureCoordinates(), 17u); +} + +void MaterialDataTest::pbrSpecularGlossinessAccessCommonTransformationCoordinatesOneDifferentTexture() { + Containers::StringView textureName = PbrSpecularGlossinessTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::DiffuseTexture, 2u}, + {MaterialAttribute::SpecularTexture, 3u}, + {MaterialAttribute::GlossinessTexture, 4u}, + {MaterialAttribute::NormalTexture, 5u}, + {MaterialAttribute::OcclusionTexture, 6u}, + {MaterialAttribute::EmissiveTexture, 7u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These are used by all textures except the one above, failing the + check */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); +} + +void MaterialDataTest::pbrSpecularGlossinessAccessNoCommonTransformationCoordinates() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::DiffuseTexture, 3u}, + {MaterialAttribute::DiffuseTextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::DiffuseTextureCoordinates, 3u}, + {MaterialAttribute::SpecularTexture, 4u}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::OcclusionTexture, 5u}, + {MaterialAttribute::OcclusionTextureCoordinates, 17u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); + + std::ostringstream out; + Error redirectError{&out}; + data.commonTextureMatrix(); + data.commonTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::PbrSpecularGlossinessMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation\n" + "Trade::PbrSpecularGlossinessMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set\n"); +} + void MaterialDataTest::phongAccess() { MaterialData base{MaterialType::Phong, { {MaterialAttribute::AmbientColor, 0xccffbbff_rgbaf}, @@ -3739,8 +3983,6 @@ void MaterialDataTest::phongAccessDefaults() { CORRADE_COMPARE(data.ambientColor(), 0x000000_rgbf); CORRADE_COMPARE(data.diffuseColor(), 0xffffff_rgbf); CORRADE_COMPARE(data.specularColor(), 0xffffff00_rgbaf); - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); CORRADE_COMPARE(data.shininess(), 80.0f); } @@ -3787,9 +4029,6 @@ void MaterialDataTest::phongAccessTextured() { CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::GB); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({1.0f, 0.5f})); CORRADE_COMPARE(data.normalTextureCoordinates(), 5); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::phongAccessTexturedDefaults() { @@ -3821,9 +4060,6 @@ void MaterialDataTest::phongAccessTexturedDefaults() { CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::RGB); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.normalTextureCoordinates(), 0); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); - CORRADE_COMPARE(data.textureCoordinates(), 0); } void MaterialDataTest::phongAccessTexturedSingleMatrixCoordinates() { @@ -3846,9 +4082,6 @@ void MaterialDataTest::phongAccessTexturedSingleMatrixCoordinates() { CORRADE_COMPARE(data.specularTextureCoordinates(), 2); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::translation({0.5f, 1.0f})); CORRADE_COMPARE(data.normalTextureCoordinates(), 2); - - CORRADE_COMPARE(data.textureMatrix(), Matrix3::translation({0.5f, 1.0f})); - CORRADE_COMPARE(data.textureCoordinates(), 2); } void MaterialDataTest::phongAccessTexturedImplicitPackedSpecularGlossiness() { @@ -3916,6 +4149,92 @@ void MaterialDataTest::phongAccessInvalidTextures() { "Trade::PhongMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture\n"); } +void MaterialDataTest::phongAccessCommonTransformationCoordinatesNoTextures() { + PhongMaterialData a{{}, {}}; + CORRADE_VERIFY(a.hasCommonTextureTransformation()); + CORRADE_VERIFY(a.hasCommonTextureCoordinates()); + CORRADE_COMPARE(a.commonTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(a.commonTextureCoordinates(), 0); + + PhongMaterialData b{{}, { + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u} + }}; + CORRADE_VERIFY(b.hasCommonTextureTransformation()); + CORRADE_VERIFY(b.hasCommonTextureCoordinates()); + CORRADE_COMPARE(b.commonTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(b.commonTextureCoordinates(), 7); +} + +void MaterialDataTest::phongAccessCommonTransformationCoordinatesOneTexture() { + Containers::StringView textureName = PhongTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PhongMaterialData data{{}, { + {textureName, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These shouldn't affect the above */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(data.hasCommonTextureTransformation()); + CORRADE_COMPARE(data.commonTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_VERIFY(data.hasCommonTextureCoordinates()); + CORRADE_COMPARE(data.commonTextureCoordinates(), 17u); +} + +void MaterialDataTest::phongAccessCommonTransformationCoordinatesOneDifferentTexture() { + Containers::StringView textureName = PhongTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PhongMaterialData data{{}, { + {MaterialAttribute::AmbientTexture, 2u}, + {MaterialAttribute::DiffuseTexture, 3u}, + {MaterialAttribute::SpecularTexture, 4u}, + {MaterialAttribute::NormalTexture, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + + /* These are used by all textures except the one above, failing the + check */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); +} + +void MaterialDataTest::phongAccessNoCommonTransformationCoordinates() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PhongMaterialData data{{}, { + {MaterialAttribute::DiffuseTexture, 3u}, + {MaterialAttribute::DiffuseTextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::DiffuseTextureCoordinates, 3u}, + {MaterialAttribute::SpecularTexture, 4u}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::NormalTexture, 5u}, + {MaterialAttribute::NormalTextureCoordinates, 17u} + }}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); + + std::ostringstream out; + Error redirectError{&out}; + data.commonTextureMatrix(); + data.commonTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::PhongMaterialData::commonTextureMatrix(): the material doesn't have a common texture coordinate transformation\n" + "Trade::PhongMaterialData::commonTextureCoordinates(): the material doesn't have a common texture coordinate set\n"); +} + void MaterialDataTest::flatAccessBaseColor() { MaterialData base{MaterialType::Flat, { {MaterialAttribute::BaseColor, 0xccffbbff_rgbaf}, @@ -4280,6 +4599,11 @@ void MaterialDataTest::pbrClearCoatAccessTexturedBaseMaterialMatrixCoordinates() CORRADE_COMPARE(data.roughnessTextureCoordinates(), 7u); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); CORRADE_COMPARE(data.normalTextureCoordinates(), 7u); + + CORRADE_VERIFY(data.hasCommonTextureTransformation()); + CORRADE_VERIFY(data.hasCommonTextureCoordinates()); + CORRADE_COMPARE(data.commonTextureMatrix(), Matrix3::translation({0.0f, 0.5f})); + CORRADE_COMPARE(data.commonTextureCoordinates(), 7); } void MaterialDataTest::pbrClearCoatAccessInvalidTextures() { @@ -4314,6 +4638,108 @@ void MaterialDataTest::pbrClearCoatAccessInvalidTextures() { "Trade::PbrClearCoatMaterialData::normalTextureCoordinates(): the layer doesn't have a normal texture\n"); } +void MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesNoTextures() { + PbrClearCoatMaterialData a{{}, { + {MaterialLayer::ClearCoat}, + }, {0, 1}}; + CORRADE_VERIFY(a.hasCommonTextureTransformation()); + CORRADE_VERIFY(a.hasCommonTextureCoordinates()); + CORRADE_COMPARE(a.commonTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(a.commonTextureCoordinates(), 0); + + PbrClearCoatMaterialData b{{}, { + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u}, + + {MaterialLayer::ClearCoat} + }, {2, 3}}; + CORRADE_VERIFY(b.hasCommonTextureTransformation()); + CORRADE_VERIFY(b.hasCommonTextureCoordinates()); + CORRADE_COMPARE(b.commonTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(b.commonTextureCoordinates(), 7); + + PbrClearCoatMaterialData c{{}, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u}, + }, {0, 3}}; + CORRADE_VERIFY(c.hasCommonTextureTransformation()); + CORRADE_VERIFY(c.hasCommonTextureCoordinates()); + CORRADE_COMPARE(c.commonTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(c.commonTextureCoordinates(), 7); +} + +void MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesOneTexture() { + Containers::StringView textureName = PbrClearCoatTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrClearCoatMaterialData data{{}, { + /* These shouldn't affect the below */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u}, + + {MaterialLayer::ClearCoat}, + {textureName, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u}, + }, {2, 6}}; + + CORRADE_VERIFY(data.hasCommonTextureTransformation()); + CORRADE_COMPARE(data.commonTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_VERIFY(data.hasCommonTextureCoordinates()); + CORRADE_COMPARE(data.commonTextureCoordinates(), 17u); +} + +void MaterialDataTest::pbrClearCoatAccessCommonTransformationCoordinatesOneDifferentTexture() { + Containers::StringView textureName = PbrClearCoatTextureData[testCaseInstanceId()]; + setTestCaseDescription(textureName); + + PbrClearCoatMaterialData data{{}, { + /* These are used by all textures except the one below, failing the + check */ + {MaterialAttribute::TextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::TextureCoordinates, 3u}, + + {MaterialLayer::ClearCoat}, + {MaterialAttribute::LayerFactorTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 3u}, + {MaterialAttribute::NormalTexture, 5u}, + {std::string{textureName} + "Matrix", Matrix3::scaling({0.5f, 1.0f})}, + {std::string{textureName} + "Coordinates", 17u} + }, {2, 8}}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); +} + +void MaterialDataTest::pbrClearCoatAccessNoCommonTransformationCoordinates() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrClearCoatMaterialData data{{}, { + {MaterialLayer::ClearCoat}, + {MaterialAttribute::LayerFactorTexture, 3u}, + {MaterialAttribute::LayerFactorTextureMatrix, Matrix3::translation({0.5f, 0.0f})}, + {MaterialAttribute::LayerFactorTextureCoordinates, 3u}, + {MaterialAttribute::RoughnessTexture, 4u}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::NormalTexture, 5u}, + {MaterialAttribute::NormalTextureCoordinates, 17u} + }, {0, 8}}; + + CORRADE_VERIFY(!data.hasCommonTextureTransformation()); + CORRADE_VERIFY(!data.hasCommonTextureCoordinates()); + + std::ostringstream out; + Error redirectError{&out}; + data.commonTextureMatrix(); + data.commonTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::PbrClearCoatMaterialData::commonTextureMatrix(): the layer doesn't have a common texture coordinate transformation\n" + "Trade::PbrClearCoatMaterialData::commonTextureCoordinates(): the layer doesn't have a common texture coordinate set\n"); +} + void MaterialDataTest::debugLayer() { std::ostringstream out;