From 69f5f8111029afd02e8391f28ddd578b6dcaedba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 4 Aug 2020 18:39:35 +0200 Subject: [PATCH] Trade: expose basic PBR material properties and helper classes. Well, "basic". Practically mirrors glTF PBR materials: - builtin metallic/roughness - the KHR_materials_pbrSpecularGlossiness extension - extra normal/occlusion/emission maps - exposes the implicit metallic/roughness and specular/glossiness packing, but also allows separate maps with arbitrary packings as well as two-channel normal maps (instead of three-channel) - provides convenience checks for the most common packing schemes including MSFT_packing_normalRoughnessMetallic and the three variants of MSFT_packing_occlusionRoughnessMetallic - teaches PhongMaterialData to recognize packed specular/glossiness maps as well Next up is exposing at least one layer extension, and then I'm done here. --- doc/changelog.dox | 9 +- src/Magnum/Trade/CMakeLists.txt | 4 + .../materialAttributeProperties.hpp | 31 + src/Magnum/Trade/MaterialData.cpp | 6 +- src/Magnum/Trade/MaterialData.h | 519 +++++++- .../PbrMetallicRoughnessMaterialData.cpp | 302 +++++ .../Trade/PbrMetallicRoughnessMaterialData.h | 566 +++++++++ .../PbrSpecularGlossinessMaterialData.cpp | 251 ++++ .../Trade/PbrSpecularGlossinessMaterialData.h | 460 +++++++ src/Magnum/Trade/PhongMaterialData.cpp | 29 +- src/Magnum/Trade/PhongMaterialData.h | 60 +- src/Magnum/Trade/Test/MaterialDataTest.cpp | 1083 ++++++++++++++++- src/Magnum/Trade/Trade.h | 2 + 13 files changed, 3271 insertions(+), 51 deletions(-) create mode 100644 src/Magnum/Trade/PbrMetallicRoughnessMaterialData.cpp create mode 100644 src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h create mode 100644 src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp create mode 100644 src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h diff --git a/doc/changelog.dox b/doc/changelog.dox index fd0811f87..f84a8d5c9 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -76,7 +76,14 @@ 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. See [mosra/magnum#459](https://github.com/mosra/magnum/pull/459). + instance; plus new @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). +- Added @ref Trade::PhongMaterialData::hasSpecularTexture(), + @ref Trade::PhongMaterialData::specularTextureSwizzle() and + @ref Trade::PhongMaterialData::normalTextureSwizzle() to make new features + added for PBR materials recognizable also in classic Phong workflows. @subsection changelog-latest-changes Changes and improvements diff --git a/src/Magnum/Trade/CMakeLists.txt b/src/Magnum/Trade/CMakeLists.txt index e2019cb8f..aa9a2a4a1 100644 --- a/src/Magnum/Trade/CMakeLists.txt +++ b/src/Magnum/Trade/CMakeLists.txt @@ -45,6 +45,8 @@ set(MagnumTrade_GracefulAssert_SRCS MeshData.cpp ObjectData2D.cpp ObjectData3D.cpp + PbrMetallicRoughnessMaterialData.cpp + PbrSpecularGlossinessMaterialData.cpp PhongMaterialData.cpp) set(MagnumTrade_HEADERS @@ -63,6 +65,8 @@ set(MagnumTrade_HEADERS MeshObjectData3D.h ObjectData2D.h ObjectData3D.h + PbrMetallicRoughnessMaterialData.h + PbrSpecularGlossinessMaterialData.h PhongMaterialData.h SceneData.h TextureData.h diff --git a/src/Magnum/Trade/Implementation/materialAttributeProperties.hpp b/src/Magnum/Trade/Implementation/materialAttributeProperties.hpp index 9b78c0a50..c7c73e283 100644 --- a/src/Magnum/Trade/Implementation/materialAttributeProperties.hpp +++ b/src/Magnum/Trade/Implementation/materialAttributeProperties.hpp @@ -39,12 +39,43 @@ _c(DiffuseTextureMatrix,Matrix3x3) _c(DiffuseTextureCoordinates,UnsignedInt) _c(SpecularColor,Vector4) _c(SpecularTexture,UnsignedInt) +_ct(SpecularTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) _c(SpecularTextureMatrix,Matrix3x3) _c(SpecularTextureCoordinates,UnsignedInt) _c(Shininess,Float) +_c(BaseColor,Vector4) +_c(BaseColorTexture,UnsignedInt) +_c(BaseColorTextureMatrix,Matrix3x3) +_c(BaseColorTextureCoordinates,UnsignedInt) +_c(Metalness,Float) +_c(MetalnessTexture,UnsignedInt) +_ct(MetalnessTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) +_c(MetalnessTextureMatrix,Matrix3x3) +_c(MetalnessTextureCoordinates,UnsignedInt) +_c(Roughness,Float) +_c(RoughnessTexture,UnsignedInt) +_ct(RoughnessTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) +_c(RoughnessTextureMatrix,Matrix3x3) +_c(RoughnessTextureCoordinates,UnsignedInt) +_c(MetallicRoughnessTexture,UnsignedInt) +_c(Glossiness,Float) +_c(GlossinessTexture,UnsignedInt) +_ct(GlossinessTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) +_c(GlossinessTextureMatrix,Matrix3x3) +_c(GlossinessTextureCoordinates,UnsignedInt) +_c(SpecularGlossinessTexture,UnsignedInt) _c(NormalTexture,UnsignedInt) +_ct(NormalTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) _c(NormalTextureMatrix,Matrix3x3) _c(NormalTextureCoordinates,UnsignedInt) +_c(OcclusionTexture,UnsignedInt) +_ct(OcclusionTextureSwizzle,TextureSwizzle,MaterialTextureSwizzle) +_c(OcclusionTextureMatrix,Matrix3x3) +_c(OcclusionTextureCoordinates,UnsignedInt) +_c(EmissiveColor,Vector3) +_c(EmissiveTexture,UnsignedInt) +_c(EmissiveTextureMatrix,Matrix3x3) +_c(EmissiveTextureCoordinates,UnsignedInt) _c(TextureMatrix,Matrix3x3) _c(TextureCoordinates,UnsignedInt) #endif diff --git a/src/Magnum/Trade/MaterialData.cpp b/src/Magnum/Trade/MaterialData.cpp index 1e9f36c51..5fc4ed97d 100644 --- a/src/Magnum/Trade/MaterialData.cpp +++ b/src/Magnum/Trade/MaterialData.cpp @@ -649,6 +649,8 @@ Debug& operator<<(Debug& debug, const MaterialType value) { /* LCOV_EXCL_START */ #define _c(value) case MaterialType::value: return debug << "::" #value; _c(Phong) + _c(PbrMetallicRoughness) + _c(PbrSpecularGlossiness) #undef _c /* LCOV_EXCL_STOP */ } @@ -658,7 +660,9 @@ Debug& operator<<(Debug& debug, const MaterialType value) { Debug& operator<<(Debug& debug, const MaterialTypes value) { return Containers::enumSetDebugOutput(debug, value, "Trade::MaterialTypes{}", { - MaterialType::Phong + MaterialType::Phong, + MaterialType::PbrMetallicRoughness, + MaterialType::PbrSpecularGlossiness }); } diff --git a/src/Magnum/Trade/MaterialData.h b/src/Magnum/Trade/MaterialData.h index 894b7f2e4..51b36b765 100644 --- a/src/Magnum/Trade/MaterialData.h +++ b/src/Magnum/Trade/MaterialData.h @@ -144,80 +144,113 @@ enum class MaterialAttribute: UnsignedInt { AmbientTextureCoordinates, /** - * Diffuse color for Phong materials, @ref MaterialAttributeType::Vector4. + * Diffuse color for Phong or PBR specular/glossiness materials, + * @ref MaterialAttributeType::Vector4. * * If @ref MaterialAttribute::DiffuseTexture is present as well, these two * are multiplied together. - * @see @ref PhongMaterialData::diffuseColor() + * @see @ref PhongMaterialData::diffuseColor(), + * @ref PbrSpecularGlossinessMaterialData::diffuseColor() */ DiffuseColor, /** - * Diffuse texture index for Phong materials, + * Diffuse texture index for Phong or PBR specular/glossiness materials, * @ref MaterialAttributeType::UnsignedInt. * * If @ref MaterialAttribute::DiffuseColor is present as well, these two * are multiplied together. - * @see @ref PhongMaterialData::diffuseTexture() + * @see @ref PhongMaterialData::diffuseTexture(), + * @ref PbrSpecularGlossinessMaterialData::diffuseTexture() */ DiffuseTexture, /** - * Diffuse texture transformation matrix for Phong materials, - * @ref MaterialAttributeType::Matrix3x3. + * Diffuse texture transformation matrix for Phong or PBR + * specular/glossiness materials, @ref MaterialAttributeType::Matrix3x3. * * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are * present. - * @see @ref PhongMaterialData::diffuseTextureMatrix() + * @see @ref PhongMaterialData::diffuseTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::diffuseTextureMatrix() */ DiffuseTextureMatrix, /** - * Diffuse texture coordinate set index for Phong materials, - * @ref MaterialAttributeType::UnsignedInt. + * Diffuse texture coordinate set index for Phong or PBR + * specular/glossiness materials, @ref MaterialAttributeType::UnsignedInt. * * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both * are present. - * @see @ref PhongMaterialData::diffuseTextureCoordinates() + * @see @ref PhongMaterialData::diffuseTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::diffuseTextureCoordinates() */ DiffuseTextureCoordinates, /** - * Specular color for Phong materials, @ref MaterialAttributeType::Vector4. + * Specular color for Phong or PBR specular/glossiness materials, + * @ref MaterialAttributeType::Vector4. Alpha is commonly zero to not + * interfere with alpha-masked objects, non-zero alpha can be for example + * used to render transparent material which are still expected to have + * specular highlights such as glass or soap bubbles. * - * If @ref MaterialAttribute::SpecularTexture is present as well, these two - * are multiplied together. - * @see @ref PhongMaterialData::specularColor() + * If @ref MaterialAttribute::SpecularTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture is present as well, + * these two are multiplied together. + * @see @ref PhongMaterialData::specularColor(), + * @ref PbrSpecularGlossinessMaterialData::specularColor() */ SpecularColor, /** - * Specular texture index for Phong materials, + * Specular texture index for Phong or PBR specular/glossiness materials, * @ref MaterialAttributeType::UnsignedInt. * * If @ref MaterialAttribute::SpecularColor is present as well, these two - * are multiplied together. - * @see @ref PhongMaterialData::specularTexture() + * are multiplied together. Can be alternatively supplied as a packed + * @ref MaterialAttribute::SpecularGlossinessTexture. + * @see @ref PhongMaterialData::hasSpecularTexture(), + * @ref PhongMaterialData::specularTexture(), + * @ref PbrSpecularGlossinessMaterialData::hasSpecularTexture(), + * @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture(), + * @ref PbrSpecularGlossinessMaterialData::specularTexture() */ SpecularTexture, /** - * Specular texture transformation matrix for Phong materials, - * @ref MaterialAttributeType::Matrix3x3. + * Specular texture swizzle for Phong or PBR specular/glossiness materials, + * @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to describe whether the alpha channel of a + * @ref MaterialAttribute::SpecularTexture is used or not. Either + * @ref MaterialTextureSwizzle::RGBA or @ref MaterialTextureSwizzle::RGB + * (which is the default) is expected. Does not apply to + * @ref MaterialAttribute::SpecularGlossinessTexture --- in that case, + * the specular texture is always three-channel, regardless of this + * attribute. + * @see @ref PbrSpecularGlossinessMaterialData::specularTextureSwizzle() + */ + SpecularTextureSwizzle, + + /** + * Specular texture transformation matrix for Phong or PBR + * specular/glossiness materials, @ref MaterialAttributeType::Matrix3x3. * * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are * present. - * @see @ref PhongMaterialData::specularTextureMatrix() + * @see @ref PhongMaterialData::specularTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::glossinessTextureMatrix() */ SpecularTextureMatrix, /** - * Specular texture coordinate set index for Phong materials, - * @ref MaterialAttributeType::UnsignedInt. + * Specular texture coordinate set index for Phong or PBR + * specular/glossiness materials, @ref MaterialAttributeType::UnsignedInt. * * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both * are present. - * @see @ref PhongMaterialData::specularTextureCoordinates() + * @see @ref PhongMaterialData::specularTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::specularTextureCoordinates() */ SpecularTextureCoordinates, @@ -228,20 +261,324 @@ enum class MaterialAttribute: UnsignedInt { */ Shininess, + /** + * Base color for PBR metallic/roughness materials, + * @ref MaterialAttributeType::Vector4. + * + * If @ref MaterialAttribute::BaseColorTexture is present as well, these + * two are multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::baseColor() + */ + BaseColor, + + /** + * Base color texture index for PBR metallic/roughness materials, + * @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::BaseColor is present as well, these two are + * multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::baseColorTexture() + */ + BaseColorTexture, + + /** + * Base color texture transformation matrix for PBR metallic/roughness + * materials, @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrMetallicRoughnessMaterialData::baseColorTextureMatrix() + */ + BaseColorTextureMatrix, + + /** + * Base color texture coordinate set index for PBR metallic/roughness + * materials, @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrMetallicRoughnessMaterialData::baseColorTextureCoordinates() + */ + BaseColorTextureCoordinates, + + /** + * Metalness for PBR metallic/roughness materials, + * @ref MaterialAttributeType::Float. + * + * If @ref MaterialAttribute::MetalnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture is present as well, + * these two are multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::metalness() + */ + Metalness, + + /** + * Metalness texture index for PBR metallic/roughness materials, + * @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::Metalness is present as well, these two are + * multiplied together. Can be alternatively supplied as a packed + * @ref MaterialAttribute::MetallicRoughnessTexture. + * @see @ref PbrMetallicRoughnessMaterialData::hasMetalnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() + * @ref PbrMetallicRoughnessMaterialData::metalnessTexture() + */ + MetalnessTexture, + + /** + * Metalness texture swizzle for PBR metallic/roughness materials, + * @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to express arbitrary packing of + * @ref MaterialAttribute::MetalnessTexture together with other maps in a + * single texture. A single-channel swizzle value is expected. If not + * present, @ref MaterialTextureSwizzle::R is assumed. Does not apply to + * @ref MaterialAttribute::MetallicRoughnessTexture --- in that case, the + * metalness is implicitly in the red channel regardless of this attribute. + * @see @ref PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() + * @ref PbrMetallicRoughnessMaterialData::metalnessTextureSwizzle() + */ + MetalnessTextureSwizzle, + + /** + * Metalness texture transformation matrix for PBR metallic/roughness + * materials, @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrMetallicRoughnessMaterialData::metalnessTextureMatrix() + */ + MetalnessTextureMatrix, + + /** + * Metalness texture coordinate set index for PBR metallic/roughness + * materials, @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrMetallicRoughnessMaterialData::metalnessTextureCoordinates() + */ + MetalnessTextureCoordinates, + + /** + * Roughness for PBR metallic/roughness materials, + * @ref MaterialAttributeType::Float. + * + * If @ref MaterialAttribute::RoughnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture is present as well, + * these two are multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::roughness() + */ + Roughness, + + /** + * Roughness texture index for PBR metallic/roughness materials, + * @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::Roughness is present as well, these two are + * multiplied together. Can be alternatively supplied as a packed + * @ref MaterialAttribute::MetallicRoughnessTexture. + * @see @ref PbrMetallicRoughnessMaterialData::hasRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() + * @ref PbrMetallicRoughnessMaterialData::roughnessTexture() + */ + RoughnessTexture, + + /** + * Roughness texture swizzle for PBR metallic/roughness materials, + * @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to express arbitrary packing of + * @ref MaterialAttribute::RoughnessTexture together with other maps in a + * single texture. A single-channel swizzle value is expected. If not + * present, @ref MaterialTextureSwizzle::R is assumed. Does not apply to + * @ref MaterialAttribute::MetallicRoughnessTexture --- in that case, the + * metalness is implicitly in the green channel regardless of this + * attribute. + * @see @ref PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() + * @ref PbrMetallicRoughnessMaterialData::roughnessTextureSwizzle() + */ + RoughnessTextureSwizzle, + + /** + * Roughness texture transformation matrix for PBR metallic/roughness + * materials, @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrMetallicRoughnessMaterialData::roughnessTextureMatrix() + */ + RoughnessTextureMatrix, + + /** + * Roughness texture coordinate set index for PBR metallic/roughness + * materials, @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrMetallicRoughnessMaterialData::roughnessTextureCoordinates() + */ + RoughnessTextureCoordinates, + + /** + * Combined metallic/roughness texture index for PBR metallic/roughness + * materials with metalness in the red channel and roughness in the green + * channel, @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::Metalness / @ref MaterialAttribute::Roughness + * is present as well, these two are multiplied together. Can be + * alternatively specified as a pair of @ref MaterialAttribute::MetalnessTexture + * / @ref MaterialAttribute::RoughnessTexture attributes together with + * @ref MaterialAttribute::MetalnessTextureSwizzle set to + * @ref MaterialTextureSwizzle::R (or omitted, since that's the default) + * and @ref MaterialAttribute::RoughnessTextureSwizzle set to + * @ref MaterialTextureSwizzle::G. Texture transformation and coordinate + * set, if needed, have to be specified either using the global + * @ref MaterialAttribute::TextureMatrix and + * @ref MaterialAttribute::TextureCoordinates attributes or the per-texture + * @ref MaterialAttribute::MetalnessTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureMatrix, + * @ref MaterialAttribute::MetalnessTextureCoordinates and + * @ref MaterialAttribute::RoughnessTextureCoordinates variants. + * @see @ref PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() + * @ref PbrMetallicRoughnessMaterialData::metalnessTexture(), + * @ref PbrMetallicRoughnessMaterialData::roughnessTexture() + */ + MetallicRoughnessTexture, + + /* DiffuseColor, DiffuseTexture, DiffuseTextureMatrix, + DiffuseTextureCoordinates, SpecularColor, SpecularTexture, + SpecularTextureSwizzle, SpecularTextureMatrix, + SpecularTextureCoordinates specified above for Phong already */ + + /** + * Glossiness for PBR specular/glossiness materials, + * @ref MaterialAttributeType::Float. + * + * If @ref MaterialAttribute::GlossinessTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture is present as well, + * these two are multiplied together. + * @see @ref PbrSpecularGlossinessMaterialData::glossiness() + */ + Glossiness, + + /** + * Glossiness texture index for PBR specular/glossiness materials, + * @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::Glossiness is present as well, these two are + * multiplied together. Can be alternatively supplied as a packed + * @ref MaterialAttribute::SpecularGlossinessTexture. + * @see @ref PbrSpecularGlossinessMaterialData::hasGlossinessTexture(), + * @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture(), + * @ref PbrSpecularGlossinessMaterialData::glossinessTexture() + */ + GlossinessTexture, + + /** + * Glossiness texture swizzle for PBR specular/glossiness materials, + * @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to express arbitrary packing of + * @ref MaterialAttribute::GlossinessTexture together with other maps in a + * single texture. A single-channel swizzle value is expected. If not + * present, @ref MaterialTextureSwizzle::R is assumed. Does not apply to + * @ref MaterialAttribute::SpecularGlossinessTexture --- in that case, + * the glossiness is implicitly in the alpha channel regardless of this + * attribute. + * @see @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture(), + * @ref PbrSpecularGlossinessMaterialData::glossinessTextureSwizzle() + */ + GlossinessTextureSwizzle, + + /** + * Glossiness texture transformation matrix for PBR specular/glossiness + * materials, @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrSpecularGlossinessMaterialData::glossinessTextureMatrix() + */ + GlossinessTextureMatrix, + + /** + * Glossiness texture coordinate set index for PBR specular/glossiness + * materials, @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrSpecularGlossinessMaterialData::glossinessTextureCoordinates() + */ + GlossinessTextureCoordinates, + + /** + * Combined specular/glossiness texture index for PBR specular/glossiness + * materials with specular color in the RGB channels and glossiness in + * alpha, @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::SpecularColor / @ref MaterialAttribute::Glossiness + * is present as well, these two are multiplied together. Can be + * alternatively specified as a pair of @ref MaterialAttribute::SpecularTexture + * / @ref MaterialAttribute::GlossinessTexture attributes together with + * @ref MaterialAttribute::GlossinessTextureSwizzle set to + * @ref MaterialTextureSwizzle::A. Texture transformation and coordinate + * set, if needed, have to be specified either using the global + * @ref MaterialAttribute::TextureMatrix and + * @ref MaterialAttribute::TextureCoordinates attributes or the per-texture + * @ref MaterialAttribute::SpecularTextureMatrix, + * @ref MaterialAttribute::GlossinessTextureMatrix, + * @ref MaterialAttribute::SpecularTextureCoordinates and + * @ref MaterialAttribute::GlossinessTextureCoordinates variants. + * @see @ref PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture(), + * @ref PbrSpecularGlossinessMaterialData::specularTexture(), + * @ref PbrSpecularGlossinessMaterialData::glossinessTexture() + */ + SpecularGlossinessTexture, + /** * Tangent-space normal map texture index, * @ref MaterialAttributeType::UnsignedInt. - * @see @ref PhongMaterialData::normalTexture() + * @see @ref PhongMaterialData::normalTexture(), + * @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::normalTexture(), + * @ref PbrSpecularGlossinessMaterialData::normalTexture() */ NormalTexture, + /** + * Normal texture swizzle, @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to express arbitrary packing together with other maps in a + * single texture. A two- or three-channel swizzle value is expected. If + * not present, @ref MaterialTextureSwizzle::RGB is assumed. + * + * If the texture is just two-component, the remaining component is + * implicit and calculated as @f$ z = \sqrt{1 - x^2 - y^2} @f$. + * @see @ref PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::normalTextureSwizzle(), + * @ref PbrSpecularGlossinessMaterialData::normalTextureSwizzle() + */ + NormalTextureSwizzle, + /** * Normal texture transformation matrix, * @ref MaterialAttributeType::Matrix3x3. * * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are * present. - * @see @ref PhongMaterialData::normalTextureMatrix() + * @see @ref PhongMaterialData::normalTextureMatrix(), + * @ref PbrMetallicRoughnessMaterialData::normalTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::normalTextureMatrix() */ NormalTextureMatrix, @@ -251,10 +588,102 @@ enum class MaterialAttribute: UnsignedInt { * * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both * are present. - * @see @ref PhongMaterialData::normalTextureCoordinates() + * @see @ref PhongMaterialData::normalTextureCoordinates(), + * @ref PbrMetallicRoughnessMaterialData::normalTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::normalTextureCoordinates() */ NormalTextureCoordinates, + /** + * Occlusion texture index, + * @ref MaterialAttributeType::UnsignedInt. + * @see @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::occlusionTexture(), + * @ref PbrSpecularGlossinessMaterialData::occlusionTexture() + */ + OcclusionTexture, + + /** + * Occlusion texture swizzle, @ref MaterialAttributeType::TextureSwizzle. + * + * Can be used to express arbitrary packing together with other maps in a + * single texture. A single-channel swizzle value is expected. If + * not present, @ref MaterialTextureSwizzle::R is assumed. + * @see @ref PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture(), + * @ref PbrMetallicRoughnessMaterialData::occlusionTextureSwizzle(), + * @ref PbrSpecularGlossinessMaterialData::occlusionTextureSwizzle() + */ + OcclusionTextureSwizzle, + + /** + * Occlusion texture transformation matrix, + * @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrMetallicRoughnessMaterialData::occlusionTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::occlusionTextureSwizzle() + */ + OcclusionTextureMatrix, + + /** + * Occlusion texture coordinate set index, + * @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrMetallicRoughnessMaterialData::occlusionTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::occlusionTextureCoordinates() + */ + OcclusionTextureCoordinates, + + /** + * Emissive color, + * @ref MaterialAttributeType::Vector3. + * + * If @ref MaterialAttribute::EmissiveTexture is present as well, these two + * are multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::emissiveColor(), + * @ref PbrSpecularGlossinessMaterialData::emissiveColor() + */ + EmissiveColor, + + /** + * Emissive texture index, + * @ref MaterialAttributeType::UnsignedInt. + * + * If @ref MaterialAttribute::EmissiveColor is present as well, these two + * are multiplied together. + * @see @ref PbrMetallicRoughnessMaterialData::emissiveTexture(), + * @ref PbrSpecularGlossinessMaterialData::emissiveTexture() + */ + EmissiveTexture, + + /** @todo EmissiveTextureSwizzle? It's a color and I'm not aware of any + existing packing schemes, so probably safe to assume it's always RGB */ + + /** + * Emissive texture transformation matrix, + * @ref MaterialAttributeType::Matrix3x3. + * + * Has a precedence over @ref MaterialAttribute::TextureMatrix if both are + * present. + * @see @ref PbrMetallicRoughnessMaterialData::emissiveTextureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::emissiveTextureMatrix(), + */ + EmissiveTextureMatrix, + + /** + * Emissive texture coordinate set index, + * @ref MaterialAttributeType::UnsignedInt. + * + * Has a precedence over @ref MaterialAttribute::TextureCoordinates if both + * are present. + * @see @ref PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates() + */ + EmissiveTextureCoordinates, + /** * Common texture transformation matrix for all textures, * @ref MaterialAttributeType::Matrix3x3. @@ -262,9 +691,16 @@ enum class MaterialAttribute: UnsignedInt { * @ref MaterialAttribute::AmbientTextureMatrix / * @ref MaterialAttribute::DiffuseTextureMatrix / * @ref MaterialAttribute::SpecularTextureMatrix / - * @ref MaterialAttribute::NormalTextureMatrix have a precedence over this - * attribute for given texture, if present. - * @see @ref PhongMaterialData::textureMatrix() + * @ref MaterialAttribute::MetalnessTextureMatrix / + * @ref MaterialAttribute::RoughnessTextureMatrix / + * @ref MaterialAttribute::GlossinessTextureMatrix / + * @ref MaterialAttribute::NormalTextureMatrix / + * @ref MaterialAttribute::OcclusionTextureMatrix / + * @ref MaterialAttribute::EmissiveTextureMatrix have a precedence over + * this attribute for given texture, if present. + * @see @ref PhongMaterialData::textureMatrix(), + * @ref PbrMetallicRoughnessMaterialData::textureMatrix(), + * @ref PbrSpecularGlossinessMaterialData::textureMatrix() */ TextureMatrix, @@ -275,9 +711,16 @@ enum class MaterialAttribute: UnsignedInt { * @ref MaterialAttribute::AmbientTextureCoordinates / * @ref MaterialAttribute::DiffuseTextureCoordinates / * @ref MaterialAttribute::SpecularTextureCoordinates / - * @ref MaterialAttribute::NormalTextureCoordinates have a precedence + * @ref MaterialAttribute::MetalnessTextureCoordinates / + * @ref MaterialAttribute::RoughnessTextureCoordinates / + * @ref MaterialAttribute::GlossinessTextureCoordinates / + * @ref MaterialAttribute::NormalTextureCoordinates / + * @ref MaterialAttribute::OcclusionTextureCoordinates / + * @ref MaterialAttribute::EmissiveTextureCoordinates have a precedence * over this attribute for given texture, if present. - * @see @ref PhongMaterialData::textureCoordinates() + * @see @ref PhongMaterialData::textureCoordinates(), + * @ref PbrMetallicRoughnessMaterialData::textureCoordinates(), + * @ref PbrSpecularGlossinessMaterialData::textureCoordinates() */ TextureCoordinates, }; @@ -707,7 +1150,19 @@ enum class MaterialType: UnsignedInt { /** * Phong. Use @ref PhongMaterialData for convenience attribute access. */ - Phong = 1 << 0 + Phong = 1 << 0, + + /** + * PBR metallic/roughness. Use @ref PbrMetallicRoughnessMaterialData for + * convenience attribute access. + */ + PbrMetallicRoughness = 1 << 1, + + /** + * PBR specular/glossiness. Use @ref PbrSpecularGlossinessMaterialData for + * convenience attribute access. + */ + PbrSpecularGlossiness = 1 << 2 }; /** @debugoperatorenum{MaterialType} */ diff --git a/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.cpp b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.cpp new file mode 100644 index 000000000..951fd0f95 --- /dev/null +++ b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.cpp @@ -0,0 +1,302 @@ +/* + 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 "PbrMetallicRoughnessMaterialData.h" + +#include "Magnum/Math/Color.h" +#include "Magnum/Math/Matrix3.h" + +namespace Magnum { namespace Trade { + +using namespace Math::Literals; + +bool PbrMetallicRoughnessMaterialData::hasMetalnessTexture() const { + return hasAttribute(MaterialAttribute::MetalnessTexture) || + hasAttribute(MaterialAttribute::MetallicRoughnessTexture); +} + +bool PbrMetallicRoughnessMaterialData::hasRoughnessTexture() const { + return hasAttribute(MaterialAttribute::RoughnessTexture) || + hasAttribute(MaterialAttribute::MetallicRoughnessTexture); +} + +bool PbrMetallicRoughnessMaterialData::hasMetallicRoughnessTexture() const { + return (hasAttribute(MaterialAttribute::MetallicRoughnessTexture) || + (hasAttribute(MaterialAttribute::MetalnessTexture) && + hasAttribute(MaterialAttribute::RoughnessTexture) && + metalnessTextureSwizzle() == MaterialTextureSwizzle::R && + roughnessTextureSwizzle() == MaterialTextureSwizzle::G)) && + metalnessTextureMatrix() == roughnessTextureMatrix() && + metalnessTextureCoordinates() == roughnessTextureCoordinates(); +} + +bool PbrMetallicRoughnessMaterialData::hasRoughnessMetallicOcclusionTexture() const { + if(!(hasAttribute(MaterialAttribute::RoughnessTexture) && + hasAttribute(MaterialAttribute::MetalnessTexture) && + hasAttribute(MaterialAttribute::OcclusionTexture) && + roughnessTextureSwizzle() == MaterialTextureSwizzle::R && + metalnessTextureSwizzle() == MaterialTextureSwizzle::G && + occlusionTextureSwizzle() == MaterialTextureSwizzle::B)) + return false; + + const Matrix3 roughnessTextureMatrix = this->roughnessTextureMatrix(); + const UnsignedInt roughnessTextureCoordinates = this->roughnessTextureCoordinates(); + return metalnessTextureMatrix() == roughnessTextureMatrix && + occlusionTextureMatrix() == roughnessTextureMatrix && + metalnessTextureCoordinates() == roughnessTextureCoordinates && + occlusionTextureCoordinates() == roughnessTextureCoordinates; +} + +bool PbrMetallicRoughnessMaterialData::hasOcclusionRoughnessMetallicTexture() const { + if(!(hasAttribute(MaterialAttribute::OcclusionTexture) && + hasAttribute(MaterialAttribute::RoughnessTexture) && + hasAttribute(MaterialAttribute::MetalnessTexture) && + occlusionTextureSwizzle() == MaterialTextureSwizzle::R && + roughnessTextureSwizzle() == MaterialTextureSwizzle::G && + metalnessTextureSwizzle() == MaterialTextureSwizzle::B)) + return false; + + const Matrix3 occlusionTextureMatrix = this->occlusionTextureMatrix(); + const UnsignedInt occlusionTextureCoordinates = this->occlusionTextureCoordinates(); + return roughnessTextureMatrix() == occlusionTextureMatrix && + metalnessTextureMatrix() == occlusionTextureMatrix && + roughnessTextureCoordinates() == occlusionTextureCoordinates && + metalnessTextureCoordinates() == occlusionTextureCoordinates; +} + +bool PbrMetallicRoughnessMaterialData::hasNormalRoughnessMetallicTexture() const { + if(!(hasAttribute(MaterialAttribute::NormalTexture) && + hasAttribute(MaterialAttribute::RoughnessTexture) && + hasAttribute(MaterialAttribute::MetalnessTexture) && + normalTextureSwizzle() == MaterialTextureSwizzle::RG && + roughnessTextureSwizzle() == MaterialTextureSwizzle::B && + metalnessTextureSwizzle() == MaterialTextureSwizzle::A)) + return false; + + const Matrix3 normalTextureMatrix = this->normalTextureMatrix(); + const UnsignedInt normalTextureCoordinates = this->normalTextureCoordinates(); + return roughnessTextureMatrix() == normalTextureMatrix && + metalnessTextureMatrix() == normalTextureMatrix && + roughnessTextureCoordinates() == normalTextureCoordinates && + metalnessTextureCoordinates() == normalTextureCoordinates; +} + +bool PbrMetallicRoughnessMaterialData::hasTextureTransformation() const { + return hasAttribute(MaterialAttribute::TextureMatrix) || + hasAttribute(MaterialAttribute::BaseColorTextureMatrix) || + hasAttribute(MaterialAttribute::MetalnessTextureMatrix) || + hasAttribute(MaterialAttribute::RoughnessTextureMatrix) || + hasAttribute(MaterialAttribute::NormalTextureMatrix) || + hasAttribute(MaterialAttribute::OcclusionTextureMatrix) || + hasAttribute(MaterialAttribute::EmissiveTextureMatrix);; +} + +bool PbrMetallicRoughnessMaterialData::hasTextureCoordinates() const { + return hasAttribute(MaterialAttribute::TextureCoordinates) || + hasAttribute(MaterialAttribute::BaseColorTextureCoordinates) || + hasAttribute(MaterialAttribute::MetalnessTextureCoordinates) || + hasAttribute(MaterialAttribute::RoughnessTextureCoordinates) || + hasAttribute(MaterialAttribute::NormalTextureCoordinates) || + hasAttribute(MaterialAttribute::OcclusionTextureCoordinates) || + hasAttribute(MaterialAttribute::EmissiveTextureCoordinates); +} + +Color4 PbrMetallicRoughnessMaterialData::baseColor() const { + return attributeOr(MaterialAttribute::BaseColor, 0xffffffff_rgbaf); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::baseColorTexture() const { + return attribute(MaterialAttribute::BaseColorTexture); +} + +Matrix3 PbrMetallicRoughnessMaterialData::baseColorTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::BaseColorTexture), + "Trade::PbrMetallicRoughnessMaterialData::baseColorTextureMatrix(): the material doesn't have a base color texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::BaseColorTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::baseColorTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::BaseColorTexture), + "Trade::PbrMetallicRoughnessMaterialData::baseColorTextureCoordinates(): the material doesn't have a base color texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::BaseColorTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Float PbrMetallicRoughnessMaterialData::metalness() const { + return attributeOr(MaterialAttribute::Metalness, 1.0f); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::metalnessTexture() const { + if(Containers::Optional value = tryAttribute(MaterialAttribute::MetallicRoughnessTexture)) + return *value; + return attribute(MaterialAttribute::MetalnessTexture); +} + +MaterialTextureSwizzle PbrMetallicRoughnessMaterialData::metalnessTextureSwizzle() const { + CORRADE_ASSERT(hasMetalnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureSwizzle(): the material doesn't have a metalness texture", {}); + if(hasAttribute(MaterialAttribute::MetallicRoughnessTexture)) + return MaterialTextureSwizzle::R; + return attributeOr(MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrMetallicRoughnessMaterialData::metalnessTextureMatrix() const { + CORRADE_ASSERT(hasMetalnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureMatrix(): the material doesn't have a metalness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::MetalnessTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::metalnessTextureCoordinates() const { + CORRADE_ASSERT(hasMetalnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureCoordinates(): the material doesn't have a metalness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::MetalnessTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Float PbrMetallicRoughnessMaterialData::roughness() const { + return attributeOr(MaterialAttribute::Roughness, 1.0f); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::roughnessTexture() const { + if(Containers::Optional value = tryAttribute(MaterialAttribute::MetallicRoughnessTexture)) + return *value; + return attribute(MaterialAttribute::RoughnessTexture); +} + +MaterialTextureSwizzle PbrMetallicRoughnessMaterialData::roughnessTextureSwizzle() const { + CORRADE_ASSERT(hasRoughnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureSwizzle(): the material doesn't have a roughness texture", {}); + if(hasAttribute(MaterialAttribute::MetallicRoughnessTexture)) + return MaterialTextureSwizzle::G; + return attributeOr(MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrMetallicRoughnessMaterialData::roughnessTextureMatrix() const { + CORRADE_ASSERT(hasRoughnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureMatrix(): the material doesn't have a roughness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::RoughnessTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::roughnessTextureCoordinates() const { + CORRADE_ASSERT(hasRoughnessTexture(), + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureCoordinates(): the material doesn't have a roughness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::RoughnessTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::normalTexture() const { + return attribute(MaterialAttribute::NormalTexture); +} + +MaterialTextureSwizzle PbrMetallicRoughnessMaterialData::normalTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrMetallicRoughnessMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture", {}); + return attributeOr(MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RGB); +} + +Matrix3 PbrMetallicRoughnessMaterialData::normalTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrMetallicRoughnessMaterialData::normalTextureMatrix(): the material doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::normalTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrMetallicRoughnessMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::occlusionTexture() const { + return attribute(MaterialAttribute::OcclusionTexture); +} + +MaterialTextureSwizzle PbrMetallicRoughnessMaterialData::occlusionTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureSwizzle(): the material doesn't have an occlusion texture", {}); + return attributeOr(MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrMetallicRoughnessMaterialData::occlusionTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureMatrix(): the material doesn't have an occlusion texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::OcclusionTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::occlusionTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureCoordinates(): the material doesn't have an occlusion texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::OcclusionTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Color3 PbrMetallicRoughnessMaterialData::emissiveColor() const { + return attributeOr(MaterialAttribute::EmissiveColor, 0x000000_srgbf); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::emissiveTexture() const { + return attribute(MaterialAttribute::EmissiveTexture); +} + +Matrix3 PbrMetallicRoughnessMaterialData::emissiveTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::EmissiveTexture), + "Trade::PbrMetallicRoughnessMaterialData::emissiveTextureMatrix(): the material doesn't have an emissive texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::EmissiveTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::EmissiveTexture), + "Trade::PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::EmissiveTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Matrix3 PbrMetallicRoughnessMaterialData::textureMatrix() const { + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrMetallicRoughnessMaterialData::textureCoordinates() const { + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +}} diff --git a/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h new file mode 100644 index 000000000..dcfb9f2de --- /dev/null +++ b/src/Magnum/Trade/PbrMetallicRoughnessMaterialData.h @@ -0,0 +1,566 @@ +#ifndef Magnum_Trade_PbrMetallicRoughnessMaterialData_h +#define Magnum_Trade_PbrMetallicRoughnessMaterialData_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::PbrMetallicRoughnessMaterialData + * @m_since_latest + */ + +#include "Magnum/Trade/MaterialData.h" + +namespace Magnum { namespace Trade { + +/** +@brief PBR metallic/roughness material data +@m_since_latest + +@see @ref AbstractImporter::material(), @ref PbrSpecularGlossinessMaterialData, + @ref PhongMaterialData +*/ +class MAGNUM_TRADE_EXPORT PbrMetallicRoughnessMaterialData: public MaterialData { + 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 MaterialData::MaterialData; + #endif + + /** + * @brief Whether the material has a metalness texture + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::MetalnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture attributes is + * present, @cpp false @ce otherwise. + * @see @ref hasRoughnessTexture(), @ref hasMetallicRoughnessTexture() + */ + bool hasMetalnessTexture() const; + + /** + * @brief Whether the material has a roughness texture + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::RoughnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture attributes is + * present, @cpp false @ce otherwise. + * @see @ref hasMetalnessTexture(), @ref hasMetallicRoughnessTexture() + */ + bool hasRoughnessTexture() const; + + /** + * @brief Whether the material has a combined metallic/roughness texture + * + * Returns @cpp true @ce if either the + * @ref MaterialAttribute::MetallicRoughnessTexture attribute is + * present or both @ref MaterialAttribute::MetalnessTexture and + * @ref MaterialAttribute::RoughnessTexture are present, point to + * the same texture ID, @ref MaterialAttribute::MetalnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::R (or omitted, in which case + * it's the default) and @ref MaterialAttribute::RoughnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::G, and ddditionally + * @ref MaterialAttribute::MetalnessTextureMatrix and + * @ref MaterialAttribute::RoughnessTextureMatrix are both either not + * present or have the same value, and + * @ref MaterialAttribute::MetalnessTextureCoordinates and + * @ref MaterialAttribute::RoughnessTextureCoordinates are both either + * not present or have the same value; @cpp false @ce otherwise. + * + * In other words, if this function returns @cpp true @ce, + * @ref metalnessTexture(), @ref metalnessTextureMatrix() and + * @ref metalnessTextureCoordinates() return values common for both + * metalness and roughness texture, and the two are packed together + * with metalness occupying the R channel and roughness the G channel. + * @see @ref hasMetalnessTexture(), @ref hasRoughnessTexture(), + * @ref hasOcclusionRoughnessMetallicTexture(), + * @ref hasRoughnessMetallicOcclusionTexture(), + * @ref hasNormalRoughnessMetallicTexture() + */ + bool hasMetallicRoughnessTexture() const; + + /** + * @brief Whether the material has a combined occlusion/roughness/metallic texture + * + * Returns @cpp true @ce if @ref MaterialAttribute::OcclusionTexture, + * @ref MaterialAttribute::RoughnessTexture and + * @ref MaterialAttribute::MetalnessTexture are all present, point to + * the same texture ID, @ref MaterialAttribute::OcclusionTextureSwizzle + * is set to @ref MaterialTextureSwizzle::R (or omitted, in which case + * it's the default), @ref MaterialAttribute::RoughnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::G and + * @ref MaterialAttribute::MetalnessTextureSwizzle is set to + * @ref MaterialTextureSwizzle::B, and additionally + * @ref MaterialAttribute::OcclusionTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureMatrix and + * @ref MaterialAttribute::MetalnessTextureMatrix are all other not + * present or have the same value, and + * @ref MaterialAttribute::OcclusionTextureCoordinates, + * @ref MaterialAttribute::RoughnessTextureCoordinates and + * @ref MaterialAttribute::MetalnessTextureCoordinates are all either + * not present or have the same value; @cpp false @ce otherwise. + * + * In other words, if this function returns @cpp true @ce, + * @ref occlusionTexture(), @ref occlusionTextureMatrix() and + * @ref occlusionTextureCoordinates() return values common for + * occlusion, roughness and metalness textures, and the three are + * packed together with occlusion occupying the R channel, roughness + * the G channel and metalness the B channel. + * @see @ref hasMetalnessTexture(), @ref hasRoughnessTexture(), + * @ref hasMetallicRoughnessTexture(), + * @ref hasRoughnessMetallicOcclusionTexture(), + * @ref hasNormalRoughnessMetallicTexture() + */ + bool hasOcclusionRoughnessMetallicTexture() const; + + /** + * @brief Whether the material has a combined roughness/metallic/occlusion texture + * + * Returns @cpp true @ce if @ref MaterialAttribute::RoughnessTexture, + * @ref MaterialAttribute::MetalnessTexture and + * @ref MaterialAttribute::OcclusionTexture are all present, point to + * the same texture ID, @ref MaterialAttribute::RoughnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::R (or omitted, in which case + * it's the default), @ref MaterialAttribute::MetalnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::G and + * @ref MaterialAttribute::OcclusionTextureSwizzle is set to + * @ref MaterialTextureSwizzle::B, and additionally + * @ref MaterialAttribute::RoughnessTextureMatrix, + * @ref MaterialAttribute::MetalnessTextureMatrix and + * @ref MaterialAttribute::OcclusionTextureMatrix are all other not + * present or have the same value, and + * @ref MaterialAttribute::RoughnessTextureCoordinates, + * @ref MaterialAttribute::MetalnessTextureCoordinates and + * @ref MaterialAttribute::OcclusionTextureCoordinates are all either + * not present or have the same value; @cpp false @ce otherwise. + * + * In other words, if this function returns @cpp true @ce, + * @ref roughnessTexture(), @ref roughnessTextureMatrix() and + * @ref roughnessTextureCoordinates() return values common for + * roughness, metalness and occlusion textures, and the three are + * packed together with roughness occupying the R channel, metalness + * the G channel and occlusion the B channel. + * @see @ref hasMetalnessTexture(), @ref hasRoughnessTexture(), + * @ref hasMetallicRoughnessTexture(), + * @ref hasOcclusionRoughnessMetallicTexture(), + * @ref hasNormalRoughnessMetallicTexture() + */ + bool hasRoughnessMetallicOcclusionTexture() const; + + /** + * @brief Whether the material has a combined normal/roughness/metallic texture + * + * Returns @cpp true @ce if @ref MaterialAttribute::NormalTexture, + * @ref MaterialAttribute::RoughnessTexture and + * @ref MaterialAttribute::MetalnessTexture are all present, point to + * the same texture ID, @ref MaterialAttribute::NormalTextureSwizzle + * is set to @ref MaterialTextureSwizzle::RG (with the third channel + * implicit), @ref MaterialAttribute::RoughnessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::B and + * @ref MaterialAttribute::MetalnessTextureSwizzle is set to + * @ref MaterialTextureSwizzle::A, and additionally + * @ref MaterialAttribute::NormalTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureMatrix and + * @ref MaterialAttribute::MetalnessTextureMatrix are all other not + * present or have the same value, and + * @ref MaterialAttribute::NormalTextureCoordinates, + * @ref MaterialAttribute::RoughnessTextureCoordinates and + * @ref MaterialAttribute::MetalnessTextureCoordinates are all either + * not present or have the same value; @cpp false @ce otherwise. + * + * In other words, if this function returns @cpp true @ce, + * @ref normalTexture(), @ref normalTextureMatrix() and + * @ref normalTextureCoordinates() return values common for normal, + * roughness and metalness textures, and the three are packed together + * with normals occupying the RG channel, roughness the B channel and + * metalness the A channel. + * @see @ref hasMetalnessTexture(), @ref hasRoughnessTexture(), + * @ref hasMetallicRoughnessTexture(), + * @ref hasRoughnessMetallicOcclusionTexture(), + * @ref hasOcclusionRoughnessMetallicTexture() + */ + bool hasNormalRoughnessMetallicTexture() const; + + /** + * @brief Whether the material has texture transformation + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::BaseColorTextureMatrix, + * @ref MaterialAttribute::MetalnessTextureMatrix, + * @ref MaterialAttribute::RoughnessTextureMatrix, + * @ref MaterialAttribute::NormalTextureMatrix, + * @ref MaterialAttribute::OcclusionTextureMatrix, + * @ref MaterialAttribute::EmissiveTextureMatrix or + * @ref MaterialAttribute::TextureMatrix attributes is present, + * @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::BaseColorTextureCoordinates, + * @ref MaterialAttribute::MetalnessTextureCoordinates, + * @ref MaterialAttribute::RoughnessTextureCoordinates, + * @ref MaterialAttribute::NormalTextureCoordinates, + * @ref MaterialAttribute::OcclusionTextureCoordinates, + * @ref MaterialAttribute::EmissiveTextureCoordinates or + * @ref MaterialAttribute::TextureCoordinates attributes is present and + * has a non-zero value, @cpp false @ce otherwise. + */ + bool hasTextureCoordinates() const; + + /** + * @brief Base color + * + * Convenience access to the @ref MaterialAttribute::BaseColor + * attribute. If not present, the default is @cpp 0xffffffff_srgbaf @ce. + * + * If the material has @ref MaterialAttribute::BaseColorTexture, the + * color and texture is meant to be multiplied together. + */ + Color4 baseColor() const; + + /** + * @brief Base color texture ID + * + * Available only if @ref MaterialAttribute::BaseColorTexture is + * present. Meant to be multiplied with @ref baseColor(). + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt baseColorTexture() const; + + /** + * @brief Base color texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::BaseColorTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::BaseColorTexture. + * @see @ref hasAttribute() + */ + Matrix3 baseColorTextureMatrix() const; + + /** + * @brief Base color texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::BaseColorTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has @ref MaterialAttribute::BaseColorTexture. + * @see @ref hasAttribute() + */ + UnsignedInt baseColorTextureCoordinates() const; + + /** + * @brief Metalness factor + * + * Convenience access to the @ref MaterialAttribute::Metalness + * attribute. If not present, the default is @cpp 1.0f @ce. + * + * If the material has a metalness texture, the factor and texture is + * meant to be multiplied together. + * @see @ref hasMetalnessTexture() + */ + Float metalness() const; + + /** + * @brief Metalness texture ID + * + * Available only if either @ref MaterialAttribute::MetalnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture is present. Meant + * to be multiplied with @ref metalness(). + * @see @ref hasMetalnessTexture(), @ref AbstractImporter::texture() + */ + UnsignedInt metalnessTexture() const; + + /** + * @brief Metalness texture swizzle + * + * If @ref MaterialAttribute::MetallicRoughnessTexture is present, + * returns always @ref MaterialTextureSwizzle::R. Otherwise returns the + * @ref MaterialAttribute::MetalnessTextureSwizzle attribute, or + * @ref MaterialTextureSwizzle::R, if it's not present. Available only + * if the material has a metalness texture. + * @see @ref hasMetalnessTexture() + */ + MaterialTextureSwizzle metalnessTextureSwizzle() const; + + /** + * @brief Metalness texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::MetalnessTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has a metalness texture. + * @see @ref hasMetalnessTexture() + */ + Matrix3 metalnessTextureMatrix() const; + + /** + * @brief Metalness texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::MetalnessTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has a metalness texture. + * @see @ref hasMetalnessTexture() + */ + UnsignedInt metalnessTextureCoordinates() const; + + /** + * @brief Roughness factor + * + * Convenience access to the @ref MaterialAttribute::Roughness + * attribute. If not present, the default is @cpp 1.0f @ce. + * + * If the material has a roughness texture, the factor and texture is + * meant to be multiplied together. + * @see @ref hasRoughnessTexture() + */ + Float roughness() const; + + /** + * @brief Roughness texture ID + * + * Available only if either @ref MaterialAttribute::RoughnessTexture or + * @ref MaterialAttribute::MetallicRoughnessTexture is present. Meant + * to be multiplied with @ref roughness(). + * @see @ref hasRoughnessTexture(), @ref AbstractImporter::texture() + */ + UnsignedInt roughnessTexture() const; + + /** + * @brief Roughness texture swizzle + * + * If @ref MaterialAttribute::MetallicRoughnessTexture is present, + * returns always @ref MaterialTextureSwizzle::G. Otherwise returns the + * @ref MaterialAttribute::RoughnessTextureSwizzle attribute, or + * @ref MaterialTextureSwizzle::R, if it's not present. Available only + * if the material has a roughness texture. + * @see @ref hasRoughnessTexture() + */ + MaterialTextureSwizzle roughnessTextureSwizzle() const; + + /** + * @brief Roughness texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::RoughnessTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has a roughness texture. + * @see @ref hasRoughnessTexture() + */ + Matrix3 roughnessTextureMatrix() const; + + /** + * @brief Roughness texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::RoughnessTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has a roughness texture. + * @see @ref hasRoughnessTexture() + */ + UnsignedInt roughnessTextureCoordinates() const; + + /** + * @brief Normal texture ID + * + * Available only if @ref MaterialAttribute::NormalTexture is present. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt normalTexture() const; + + /** + * @brief Normal texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::NormalTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::NormalTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + Matrix3 normalTextureMatrix() const; + + /** + * @brief Normal texture swizzle + * @m_since_latest + * + * Convenience access to the + * @ref MaterialAttribute::NormalTextureSwizzle attribute. If not + * present, the default is @ref MaterialTextureSwizzle::RGB. Available + * only if @ref MaterialAttribute::NormalTexture is present. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle normalTextureSwizzle() const; + + /** + * @brief Normal texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::NormalTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has @ref MaterialAttribute::NormalTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt normalTextureCoordinates() const; + + /** + * @brief Occlusion texture ID + * + * Available only if @ref MaterialAttribute::OcclusionTexture is present. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt occlusionTexture() const; + + /** + * @brief Occlusion texture swizzle + * + * Convenience access to the + * @ref MaterialAttribute::OcclusionTextureSwizzle attribute. If not + * present, the default is @ref MaterialTextureSwizzle::R. Available + * only if @ref MaterialAttribute::OcclusionTexture is present. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle occlusionTextureSwizzle() const; + + /** + * @brief Occlusion texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::OcclusionTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::OcclusionTexture. + * @see @ref hasAttribute() + */ + Matrix3 occlusionTextureMatrix() const; + + /** + * @brief Occlusion texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::OcclusionTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has @ref MaterialAttribute::OcclusionTexture. + * @see @ref hasAttribute() + */ + UnsignedInt occlusionTextureCoordinates() const; + + /** + * @brief Emissive color + * + * Convenience access to the @ref MaterialAttribute::EmissiveColor + * attribute. If not present, the default is @cpp 0x000000_srgbf @ce + * (i.e, no emission). + * + * If the material has @ref MaterialAttribute::EmissiveTexture, the + * color and texture is meant to be multiplied together. + */ + Color3 emissiveColor() const; + + /** + * @brief Emissive texture ID + * + * Available only if @ref MaterialAttribute::EmissiveTexture is present. + * Meant to be multiplied with @ref emissiveColor(). + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt emissiveTexture() const; + + /* No EmissiveTextureSwizzle attribute right now (implicitly RGB) */ + + /** + * @brief Emissive texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::EmissiveTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::EmissiveTexture. + * @see @ref hasAttribute() + */ + Matrix3 emissiveTextureMatrix() const; + + /** + * @brief Emissive texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::EmissiveTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has @ref MaterialAttribute::EmissiveTexture. + * @see @ref hasAttribute() + */ + UnsignedInt emissiveTextureCoordinates() const; + + /** + * @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() + */ + Matrix3 textureMatrix() 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; +}; + +}} + +#endif diff --git a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp new file mode 100644 index 000000000..d38cebaee --- /dev/null +++ b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.cpp @@ -0,0 +1,251 @@ +/* + 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 "PbrSpecularGlossinessMaterialData.h" + +#include "Magnum/Math/Color.h" +#include "Magnum/Math/Matrix3.h" + +namespace Magnum { namespace Trade { + +using namespace Math::Literals; + +bool PbrSpecularGlossinessMaterialData::hasSpecularTexture() const { + return hasAttribute(MaterialAttribute::SpecularTexture) || + hasAttribute(MaterialAttribute::SpecularGlossinessTexture); +} + +bool PbrSpecularGlossinessMaterialData::hasGlossinessTexture() const { + return hasAttribute(MaterialAttribute::GlossinessTexture) || + hasAttribute(MaterialAttribute::SpecularGlossinessTexture); +} + +bool PbrSpecularGlossinessMaterialData::hasSpecularGlossinessTexture() const { + return (hasAttribute(MaterialAttribute::SpecularGlossinessTexture) || + (hasAttribute(MaterialAttribute::SpecularTexture) && + hasAttribute(MaterialAttribute::GlossinessTexture) && + specularTextureSwizzle() == MaterialTextureSwizzle::RGB && + glossinessTextureSwizzle() == MaterialTextureSwizzle::A)) && + specularTextureMatrix() == glossinessTextureMatrix() && + specularTextureCoordinates() == glossinessTextureCoordinates(); +} + +bool PbrSpecularGlossinessMaterialData::hasTextureTransformation() const { + return hasAttribute(MaterialAttribute::TextureMatrix) || + hasAttribute(MaterialAttribute::DiffuseTextureMatrix) || + hasAttribute(MaterialAttribute::SpecularTextureMatrix) || + hasAttribute(MaterialAttribute::GlossinessTextureMatrix) || + hasAttribute(MaterialAttribute::NormalTextureMatrix) || + hasAttribute(MaterialAttribute::OcclusionTextureMatrix) || + hasAttribute(MaterialAttribute::EmissiveTextureMatrix); +} + +bool PbrSpecularGlossinessMaterialData::hasTextureCoordinates() const { + return hasAttribute(MaterialAttribute::TextureCoordinates) || + hasAttribute(MaterialAttribute::DiffuseTextureCoordinates) || + hasAttribute(MaterialAttribute::SpecularTextureCoordinates) || + hasAttribute(MaterialAttribute::GlossinessTextureCoordinates) || + hasAttribute(MaterialAttribute::NormalTextureCoordinates) || + hasAttribute(MaterialAttribute::OcclusionTextureCoordinates) || + hasAttribute(MaterialAttribute::EmissiveTextureCoordinates); +} + +Color4 PbrSpecularGlossinessMaterialData::diffuseColor() const { + return attributeOr(MaterialAttribute::DiffuseColor, 0xffffffff_srgbaf); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::diffuseTexture() const { + return attribute(MaterialAttribute::DiffuseTexture); +} + +Matrix3 PbrSpecularGlossinessMaterialData::diffuseTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::DiffuseTexture), + "Trade::PbrSpecularGlossinessMaterialData::diffuseTextureMatrix(): the material doesn't have a diffuse texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::DiffuseTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::diffuseTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::DiffuseTexture), + "Trade::PbrSpecularGlossinessMaterialData::diffuseTextureCoordinates(): the material doesn't have a diffuse texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::DiffuseTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Color4 PbrSpecularGlossinessMaterialData::specularColor() const { + return attributeOr(MaterialAttribute::SpecularColor, 0xffffff00_srgbaf); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::specularTexture() const { + if(Containers::Optional value = tryAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return *value; + return attribute(MaterialAttribute::SpecularTexture); +} + +MaterialTextureSwizzle PbrSpecularGlossinessMaterialData::specularTextureSwizzle() const { + CORRADE_ASSERT(hasSpecularTexture(), + "Trade::PbrSpecularGlossinessMaterialData::specularTextureSwizzle(): the material doesn't have a specular texture", {}); + if(hasAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return MaterialTextureSwizzle::RGB; + return attributeOr(MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGB); +} + +Matrix3 PbrSpecularGlossinessMaterialData::specularTextureMatrix() const { + CORRADE_ASSERT(hasSpecularTexture(), + "Trade::PbrSpecularGlossinessMaterialData::specularTextureMatrix(): the material doesn't have a specular texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::SpecularTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::specularTextureCoordinates() const { + CORRADE_ASSERT(hasSpecularTexture(), + "Trade::PbrSpecularGlossinessMaterialData::specularTextureCoordinates(): the material doesn't have a specular texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::SpecularTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Float PbrSpecularGlossinessMaterialData::glossiness() const { + return attributeOr(MaterialAttribute::Glossiness, 1.0f); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::glossinessTexture() const { + if(Containers::Optional value = tryAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return *value; + return attribute(MaterialAttribute::GlossinessTexture); +} + +MaterialTextureSwizzle PbrSpecularGlossinessMaterialData::glossinessTextureSwizzle() const { + CORRADE_ASSERT(hasGlossinessTexture(), + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureSwizzle(): the material doesn't have a glossiness texture", {}); + if(hasAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return MaterialTextureSwizzle::A; + return attributeOr(MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrSpecularGlossinessMaterialData::glossinessTextureMatrix() const { + CORRADE_ASSERT(hasGlossinessTexture(), + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureMatrix(): the material doesn't have a glossiness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::GlossinessTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::glossinessTextureCoordinates() const { + CORRADE_ASSERT(hasGlossinessTexture(), + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureCoordinates(): the material doesn't have a glossiness texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::GlossinessTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::normalTexture() const { + return attribute(MaterialAttribute::NormalTexture); +} + +MaterialTextureSwizzle PbrSpecularGlossinessMaterialData::normalTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrSpecularGlossinessMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture", {}); + return attributeOr(MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RGB); +} + +Matrix3 PbrSpecularGlossinessMaterialData::normalTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrSpecularGlossinessMaterialData::normalTextureMatrix(): the material doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::normalTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PbrSpecularGlossinessMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::NormalTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::occlusionTexture() const { + return attribute(MaterialAttribute::OcclusionTexture); +} + +MaterialTextureSwizzle PbrSpecularGlossinessMaterialData::occlusionTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureSwizzle(): the material doesn't have an occlusion texture", {}); + return attributeOr(MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::R); +} + +Matrix3 PbrSpecularGlossinessMaterialData::occlusionTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureMatrix(): the material doesn't have an occlusion texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::OcclusionTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::occlusionTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::OcclusionTexture), + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureCoordinates(): the material doesn't have an occlusion texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::OcclusionTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Color3 PbrSpecularGlossinessMaterialData::emissiveColor() const { + return attributeOr(MaterialAttribute::EmissiveColor, 0x000000_srgbf); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::emissiveTexture() const { + return attribute(MaterialAttribute::EmissiveTexture); +} + +Matrix3 PbrSpecularGlossinessMaterialData::emissiveTextureMatrix() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::EmissiveTexture), + "Trade::PbrSpecularGlossinessMaterialData::emissiveTextureMatrix(): the material doesn't have an emissive texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::EmissiveTextureMatrix)) + return *value; + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::EmissiveTexture), + "Trade::PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture", {}); + if(Containers::Optional value = tryAttribute(MaterialAttribute::EmissiveTextureCoordinates)) + return *value; + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +Matrix3 PbrSpecularGlossinessMaterialData::textureMatrix() const { + return attributeOr(MaterialAttribute::TextureMatrix, Matrix3{}); +} + +UnsignedInt PbrSpecularGlossinessMaterialData::textureCoordinates() const { + return attributeOr(MaterialAttribute::TextureCoordinates, 0u); +} + +}} diff --git a/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h new file mode 100644 index 000000000..719d87f94 --- /dev/null +++ b/src/Magnum/Trade/PbrSpecularGlossinessMaterialData.h @@ -0,0 +1,460 @@ +#ifndef Magnum_Trade_PbrSpecularGlossinessMaterialData_h +#define Magnum_Trade_PbrSpecularGlossinessMaterialData_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::PbrSpecularGlossinessMaterialData + * @m_since_latest + */ + +#include "Magnum/Trade/MaterialData.h" + +namespace Magnum { namespace Trade { + +/** +@brief PBR specular/glossiness material data +@m_since_latest + +@see @ref AbstractImporter::material(), @ref PbrMetallicRoughnessMaterialData, + @ref PhongMaterialData +*/ +class MAGNUM_TRADE_EXPORT PbrSpecularGlossinessMaterialData: public MaterialData { + 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 MaterialData::MaterialData; + #endif + + /** + * @brief Whether the material has a specular texture + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::SpecularTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture attributes is + * present, @cpp false @ce otherwise. + * @see @ref hasGlossinessTexture(), + * @ref hasSpecularGlossinessTexture() + */ + bool hasSpecularTexture() const; + + /** + * @brief Whether the material has a glossiness texture + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::GlossinessTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture attributes is + * present, @cpp false @ce otherwise. + * @see @ref hasSpecularTexture(), + * @ref hasSpecularGlossinessTexture() + */ + bool hasGlossinessTexture() const; + + /** + * @brief Whether the material has a combined specular/glossiness texture + * + * Returns @cpp true @ce if either the + * @ref MaterialAttribute::SpecularGlossinessTexture attribute is + * present or both @ref MaterialAttribute::SpecularTexture and + * @ref MaterialAttribute::GlossinessTexture are present, point to + * the same texture ID and @ref MaterialAttribute::GlossinessTextureSwizzle + * is set to @ref MaterialTextureSwizzle::A, and ddditionally + * @ref MaterialAttribute::SpecularTextureMatrix and + * @ref MaterialAttribute::GlossinessTextureMatrix are both either not + * present or have the same value, and + * @ref MaterialAttribute::SpecularTextureCoordinates and + * @ref MaterialAttribute::GlossinessTextureCoordinates are both either + * not present or have the same value; @cpp false @ce otherwise. + * + * In other words, if this function returns @cpp true @ce, + * @ref specularTexture(), @ref specularTextureMatrix() and + * @ref specularTextureCoordinates() return values common for both + * specular and glossiness texture, and the two are packed together + * with specular occupying the RGB channels and glossiness the alpha. + * @see @ref hasSpecularTexture(), @ref hasGlossinessTexture() + */ + bool hasSpecularGlossinessTexture() const; + + /** + * @brief Whether the material has texture transformation + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::DiffuseTextureMatrix, + * @ref MaterialAttribute::SpecularTextureMatrix, + * @ref MaterialAttribute::GlossinessTextureMatrix, + * @ref MaterialAttribute::NormalTextureMatrix, + * @ref MaterialAttribute::OcclusionTextureMatrix, + * @ref MaterialAttribute::EmissiveTextureMatrix or + * @ref MaterialAttribute::TextureMatrix attributes is present, + * @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::DiffuseTextureCoordinates, + * @ref MaterialAttribute::SpecularTextureCoordinates, + * @ref MaterialAttribute::GlossinessTextureCoordinates, + * @ref MaterialAttribute::NormalTextureCoordinates, + * @ref MaterialAttribute::OcclusionTextureCoordinates, + * @ref MaterialAttribute::EmissiveTextureCoordinates or + * @ref MaterialAttribute::TextureCoordinates attributes is present and + * has a non-zero value, @cpp false @ce otherwise. + */ + bool hasTextureCoordinates() const; + + /** + * @brief Base color + * + * Convenience access to the @ref MaterialAttribute::DiffuseColor + * attribute. If not present, the default is @cpp 0xffffffff_srgbaf @ce. + * + * If the material has @ref MaterialAttribute::DiffuseTexture, the + * color and texture is meant to be multiplied together. + */ + Color4 diffuseColor() const; + + /** + * @brief Base color texture ID + * + * Available only if @ref MaterialAttribute::DiffuseTexture is + * present. Meant to be multiplied with @ref diffuseColor(). + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt diffuseTexture() const; + + /** + * @brief Base color texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::DiffuseTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::DiffuseTexture. + * @see @ref hasAttribute() + */ + Matrix3 diffuseTextureMatrix() const; + + /** + * @brief Base color texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::DiffuseTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has @ref MaterialAttribute::DiffuseTexture. + * @see @ref hasAttribute() + */ + UnsignedInt diffuseTextureCoordinates() const; + + /** + * @brief Specular color + * + * Convenience access to the @ref MaterialAttribute::SpecularColor + * attribute. If not present, the default is @cpp 0xffffff00_srgbaf @ce. + * + * If the material has a specular texture, the color and texture is + * meant to be multiplied together. + * @see @ref hasSpecularTexture() + */ + Color4 specularColor() const; + + /** + * @brief Specular texture ID + * + * Available only if either @ref MaterialAttribute::SpecularTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture is present. Meant + * to be multiplied with @ref specularColor(). + * @see @ref hasSpecularTexture(), @ref AbstractImporter::texture() + */ + UnsignedInt specularTexture() const; + + /** + * @brief Specular texture swizzle + * + * If @ref MaterialAttribute::SpecularGlossinessTexture is present, + * returns always @ref MaterialTextureSwizzle::RGB. Otherwise returns + * the @ref MaterialAttribute::SpecularTextureSwizzle attribute, or + * @ref MaterialTextureSwizzle::RGB if it's not present. Available only + * if the material has a specular texture. + * @see @ref hasSpecularTexture() + */ + MaterialTextureSwizzle specularTextureSwizzle() const; + + /** + * @brief Specular texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::SpecularTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has a specular texture. + * @see @ref hasSpecularTexture() + */ + Matrix3 specularTextureMatrix() const; + + /** + * @brief Specular texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::SpecularTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has a specular texture. + * @see @ref hasSpecularTexture() + */ + UnsignedInt specularTextureCoordinates() const; + + /** + * @brief Glossiness factor + * + * Convenience access to the @ref MaterialAttribute::Glossiness + * attribute. If not present, the default is @cpp 1.0f @ce. + * + * If the material has a glossiness texture, the factor and texture is + * meant to be multiplied together. + * @see @ref hasGlossinessTexture() + */ + Float glossiness() const; + + /** + * @brief Glossiness texture ID + * + * Available only if either @ref MaterialAttribute::GlossinessTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture is present. Meant + * to be multiplied with @ref glossiness(). + * @see @ref hasGlossinessTexture(), @ref AbstractImporter::texture() + */ + UnsignedInt glossinessTexture() const; + + /** + * @brief Glossiness texture swizzle + * + * If @ref MaterialAttribute::SpecularGlossinessTexture is present, + * returns always @ref MaterialTextureSwizzle::A. Otherwise returns the + * @ref MaterialAttribute::GlossinessTextureSwizzle attribute, or + * @ref MaterialTextureSwizzle::R if it's not present. Available only + * if the material has a glossiness texture. + * @see @ref hasGlossinessTexture() + */ + MaterialTextureSwizzle glossinessTextureSwizzle() const; + + /** + * @brief Glossiness texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::GlossinessTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has a glossiness texture. + * @see @ref hasGlossinessTexture() + */ + Matrix3 glossinessTextureMatrix() const; + + /** + * @brief Glossiness texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::GlossinessTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has a glossiness texture. + * @see @ref hasGlossinessTexture() + */ + UnsignedInt glossinessTextureCoordinates() const; + + /** + * @brief Normal texture ID + * + * Available only if @ref MaterialAttribute::NormalTexture is present. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt normalTexture() const; + + /** + * @brief Normal texture swizzle + * + * Convenience access to the + * @ref MaterialAttribute::NormalTextureSwizzle attribute. If not + * present, the default is @ref MaterialTextureSwizzle::RGB. Available + * only if @ref MaterialAttribute::NormalTexture is present. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle normalTextureSwizzle() const; + + /** + * @brief Normal texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::NormalTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::NormalTexture. + * @see @ref hasAttribute() + */ + Matrix3 normalTextureMatrix() const; + + /** + * @brief Normal texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::NormalTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has @ref MaterialAttribute::NormalTexture. + * @see @ref hasAttribute() + */ + UnsignedInt normalTextureCoordinates() const; + + /** + * @brief Occlusion texture ID + * + * Available only if @ref MaterialAttribute::OcclusionTexture is present. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt occlusionTexture() const; + + /** + * @brief Occlusion texture swizzle + * + * Convenience access to the + * @ref MaterialAttribute::OcclusionTextureSwizzle attribute. If not + * present, the default is @ref MaterialTextureSwizzle::R. Available + * only if @ref MaterialAttribute::OcclusionTexture is present. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle occlusionTextureSwizzle() const; + + /** + * @brief Occlusion texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::OcclusionTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::OcclusionTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + Matrix3 occlusionTextureMatrix() const; + + /** + * @brief Occlusion texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::OcclusionTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither is + * present, the default is @cpp 0 @ce. Available only if the material + * has @ref MaterialAttribute::OcclusionTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt occlusionTextureCoordinates() const; + + /** + * @brief Emissive color + * + * Convenience access to the @ref MaterialAttribute::EmissiveColor + * attribute. If not present, the default is @cpp 0x000000_srgbf @ce + * (i.e, no emission). + * + * If the material has @ref MaterialAttribute::EmissiveTexture, the + * color and texture is meant to be multiplied together. + */ + Color3 emissiveColor() const; + + /** + * @brief Emissive texture ID + * + * Available only if @ref MaterialAttribute::EmissiveTexture is present. + * Meant to be multiplied with @ref emissiveColor(). + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt emissiveTexture() const; + + /* No EmissiveTextureSwizzle attribute right now (implicitly RGB) */ + + /** + * @brief Emissive texture coordinate transformation matrix + * + * Convenience access to the @ref MaterialAttribute::EmissiveTextureMatrix + * / @ref MaterialAttribute::TextureMatrix attributes. If neither is + * present, the default is an identity matrix. Available only if the + * material has @ref MaterialAttribute::EmissiveTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + Matrix3 emissiveTextureMatrix() const; + + /** + * @brief Emissive texture coordinate set + * + * Convenience access to the @ref MaterialAttribute::EmissiveTextureCoordinates + * / @ref MaterialAttribute::TextureCoordinates attributes. If neither + * is present, the default is @cpp 0 @ce. Available only if the + * material has @ref MaterialAttribute::EmissiveTexture. + * @see @ref hasAttribute(), @ref AbstractImporter::texture() + */ + UnsignedInt emissiveTextureCoordinates() const; + + /** + * @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() + */ + Matrix3 textureMatrix() 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; +}; + +}} + +#endif diff --git a/src/Magnum/Trade/PhongMaterialData.cpp b/src/Magnum/Trade/PhongMaterialData.cpp index 2c596b4a3..a251a7546 100644 --- a/src/Magnum/Trade/PhongMaterialData.cpp +++ b/src/Magnum/Trade/PhongMaterialData.cpp @@ -115,7 +115,7 @@ PhongMaterialData::Flags PhongMaterialData::flags() const { flags |= Flag::AmbientTexture; if(hasAttribute(MaterialAttribute::DiffuseTexture)) flags |= Flag::DiffuseTexture; - if(hasAttribute(MaterialAttribute::SpecularTexture)) + if(hasSpecularTexture()) flags |= Flag::SpecularTexture; if(hasAttribute(MaterialAttribute::NormalTexture)) flags |= Flag::NormalTexture; @@ -129,6 +129,11 @@ PhongMaterialData::Flags PhongMaterialData::flags() const { CORRADE_IGNORE_DEPRECATED_POP #endif +bool PhongMaterialData::hasSpecularTexture() const { + return hasAttribute(MaterialAttribute::SpecularTexture) || + hasAttribute(MaterialAttribute::SpecularGlossinessTexture); +} + bool PhongMaterialData::hasTextureTransformation() const { return hasAttribute(MaterialAttribute::AmbientTextureMatrix) || hasAttribute(MaterialAttribute::DiffuseTextureMatrix) || @@ -195,15 +200,25 @@ UnsignedInt PhongMaterialData::diffuseTextureCoordinates() const { } Color4 PhongMaterialData::specularColor() const { - return attributeOr(MaterialAttribute::SpecularColor, 0xffffffff_rgbaf); + return attributeOr(MaterialAttribute::SpecularColor, 0xffffff00_rgbaf); } UnsignedInt PhongMaterialData::specularTexture() const { + if(Containers::Optional value = tryAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return *value; return attribute(MaterialAttribute::SpecularTexture); } +MaterialTextureSwizzle PhongMaterialData::specularTextureSwizzle() const { + CORRADE_ASSERT(hasSpecularTexture(), + "Trade::PhongMaterialData::specularTextureSwizzle(): the material doesn't have a specular texture", {}); + if(hasAttribute(MaterialAttribute::SpecularGlossinessTexture)) + return MaterialTextureSwizzle::RGB; + return attributeOr(MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGB); +} + Matrix3 PhongMaterialData::specularTextureMatrix() const { - CORRADE_ASSERT(hasAttribute(MaterialAttribute::SpecularTexture), + CORRADE_ASSERT(hasSpecularTexture(), "Trade::PhongMaterialData::specularTextureMatrix(): the material doesn't have a specular texture", {}); if(Containers::Optional set = tryAttribute(MaterialAttribute::SpecularTextureMatrix)) return *set; @@ -211,7 +226,7 @@ Matrix3 PhongMaterialData::specularTextureMatrix() const { } UnsignedInt PhongMaterialData::specularTextureCoordinates() const { - CORRADE_ASSERT(hasAttribute(MaterialAttribute::SpecularTexture), + CORRADE_ASSERT(hasSpecularTexture(), "Trade::PhongMaterialData::specularTextureCoordinates(): the material doesn't have a specular texture", {}); if(Containers::Optional set = tryAttribute(MaterialAttribute::SpecularTextureCoordinates)) return *set; @@ -222,6 +237,12 @@ UnsignedInt PhongMaterialData::normalTexture() const { return attribute(MaterialAttribute::NormalTexture); } +MaterialTextureSwizzle PhongMaterialData::normalTextureSwizzle() const { + CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), + "Trade::PhongMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture", {}); + return attributeOr(MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RGB); +} + Matrix3 PhongMaterialData::normalTextureMatrix() const { CORRADE_ASSERT(hasAttribute(MaterialAttribute::NormalTexture), "Trade::PhongMaterialData::normalTextureMatrix(): the material doesn't have a normal texture", {}); diff --git a/src/Magnum/Trade/PhongMaterialData.h b/src/Magnum/Trade/PhongMaterialData.h index d7d8cce3f..646047556 100644 --- a/src/Magnum/Trade/PhongMaterialData.h +++ b/src/Magnum/Trade/PhongMaterialData.h @@ -37,7 +37,8 @@ namespace Magnum { namespace Trade { /** @brief Phong material data -@see @ref AbstractImporter::material() +@see @ref AbstractImporter::material(), @ref PbrMetallicRoughnessMaterialData, + @ref PbrSpecularGlossinessMaterialData */ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { public: @@ -227,6 +228,17 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { CORRADE_IGNORE_DEPRECATED_POP #endif + /** + * @brief Whether the material has a specular texture + * @m_since_latest + * + * Returns @cpp true @ce if any of the + * @ref MaterialAttribute::SpecularTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture attributes is + * present, @cpp false @ce otherwise. + */ + bool hasSpecularTexture() const; + /** * @brief Whether the material has texture transformation * @m_since_latest @@ -390,23 +402,37 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { * @brief Specular color * * Convenience access to the @ref MaterialAttribute::SpecularColor - * attribute. If not present, the default is @cpp 0xffffffff_rgbaf @ce. + * attribute. If not present, the default is @cpp 0xffffff00_rgbaf @ce. * - * If the material has @ref MaterialAttribute::SpecularTexture, the - * color and texture is meant to be multiplied together. - * @see @ref hasAttribute() + * If the material has a specular texture, the color and texture is + * meant to be multiplied together. + * @see @ref hasSpecularTexture() */ Color4 specularColor() const; /** * @brief Specular texture ID * - * Available only if @ref MaterialAttribute::SpecularTexture is - * present. Meant to be multiplied with @ref specularColor(). + * Available only if either @ref MaterialAttribute::SpecularTexture or + * @ref MaterialAttribute::SpecularGlossinessTexture is present. Meant + * to be multiplied with @ref specularColor(). * @see @ref hasAttribute(), @ref AbstractImporter::texture() */ UnsignedInt specularTexture() const; + /** + * @brief Specular texture swizzle + * @m_since_latest + * + * If @ref MaterialAttribute::SpecularGlossinessTexture is present, + * returns always @ref MaterialTextureSwizzle::RGB. Otherwise returns + * the @ref MaterialAttribute::SpecularTextureSwizzle attribute, or + * @ref MaterialTextureSwizzle::RGB if it's not present. Available only + * if the material has a specular texture. + * @see @ref hasSpecularTexture() + */ + MaterialTextureSwizzle specularTextureSwizzle() const; + /** * @brief Specular texture coordinate transformation matrix * @m_since_latest @@ -414,8 +440,8 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { * Convenience access to the @ref MaterialAttribute::SpecularTextureMatrix * / @ref MaterialAttribute::TextureMatrix attributes. If neither is * present, the default is an identity matrix. Available only if the - * material has @ref MaterialAttribute::SpecularTexture. - * @see @ref hasAttribute() + * material has a specular texture. + * @see @ref hasSpecularTexture() */ Matrix3 specularTextureMatrix() const; @@ -426,8 +452,8 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { * Convenience access to the @ref MaterialAttribute::SpecularTextureCoordinates * / @ref MaterialAttribute::TextureCoordinates attributes. If neither * is present, the default is @cpp 0 @ce. Available only if the - * material has @ref MaterialAttribute::SpecularTexture. - * @see @ref hasAttribute() + * material has a specular texture. + * @see @ref hasSpecularTexture() */ UnsignedInt specularTextureCoordinates() const; @@ -451,6 +477,18 @@ class MAGNUM_TRADE_EXPORT PhongMaterialData: public MaterialData { */ UnsignedInt normalTexture() const; + /** + * @brief Normal texture swizzle + * @m_since_latest + * + * Convenience access to the + * @ref MaterialAttribute::NormalTextureSwizzle attribute. If not + * present, the default is @ref MaterialTextureSwizzle::RGB. Available + * only if @ref MaterialAttribute::NormalTexture is present. + * @see @ref hasAttribute() + */ + MaterialTextureSwizzle normalTextureSwizzle() const; + /** * @brief Normal texture coordinate transformation matrix * @m_since_latest diff --git a/src/Magnum/Trade/Test/MaterialDataTest.cpp b/src/Magnum/Trade/Test/MaterialDataTest.cpp index fe45595d3..783c589aa 100644 --- a/src/Magnum/Trade/Test/MaterialDataTest.cpp +++ b/src/Magnum/Trade/Test/MaterialDataTest.cpp @@ -34,6 +34,8 @@ #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Trade/MaterialData.h" +#include "Magnum/Trade/PbrMetallicRoughnessMaterialData.h" +#include "Magnum/Trade/PbrSpecularGlossinessMaterialData.h" #include "Magnum/Trade/PhongMaterialData.h" namespace Magnum { namespace Trade { namespace Test { namespace { @@ -127,11 +129,33 @@ class MaterialDataTest: public TestSuite::Tester { void constructPhongDeprecatedNoTextureCoordinatesFlag(); #endif + void pbrMetallicRoughnessAccess(); + void pbrMetallicRoughnessAccessDefaults(); + void pbrMetallicRoughnessAccessTextured(); + void pbrMetallicRoughnessAccessTexturedDefaults(); + void pbrMetallicRoughnessAccessTexturedImplicitPackedMetallicRoughness(); + void pbrMetallicRoughnessAccessTexturedExplicitPackedMetallicRoughness(); + void pbrMetallicRoughnessAccessTexturedExplicitPackedRoughnessMetallicOcclusion(); + void pbrMetallicRoughnessAccessTexturedExplicitPackedOcclusionRoughnessMetallic(); + void pbrMetallicRoughnessAccessTexturedExplicitPackedNormalRoughnessMetallic(); + void pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates(); + void pbrMetallicRoughnessAccessInvalidTextures(); + + void pbrSpecularGlossinessAccess(); + void pbrSpecularGlossinessAccessDefaults(); + void pbrSpecularGlossinessAccessTextured(); + void pbrSpecularGlossinessAccessTexturedDefaults(); + void pbrSpecularGlossinessAccessTexturedImplicitPackedSpecularGlossiness(); + void pbrSpecularGlossinessAccessTexturedExplicitPackedSpecularGlossiness(); + void pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinates(); + void pbrSpecularGlossinessAccessInvalidTextures(); + void phongAccess(); void phongAccessDefaults(); void phongAccessTextured(); void phongAccessTexturedDefaults(); void phongAccessTexturedSingleMatrixCoordinates(); + void phongAccessTexturedImplicitPackedSpecularGlossiness(); void phongAccessInvalidTextures(); void debugAttribute(); @@ -264,11 +288,33 @@ MaterialDataTest::MaterialDataTest() { &MaterialDataTest::constructPhongDeprecatedNoTextureCoordinatesFlag, #endif + &MaterialDataTest::pbrMetallicRoughnessAccess, + &MaterialDataTest::pbrMetallicRoughnessAccessDefaults, + &MaterialDataTest::pbrMetallicRoughnessAccessTextured, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedDefaults, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedImplicitPackedMetallicRoughness, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedMetallicRoughness, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedRoughnessMetallicOcclusion, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedOcclusionRoughnessMetallic, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedNormalRoughnessMetallic, + &MaterialDataTest::pbrMetallicRoughnessAccessTexturedSingleMatrixCoordinates, + &MaterialDataTest::pbrMetallicRoughnessAccessInvalidTextures, + + &MaterialDataTest::pbrSpecularGlossinessAccess, + &MaterialDataTest::pbrSpecularGlossinessAccessDefaults, + &MaterialDataTest::pbrSpecularGlossinessAccessTextured, + &MaterialDataTest::pbrSpecularGlossinessAccessTexturedDefaults, + &MaterialDataTest::pbrSpecularGlossinessAccessTexturedImplicitPackedSpecularGlossiness, + &MaterialDataTest::pbrSpecularGlossinessAccessTexturedExplicitPackedSpecularGlossiness, + &MaterialDataTest::pbrSpecularGlossinessAccessTexturedSingleMatrixCoordinates, + &MaterialDataTest::pbrSpecularGlossinessAccessInvalidTextures, + &MaterialDataTest::phongAccess, &MaterialDataTest::phongAccessDefaults, &MaterialDataTest::phongAccessTextured, &MaterialDataTest::phongAccessTexturedDefaults, &MaterialDataTest::phongAccessTexturedSingleMatrixCoordinates, + &MaterialDataTest::phongAccessTexturedImplicitPackedSpecularGlossiness, &MaterialDataTest::phongAccessInvalidTextures, &MaterialDataTest::debugAttribute, @@ -2086,6 +2132,1003 @@ void MaterialDataTest::constructPhongDeprecatedNoTextureCoordinatesFlag() { } #endif +void MaterialDataTest::pbrMetallicRoughnessAccess() { + MaterialData base{MaterialType::PbrMetallicRoughness, { + {MaterialAttribute::BaseColor, 0xccffbbff_rgbaf}, + {MaterialAttribute::Metalness, 0.5f}, + {MaterialAttribute::Roughness, 0.79f}, + {MaterialAttribute::EmissiveColor, 0x111111_rgbf} + }}; + + CORRADE_COMPARE(base.types(), MaterialType::PbrMetallicRoughness); + const PbrMetallicRoughnessMaterialData& data = static_cast(base); + + CORRADE_VERIFY(!data.hasMetalnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessTexture()); + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.baseColor(), 0xccffbbff_rgbaf); + CORRADE_COMPARE(data.metalness(), 0.5f); + CORRADE_COMPARE(data.roughness(), 0.79f); + CORRADE_COMPARE(data.emissiveColor(), 0x111111_rgbf); +} + +void MaterialDataTest::pbrMetallicRoughnessAccessDefaults() { + MaterialData base{{}, {}}; + + CORRADE_COMPARE(base.types(), MaterialTypes{}); + /* Casting is fine even if the type doesn't include PbrMetallicRoughness */ + const PbrMetallicRoughnessMaterialData& data = static_cast(base); + + CORRADE_VERIFY(!data.hasMetalnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessTexture()); + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.baseColor(), 0xffffffff_rgbaf); + 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() { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::BaseColor, 0xccffbbff_rgbaf}, + {MaterialAttribute::BaseColorTexture, 0u}, + {MaterialAttribute::BaseColorTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::BaseColorTextureCoordinates, 2u}, + {MaterialAttribute::Metalness, 0.5f}, + {MaterialAttribute::MetalnessTexture, 1u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u}, + {MaterialAttribute::Roughness, 0.79f}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({1.0f, 1.0f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 4u}, + {MaterialAttribute::NormalTexture, 3u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::BA}, + {MaterialAttribute::NormalTextureMatrix, Matrix3::scaling({1.0f, 0.5f})}, + {MaterialAttribute::NormalTextureCoordinates, 5u}, + {MaterialAttribute::OcclusionTexture, 4u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({1.0f, 0.75f})}, + {MaterialAttribute::OcclusionTextureCoordinates, 6u}, + {MaterialAttribute::EmissiveColor, 0x111111_rgbf}, + {MaterialAttribute::EmissiveTexture, 5u}, + {MaterialAttribute::EmissiveTextureMatrix, Matrix3::scaling({0.75f, 0.5f})}, + {MaterialAttribute::EmissiveTextureCoordinates, 7u} + }}; + + CORRADE_VERIFY(data.hasMetalnessTexture()); + CORRADE_VERIFY(data.hasRoughnessTexture()); + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.baseColor(), 0xccffbbff_rgbaf); + CORRADE_COMPARE(data.baseColorTexture(), 0); + CORRADE_COMPARE(data.baseColorTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.baseColorTextureCoordinates(), 2); + CORRADE_COMPARE(data.metalness(), 0.5f); + CORRADE_COMPARE(data.metalnessTexture(), 1); + CORRADE_COMPARE(data.metalnessTextureSwizzle(), MaterialTextureSwizzle::G); + CORRADE_COMPARE(data.metalnessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.metalnessTextureCoordinates(), 3); + CORRADE_COMPARE(data.roughness(), 0.79f); + CORRADE_COMPARE(data.roughnessTexture(), 2); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::scaling({1.0f, 1.0f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 4); + CORRADE_COMPARE(data.normalTexture(), 3); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::BA); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({1.0f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 5); + CORRADE_COMPARE(data.occlusionTexture(), 4); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3::scaling({1.0f, 0.75f})); + CORRADE_COMPARE(data.occlusionTextureSwizzle(), MaterialTextureSwizzle::B); + CORRADE_COMPARE(data.occlusionTextureCoordinates(), 6); + CORRADE_COMPARE(data.emissiveColor(), 0x111111_rgbf); + 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() { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::BaseColorTexture, 1u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 3u}, + {MaterialAttribute::NormalTexture, 4u}, + {MaterialAttribute::OcclusionTexture, 5u}, + {MaterialAttribute::EmissiveTexture, 6u} + }}; + + CORRADE_VERIFY(data.hasMetalnessTexture()); + CORRADE_VERIFY(data.hasRoughnessTexture()); + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.baseColor(), 0xffffffff_rgbaf); + CORRADE_COMPARE(data.baseColorTexture(), 1); + CORRADE_COMPARE(data.baseColorTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.baseColorTextureCoordinates(), 0); + CORRADE_COMPARE(data.metalness(), 1.0f); + CORRADE_COMPARE(data.metalnessTexture(), 2); + CORRADE_COMPARE(data.metalnessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.metalnessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.metalnessTextureCoordinates(), 0); + CORRADE_COMPARE(data.roughness(), 1.0f); + CORRADE_COMPARE(data.roughnessTexture(), 3); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 0); + CORRADE_COMPARE(data.normalTexture(), 4); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.normalTextureCoordinates(), 0); + CORRADE_COMPARE(data.occlusionTexture(), 5); + CORRADE_COMPARE(data.occlusionTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.occlusionTextureCoordinates(), 0); + CORRADE_COMPARE(data.emissiveColor(), 0x000000_rgbf); + 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() { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::BaseColorTexture, 1u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 3u}, + {MaterialAttribute::NormalTexture, 4u}, + {MaterialAttribute::OcclusionTexture, 5u}, + {MaterialAttribute::EmissiveTexture, 6u}, + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u} + }}; + + CORRADE_COMPARE(data.baseColorTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.baseColorTextureCoordinates(), 7); + CORRADE_COMPARE(data.metalnessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.metalnessTextureCoordinates(), 7); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 7); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 7); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + 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() { + /* Just the texture ID, the rest is implicit */ + { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetallicRoughnessTexture, 2u}, + }}; + CORRADE_VERIFY(data.hasMetallicRoughnessTexture()); + CORRADE_COMPARE(data.metalnessTexture(), 2); + CORRADE_COMPARE(data.metalnessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.metalnessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.metalnessTextureCoordinates(), 0); + CORRADE_COMPARE(data.roughnessTexture(), 2); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::G); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 0); + + /* Explicit parameters for everything, but all the same */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetallicRoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::R}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasMetallicRoughnessTexture()); + CORRADE_COMPARE(data.metalnessTexture(), 2); + CORRADE_COMPARE(data.metalnessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.metalnessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.metalnessTextureCoordinates(), 3); + CORRADE_COMPARE(data.roughnessTexture(), 2); + CORRADE_COMPARE(data.roughnessTextureSwizzle(), MaterialTextureSwizzle::G); + CORRADE_COMPARE(data.roughnessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.roughnessTextureCoordinates(), 3); + + /* Swizzle is ignored when the combined texture is specified, so this is + fine */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetallicRoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(data.hasMetallicRoughnessTexture()); + + /* Unexpected texture matrix */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetallicRoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + + /* Unexpected texture coordinates */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetallicRoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + } +} + +void MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedMetallicRoughness() { + /* Just the texture IDs and swizzles, the rest is implicit */ + { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G} + }}; + CORRADE_VERIFY(data.hasMetallicRoughnessTexture()); + + /* Explicit parameters for everything, but all the same */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::R}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasMetallicRoughnessTexture()); + + /* One texture missing */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + + /* Unexpected swizzle */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + + /* Unexpected texture matrix */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + + /* Unexpected texture coordinates */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::RoughnessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasMetallicRoughnessTexture()); + } +} + +void MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedRoughnessMetallicOcclusion() { + /* Just the texture IDs and swizzles, the rest is implicit */ + { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(data.hasRoughnessMetallicOcclusionTexture()); + + /* Explicit parameters for everything, but all the same */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::R}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 3u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u}, + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::OcclusionTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasRoughnessMetallicOcclusionTexture()); + + /* One texture missing */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + + /* Unexpected swizzle */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + + /* Unexpected texture matrix */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + }}; + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + + /* Unexpected texture coordinates */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasRoughnessMetallicOcclusionTexture()); + } +} + +void MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedOcclusionRoughnessMetallic() { + /* Just the texture IDs and swizzles, the rest is implicit */ + { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(data.hasOcclusionRoughnessMetallicTexture()); + + /* Explicit parameters for everything, but all the same */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::R}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::OcclusionTextureCoordinates, 3u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 3u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasOcclusionRoughnessMetallicTexture()); + + /* One texture missing */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + + /* Unexpected swizzle */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + + /* Unexpected texture matrix */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + + /* Unexpected texture coordinates */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::OcclusionTexture, 2u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::G}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasOcclusionRoughnessMetallicTexture()); + } +} + +void MaterialDataTest::pbrMetallicRoughnessAccessTexturedExplicitPackedNormalRoughnessMetallic() { + /* Just the texture IDs and swizzles, the rest is implicit */ + { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::NormalTexture, 2u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RG}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A} + }}; + CORRADE_VERIFY(data.hasNormalRoughnessMetallicTexture()); + + /* Explicit parameters for everything, but all the same */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::NormalTexture, 2u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RG}, + {MaterialAttribute::NormalTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::NormalTextureCoordinates, 3u}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::RoughnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::RoughnessTextureCoordinates, 3u}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::MetalnessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasNormalRoughnessMetallicTexture()); + + /* One texture missing */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A}, + }}; + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + + /* Unexpected swizzle */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::NormalTexture, 2u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RGB}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A}, + }}; + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + + /* Unexpected texture matrix */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::NormalTexture, 2u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RG}, + {MaterialAttribute::NormalTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A}, + }}; + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + + /* Unexpected texture coordinates */ + } { + PbrMetallicRoughnessMaterialData data{{}, { + {MaterialAttribute::NormalTexture, 2u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::RG}, + {MaterialAttribute::RoughnessTexture, 2u}, + {MaterialAttribute::RoughnessTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::MetalnessTexture, 2u}, + {MaterialAttribute::MetalnessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::MetalnessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasNormalRoughnessMetallicTexture()); + } +} + +void MaterialDataTest::pbrMetallicRoughnessAccessInvalidTextures() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrMetallicRoughnessMaterialData data{{}, {}}; + + std::ostringstream out; + Error redirectError{&out}; + data.baseColorTexture(); + data.baseColorTextureMatrix(); + data.baseColorTextureCoordinates(); + data.metalnessTexture(); + data.metalnessTextureSwizzle(); + data.metalnessTextureMatrix(); + data.metalnessTextureCoordinates(); + data.roughnessTexture(); + data.roughnessTextureSwizzle(); + data.roughnessTextureMatrix(); + data.roughnessTextureCoordinates(); + data.normalTexture(); + data.normalTextureSwizzle(); + data.normalTextureMatrix(); + data.normalTextureCoordinates(); + data.occlusionTexture(); + data.occlusionTextureSwizzle(); + data.occlusionTextureMatrix(); + data.occlusionTextureCoordinates(); + data.emissiveTexture(); + data.emissiveTextureMatrix(); + data.emissiveTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::MaterialData::attribute(): attribute BaseColorTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::baseColorTextureMatrix(): the material doesn't have a base color texture\n" + "Trade::PbrMetallicRoughnessMaterialData::baseColorTextureCoordinates(): the material doesn't have a base color texture\n" + "Trade::MaterialData::attribute(): attribute MetalnessTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureSwizzle(): the material doesn't have a metalness texture\n" + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureMatrix(): the material doesn't have a metalness texture\n" + "Trade::PbrMetallicRoughnessMaterialData::metalnessTextureCoordinates(): the material doesn't have a metalness texture\n" + "Trade::MaterialData::attribute(): attribute RoughnessTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureSwizzle(): the material doesn't have a roughness texture\n" + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureMatrix(): the material doesn't have a roughness texture\n" + "Trade::PbrMetallicRoughnessMaterialData::roughnessTextureCoordinates(): the material doesn't have a roughness texture\n" + "Trade::MaterialData::attribute(): attribute NormalTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture\n" + "Trade::PbrMetallicRoughnessMaterialData::normalTextureMatrix(): the material doesn't have a normal texture\n" + "Trade::PbrMetallicRoughnessMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture\n" + "Trade::MaterialData::attribute(): attribute OcclusionTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureSwizzle(): the material doesn't have an occlusion texture\n" + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureMatrix(): the material doesn't have an occlusion texture\n" + "Trade::PbrMetallicRoughnessMaterialData::occlusionTextureCoordinates(): the material doesn't have an occlusion texture\n" + "Trade::MaterialData::attribute(): attribute EmissiveTexture not found in layer 0\n" + "Trade::PbrMetallicRoughnessMaterialData::emissiveTextureMatrix(): the material doesn't have an emissive texture\n" + "Trade::PbrMetallicRoughnessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture\n"); +} + +void MaterialDataTest::pbrSpecularGlossinessAccess() { + MaterialData base{MaterialType::PbrSpecularGlossiness, { + {MaterialAttribute::DiffuseColor, 0xccffbbff_rgbaf}, + {MaterialAttribute::SpecularColor, 0xff336600_rgbaf}, + {MaterialAttribute::Glossiness, 0.79f}, + {MaterialAttribute::EmissiveColor, 0x111111_rgbf} + }}; + + CORRADE_COMPARE(base.types(), MaterialType::PbrSpecularGlossiness); + const PbrSpecularGlossinessMaterialData& data = static_cast(base); + + CORRADE_VERIFY(!data.hasSpecularTexture()); + CORRADE_VERIFY(!data.hasGlossinessTexture()); + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.diffuseColor(), 0xccffbbff_rgbaf); + CORRADE_COMPARE(data.specularColor(), 0xff336600_rgbaf); + CORRADE_COMPARE(data.glossiness(), 0.79f); +} + +void MaterialDataTest::pbrSpecularGlossinessAccessDefaults() { + MaterialData base{{}, {}}; + + CORRADE_COMPARE(base.types(), MaterialTypes{}); + /* Casting is fine even if the type doesn't include PbrMetallicRoughness */ + const PbrSpecularGlossinessMaterialData& data = static_cast(base); + + CORRADE_VERIFY(!data.hasSpecularTexture()); + CORRADE_VERIFY(!data.hasGlossinessTexture()); + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.diffuseColor(), 0xffffffff_rgbaf); + CORRADE_COMPARE(data.specularColor(), 0xffffff00_rgbaf); + CORRADE_COMPARE(data.glossiness(), 1.0f); +} + +void MaterialDataTest::pbrSpecularGlossinessAccessTextured() { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::DiffuseColor, 0xccffbbff_rgbaf}, + {MaterialAttribute::DiffuseTexture, 0u}, + {MaterialAttribute::DiffuseTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::DiffuseTextureCoordinates, 2u}, + {MaterialAttribute::SpecularColor, 0x33556600_rgbaf}, + {MaterialAttribute::SpecularTexture, 1u}, + {MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGBA}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::SpecularTextureCoordinates, 3u}, + {MaterialAttribute::Glossiness, 0.79f}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::GlossinessTextureMatrix, Matrix3::scaling({1.0f, 1.0f})}, + {MaterialAttribute::GlossinessTextureCoordinates, 4u}, + {MaterialAttribute::NormalTexture, 3u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::BA}, + {MaterialAttribute::NormalTextureMatrix, Matrix3::scaling({1.0f, 0.5f})}, + {MaterialAttribute::NormalTextureCoordinates, 5u}, + {MaterialAttribute::OcclusionTexture, 4u}, + {MaterialAttribute::OcclusionTextureSwizzle, MaterialTextureSwizzle::B}, + {MaterialAttribute::OcclusionTextureMatrix, Matrix3::scaling({1.0f, 0.75f})}, + {MaterialAttribute::OcclusionTextureCoordinates, 6u}, + {MaterialAttribute::EmissiveColor, 0x111111_rgbf}, + {MaterialAttribute::EmissiveTexture, 5u}, + {MaterialAttribute::EmissiveTextureMatrix, Matrix3::scaling({0.75f, 0.5f})}, + {MaterialAttribute::EmissiveTextureCoordinates, 7u} + }}; + + CORRADE_VERIFY(data.hasSpecularTexture()); + CORRADE_VERIFY(data.hasGlossinessTexture()); + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.diffuseColor(), 0xccffbbff_rgbaf); + CORRADE_COMPARE(data.diffuseTexture(), 0); + CORRADE_COMPARE(data.diffuseTextureMatrix(), Matrix3::scaling({0.5f, 1.0f})); + CORRADE_COMPARE(data.diffuseTextureCoordinates(), 2); + CORRADE_COMPARE(data.specularColor(), 0x33556600_rgbaf); + CORRADE_COMPARE(data.specularTexture(), 1); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGBA); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.specularTextureCoordinates(), 3); + CORRADE_COMPARE(data.glossiness(), 0.79f); + CORRADE_COMPARE(data.glossinessTexture(), 2); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3::scaling({1.0f, 1.0f})); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 4); + CORRADE_COMPARE(data.normalTexture(), 3); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::BA); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({1.0f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 5); + CORRADE_COMPARE(data.occlusionTexture(), 4); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3::scaling({1.0f, 0.75f})); + CORRADE_COMPARE(data.occlusionTextureSwizzle(), MaterialTextureSwizzle::B); + CORRADE_COMPARE(data.occlusionTextureCoordinates(), 6); + CORRADE_COMPARE(data.emissiveColor(), 0x111111_rgbf); + 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() { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::DiffuseTexture, 1u}, + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::GlossinessTexture, 3u}, + {MaterialAttribute::NormalTexture, 4u}, + {MaterialAttribute::OcclusionTexture, 5u}, + {MaterialAttribute::EmissiveTexture, 6u} + }}; + + CORRADE_VERIFY(data.hasSpecularTexture()); + CORRADE_VERIFY(data.hasGlossinessTexture()); + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + CORRADE_VERIFY(!data.hasTextureTransformation()); + CORRADE_VERIFY(!data.hasTextureCoordinates()); + CORRADE_COMPARE(data.diffuseColor(), 0xffffffff_rgbaf); + CORRADE_COMPARE(data.diffuseTexture(), 1); + CORRADE_COMPARE(data.diffuseTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.diffuseTextureCoordinates(), 0); + CORRADE_COMPARE(data.specularColor(), 0xffffff00_rgbaf); + CORRADE_COMPARE(data.specularTexture(), 2); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.specularTextureCoordinates(), 0); + CORRADE_COMPARE(data.glossiness(), 1.0f); + CORRADE_COMPARE(data.glossinessTexture(), 3); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 0); + CORRADE_COMPARE(data.normalTexture(), 4); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.normalTextureCoordinates(), 0); + CORRADE_COMPARE(data.occlusionTexture(), 5); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.occlusionTextureSwizzle(), MaterialTextureSwizzle::R); + CORRADE_COMPARE(data.occlusionTextureCoordinates(), 0); + CORRADE_COMPARE(data.emissiveColor(), 0x000000_rgbf); + 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() { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::DiffuseTexture, 1u}, + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::GlossinessTexture, 3u}, + {MaterialAttribute::NormalTexture, 4u}, + {MaterialAttribute::OcclusionTexture, 5u}, + {MaterialAttribute::EmissiveTexture, 6u}, + {MaterialAttribute::TextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::TextureCoordinates, 7u} + }}; + + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.diffuseTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.diffuseTextureCoordinates(), 7); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.specularTextureCoordinates(), 7); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 7); + CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.normalTextureCoordinates(), 7); + CORRADE_COMPARE(data.occlusionTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + 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() { + /* Just the texture ID, the rest is implicit */ + { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularGlossinessTexture, 2u}, + }}; + CORRADE_VERIFY(data.hasSpecularGlossinessTexture()); + CORRADE_COMPARE(data.specularTexture(), 2); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.specularTextureCoordinates(), 0); + CORRADE_COMPARE(data.glossinessTexture(), 2); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 0); + + /* Explicit parameters for everything, but all the same */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularGlossinessTexture, 2u}, + {MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGB}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::SpecularTextureCoordinates, 3u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::GlossinessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::GlossinessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasSpecularGlossinessTexture()); + CORRADE_COMPARE(data.specularTexture(), 2); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.specularTextureCoordinates(), 3); + CORRADE_COMPARE(data.glossinessTexture(), 2); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 3); + + /* Swizzle is ignored when the combined texture is specified, so this is + fine. */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularGlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::B}, + }}; + CORRADE_VERIFY(data.hasSpecularGlossinessTexture()); + + /* Unexpected texture matrix */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularGlossinessTexture, 2u}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + + /* Unexpected texture coordinates */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularGlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureCoordinates, 1u}, + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + } +} + +void MaterialDataTest::pbrSpecularGlossinessAccessTexturedExplicitPackedSpecularGlossiness() { + /* Just the texture ID and swizzles, the rest is implicit */ + { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A} + }}; + CORRADE_VERIFY(data.hasSpecularGlossinessTexture()); + CORRADE_COMPARE(data.specularTexture(), 2); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.specularTextureCoordinates(), 0); + CORRADE_COMPARE(data.glossinessTexture(), 2); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3{}); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 0); + + /* Explicit parameters for everything, but all the same */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGB}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::SpecularTextureCoordinates, 3u}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::GlossinessTextureMatrix, Matrix3::scaling({0.5f, 0.5f})}, + {MaterialAttribute::GlossinessTextureCoordinates, 3u} + }}; + CORRADE_VERIFY(data.hasSpecularGlossinessTexture()); + CORRADE_COMPARE(data.specularTexture(), 2); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.specularTextureCoordinates(), 3); + CORRADE_COMPARE(data.glossinessTexture(), 2); + CORRADE_COMPARE(data.glossinessTextureSwizzle(), MaterialTextureSwizzle::A); + CORRADE_COMPARE(data.glossinessTextureMatrix(), Matrix3::scaling({0.5f, 0.5f})); + CORRADE_COMPARE(data.glossinessTextureCoordinates(), 3); + + /* Unexpected swizzle 1 */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGBA}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A} + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + + /* Unexpected swizzle 2 */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::B} + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + + /* Unexpected texture matrix */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({0.5f, 1.0f})}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A} + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + + /* Unexpected texture coordinates */ + } { + PbrSpecularGlossinessMaterialData data{{}, { + {MaterialAttribute::SpecularTexture, 2u}, + {MaterialAttribute::GlossinessTexture, 2u}, + {MaterialAttribute::GlossinessTextureSwizzle, MaterialTextureSwizzle::A}, + {MaterialAttribute::GlossinessTextureCoordinates, 1u} + }}; + CORRADE_VERIFY(!data.hasSpecularGlossinessTexture()); + } +} + +void MaterialDataTest::pbrSpecularGlossinessAccessInvalidTextures() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + PbrSpecularGlossinessMaterialData data{{}, {}}; + + std::ostringstream out; + Error redirectError{&out}; + data.diffuseTexture(); + data.diffuseTextureMatrix(); + data.diffuseTextureCoordinates(); + data.specularTexture(); + data.specularTextureSwizzle(); + data.specularTextureMatrix(); + data.specularTextureCoordinates(); + data.glossinessTexture(); + data.glossinessTextureSwizzle(); + data.glossinessTextureMatrix(); + data.glossinessTextureCoordinates(); + data.normalTexture(); + data.normalTextureSwizzle(); + data.normalTextureMatrix(); + data.normalTextureCoordinates(); + data.occlusionTexture(); + data.occlusionTextureSwizzle(); + data.occlusionTextureMatrix(); + data.occlusionTextureCoordinates(); + data.emissiveTexture(); + data.emissiveTextureMatrix(); + data.emissiveTextureCoordinates(); + CORRADE_COMPARE(out.str(), + "Trade::MaterialData::attribute(): attribute DiffuseTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::diffuseTextureMatrix(): the material doesn't have a diffuse texture\n" + "Trade::PbrSpecularGlossinessMaterialData::diffuseTextureCoordinates(): the material doesn't have a diffuse texture\n" + "Trade::MaterialData::attribute(): attribute SpecularTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::specularTextureSwizzle(): the material doesn't have a specular texture\n" + "Trade::PbrSpecularGlossinessMaterialData::specularTextureMatrix(): the material doesn't have a specular texture\n" + "Trade::PbrSpecularGlossinessMaterialData::specularTextureCoordinates(): the material doesn't have a specular texture\n" + "Trade::MaterialData::attribute(): attribute GlossinessTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureSwizzle(): the material doesn't have a glossiness texture\n" + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureMatrix(): the material doesn't have a glossiness texture\n" + "Trade::PbrSpecularGlossinessMaterialData::glossinessTextureCoordinates(): the material doesn't have a glossiness texture\n" + "Trade::MaterialData::attribute(): attribute NormalTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture\n" + "Trade::PbrSpecularGlossinessMaterialData::normalTextureMatrix(): the material doesn't have a normal texture\n" + "Trade::PbrSpecularGlossinessMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture\n" + "Trade::MaterialData::attribute(): attribute OcclusionTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureSwizzle(): the material doesn't have an occlusion texture\n" + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureMatrix(): the material doesn't have an occlusion texture\n" + "Trade::PbrSpecularGlossinessMaterialData::occlusionTextureCoordinates(): the material doesn't have an occlusion texture\n" + "Trade::MaterialData::attribute(): attribute EmissiveTexture not found in layer 0\n" + "Trade::PbrSpecularGlossinessMaterialData::emissiveTextureMatrix(): the material doesn't have an emissive texture\n" + "Trade::PbrSpecularGlossinessMaterialData::emissiveTextureCoordinates(): the material doesn't have an emissive texture\n"); +} + void MaterialDataTest::phongAccess() { MaterialData base{MaterialType::Phong, { {MaterialAttribute::AmbientColor, 0xccffbbff_rgbaf}, @@ -2097,6 +3140,7 @@ void MaterialDataTest::phongAccess() { CORRADE_COMPARE(base.types(), MaterialType::Phong); const PhongMaterialData& data = static_cast(base); + CORRADE_VERIFY(!data.hasSpecularTexture()); CORRADE_VERIFY(!data.hasTextureTransformation()); CORRADE_VERIFY(!data.hasTextureCoordinates()); CORRADE_COMPARE(data.ambientColor(), 0xccffbb_rgbf); @@ -2116,7 +3160,7 @@ void MaterialDataTest::phongAccessDefaults() { CORRADE_VERIFY(!data.hasTextureCoordinates()); CORRADE_COMPARE(data.ambientColor(), 0x000000_rgbf); CORRADE_COMPARE(data.diffuseColor(), 0xffffff_rgbf); - CORRADE_COMPARE(data.specularColor(), 0xffffff_rgbf); + CORRADE_COMPARE(data.specularColor(), 0xffffff00_rgbaf); CORRADE_COMPARE(data.textureMatrix(), Matrix3{}); CORRADE_COMPARE(data.textureCoordinates(), 0); CORRADE_COMPARE(data.shininess(), 80.0f); @@ -2134,13 +3178,16 @@ void MaterialDataTest::phongAccessTextured() { {MaterialAttribute::DiffuseTextureCoordinates, 3u}, {MaterialAttribute::SpecularColor, 0xacabadff_rgbaf}, {MaterialAttribute::SpecularTexture, 17u}, + {MaterialAttribute::SpecularTextureSwizzle, MaterialTextureSwizzle::RGBA}, {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({1.0f, 1.0f})}, {MaterialAttribute::SpecularTextureCoordinates, 4u}, {MaterialAttribute::NormalTexture, 0u}, + {MaterialAttribute::NormalTextureSwizzle, MaterialTextureSwizzle::GB}, {MaterialAttribute::NormalTextureMatrix, Matrix3::scaling({1.0f, 0.5f})}, {MaterialAttribute::NormalTextureCoordinates, 5u} }}; + CORRADE_VERIFY(data.hasSpecularTexture()); CORRADE_VERIFY(data.hasTextureTransformation()); CORRADE_VERIFY(data.hasTextureCoordinates()); CORRADE_COMPARE(data.ambientColor(), 0x111111_rgbf); @@ -2153,9 +3200,11 @@ void MaterialDataTest::phongAccessTextured() { CORRADE_COMPARE(data.diffuseTextureCoordinates(), 3); CORRADE_COMPARE(data.specularColor(), 0xacabad_rgbf); CORRADE_COMPARE(data.specularTexture(), 17); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGBA); CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({1.0f, 1.0f})); CORRADE_COMPARE(data.specularTextureCoordinates(), 4); CORRADE_COMPARE(data.normalTexture(), 0); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::GB); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3::scaling({1.0f, 0.5f})); CORRADE_COMPARE(data.normalTextureCoordinates(), 5); @@ -2171,6 +3220,7 @@ void MaterialDataTest::phongAccessTexturedDefaults() { {MaterialAttribute::NormalTexture, 1u} }}; + CORRADE_VERIFY(data.hasSpecularTexture()); CORRADE_VERIFY(!data.hasTextureTransformation()); CORRADE_VERIFY(!data.hasTextureCoordinates()); CORRADE_COMPARE(data.ambientColor(), 0xffffffff_rgbaf); @@ -2181,11 +3231,13 @@ void MaterialDataTest::phongAccessTexturedDefaults() { CORRADE_COMPARE(data.diffuseTexture(), 33); CORRADE_COMPARE(data.diffuseTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.diffuseTextureCoordinates(), 0); - CORRADE_COMPARE(data.specularColor(), 0xffffffff_rgbaf); + CORRADE_COMPARE(data.specularColor(), 0xffffff00_rgbaf); CORRADE_COMPARE(data.specularTexture(), 17); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.specularTextureCoordinates(), 0); CORRADE_COMPARE(data.normalTexture(), 1); + CORRADE_COMPARE(data.normalTextureSwizzle(), MaterialTextureSwizzle::RGB); CORRADE_COMPARE(data.normalTextureMatrix(), Matrix3{}); CORRADE_COMPARE(data.normalTextureCoordinates(), 0); @@ -2218,6 +3270,29 @@ void MaterialDataTest::phongAccessTexturedSingleMatrixCoordinates() { CORRADE_COMPARE(data.textureCoordinates(), 2); } +void MaterialDataTest::phongAccessTexturedImplicitPackedSpecularGlossiness() { + PhongMaterialData data{{}, { + {MaterialAttribute::SpecularColor, 0xacabadff_rgbaf}, + {MaterialAttribute::SpecularGlossinessTexture, 17u}, + {MaterialAttribute::SpecularTextureMatrix, Matrix3::scaling({1.0f, 1.0f})}, + {MaterialAttribute::SpecularTextureCoordinates, 4u}, + }}; + + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(data.flags(), PhongMaterialData::Flag::SpecularTexture|PhongMaterialData::Flag::TextureCoordinates|PhongMaterialData::Flag::TextureTransformation); + CORRADE_IGNORE_DEPRECATED_POP + #endif + CORRADE_VERIFY(data.hasSpecularTexture()); + CORRADE_VERIFY(data.hasTextureTransformation()); + CORRADE_VERIFY(data.hasTextureCoordinates()); + CORRADE_COMPARE(data.specularColor(), 0xacabad_rgbf); + CORRADE_COMPARE(data.specularTexture(), 17); + CORRADE_COMPARE(data.specularTextureSwizzle(), MaterialTextureSwizzle::RGB); + CORRADE_COMPARE(data.specularTextureMatrix(), Matrix3::scaling({1.0f, 1.0f})); + CORRADE_COMPARE(data.specularTextureCoordinates(), 4); +} + void MaterialDataTest::phongAccessInvalidTextures() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -2234,9 +3309,11 @@ void MaterialDataTest::phongAccessInvalidTextures() { data.diffuseTextureMatrix(); data.diffuseTextureCoordinates(); data.specularTexture(); + data.specularTextureSwizzle(); data.specularTextureMatrix(); data.specularTextureCoordinates(); data.normalTexture(); + data.normalTextureSwizzle(); data.normalTextureMatrix(); data.normalTextureCoordinates(); CORRADE_COMPARE(out.str(), @@ -2247,9 +3324,11 @@ void MaterialDataTest::phongAccessInvalidTextures() { "Trade::PhongMaterialData::diffuseTextureMatrix(): the material doesn't have a diffuse texture\n" "Trade::PhongMaterialData::diffuseTextureCoordinates(): the material doesn't have a diffuse texture\n" "Trade::MaterialData::attribute(): attribute SpecularTexture not found in layer 0\n" + "Trade::PhongMaterialData::specularTextureSwizzle(): the material doesn't have a specular texture\n" "Trade::PhongMaterialData::specularTextureMatrix(): the material doesn't have a specular texture\n" "Trade::PhongMaterialData::specularTextureCoordinates(): the material doesn't have a specular texture\n" "Trade::MaterialData::attribute(): attribute NormalTexture not found in layer 0\n" + "Trade::PhongMaterialData::normalTextureSwizzle(): the material doesn't have a normal texture\n" "Trade::PhongMaterialData::normalTextureMatrix(): the material doesn't have a normal texture\n" "Trade::PhongMaterialData::normalTextureCoordinates(): the material doesn't have a normal texture\n"); } diff --git a/src/Magnum/Trade/Trade.h b/src/Magnum/Trade/Trade.h index ac59202b5..9d7fc246b 100644 --- a/src/Magnum/Trade/Trade.h +++ b/src/Magnum/Trade/Trade.h @@ -90,6 +90,8 @@ class MeshObjectData2D; class MeshObjectData3D; class ObjectData2D; class ObjectData3D; +class PbrMetallicRoughnessMaterialData; +class PbrSpecularGlossinessMaterialData; class PhongMaterialData; class TextureData; class SceneData;