Browse Source

MaterialTools: add filter{Attributes,Layers,AttributesLayers}().

These are extremely essential for about anything related to materials
but were waiting for (also essential) BitArray APIs to get done.
pull/601/head
Vladimír Vondruš 3 years ago
parent
commit
b1a13c9140
  1. 36
      src/Magnum/MaterialTools/CMakeLists.txt
  2. 139
      src/Magnum/MaterialTools/Filter.cpp
  3. 83
      src/Magnum/MaterialTools/Filter.h
  4. 1
      src/Magnum/MaterialTools/Test/CMakeLists.txt
  5. 323
      src/Magnum/MaterialTools/Test/FilterTest.cpp

36
src/Magnum/MaterialTools/CMakeLists.txt

@ -32,9 +32,11 @@ set(MagnumMaterialTools_SRCS
PhongToPbrMetallicRoughness.cpp)
# Files compiled with different flags for main library and unit test library
set(MagnumMaterialTools_GracefulAssert_SRCS )
set(MagnumMaterialTools_GracefulAssert_SRCS
Filter.cpp)
set(MagnumMaterialTools_HEADERS
Filter.h
PhongToPbrMetallicRoughness.h
visibility.h)
@ -57,11 +59,7 @@ endif()
# Main MaterialTools library
add_library(MagnumMaterialTools ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumMaterialToolsObjects>
${MagnumMaterialTools_HEADERS}
${MagnumMaterialTools_PRIVATE_HEADERS}
# XCode workaround, see file comment for details.
# TODO remove once MagnumMaterialTools_GracefulAssert_SRCS is non-empty
${PROJECT_SOURCE_DIR}/src/dummy.cpp)
${MagnumMaterialTools_GracefulAssert_SRCS})
set_target_properties(MagnumMaterialTools PROPERTIES DEBUG_POSTFIX "-d")
if(NOT MAGNUM_BUILD_STATIC)
set_target_properties(MagnumMaterialTools PROPERTIES VERSION ${MAGNUM_LIBRARY_VERSION} SOVERSION ${MAGNUM_LIBRARY_SOVERSION})
@ -79,19 +77,19 @@ install(TARGETS MagnumMaterialTools
install(FILES ${MagnumMaterialTools_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/MaterialTools)
if(MAGNUM_BUILD_TESTS)
# # Library with graceful assert for testing
# add_library(MagnumMaterialToolsTestLib ${SHARED_OR_STATIC} ${EXCLUDE_FROM_ALL_IF_TEST_TARGET}
# $<TARGET_OBJECTS:MagnumMaterialToolsObjects>
# ${MagnumMaterialTools_GracefulAssert_SRCS})
# set_target_properties(MagnumMaterialToolsTestLib PROPERTIES DEBUG_POSTFIX "-d")
# target_compile_definitions(MagnumMaterialToolsTestLib PRIVATE
# "CORRADE_GRACEFUL_ASSERT" "MagnumMaterialTools_EXPORTS")
# if(MAGNUM_BUILD_STATIC_PIC)
# set_target_properties(MagnumMaterialToolsTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON)
# endif()
# target_link_libraries(MagnumMaterialToolsTestLib PUBLIC
# Magnum
# MagnumTrade)
# Library with graceful assert for testing
add_library(MagnumMaterialToolsTestLib ${SHARED_OR_STATIC} ${EXCLUDE_FROM_ALL_IF_TEST_TARGET}
$<TARGET_OBJECTS:MagnumMaterialToolsObjects>
${MagnumMaterialTools_GracefulAssert_SRCS})
set_target_properties(MagnumMaterialToolsTestLib PROPERTIES DEBUG_POSTFIX "-d")
target_compile_definitions(MagnumMaterialToolsTestLib PRIVATE
"CORRADE_GRACEFUL_ASSERT" "MagnumMaterialTools_EXPORTS")
if(MAGNUM_BUILD_STATIC_PIC)
set_target_properties(MagnumMaterialToolsTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
target_link_libraries(MagnumMaterialToolsTestLib PUBLIC
Magnum
MagnumTrade)
add_subdirectory(Test ${EXCLUDE_FROM_ALL_IF_TEST_TARGET})
endif()

139
src/Magnum/MaterialTools/Filter.cpp

@ -0,0 +1,139 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
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 "Filter.h"
#include <Corrade/Containers/BitArray.h>
#include <Corrade/Containers/StridedBitArrayView.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Trade/MaterialData.h"
namespace Magnum { namespace MaterialTools {
namespace {
/* - if inputLayersToKeep is nullptr, all layers are kept,
- if inputAttributesToKeep is nullptr then only attributes present in
enabled layers are kept,
- if neither is nullptr then inputAttributesToKeep is patched to have zero
bits for all attributes in filtered-out layers,
- both can't be nullptr */
Trade::MaterialData filterAttributesLayersImplementation(const Trade::MaterialData& material, const Containers::BitArrayView inputAttributesToKeep, const Containers::BitArrayView inputLayersToKeep) {
CORRADE_INTERNAL_ASSERT(inputAttributesToKeep.data() || inputLayersToKeep.data());
const std::size_t totalAttributeCount = material.attributeDataOffset(material.layerCount());
/* Generate the input attribute bit array or make a mutable copy. Using an
Array<char> and not a BitArray so we can preserve the bit offset and
copy without a shift. */
/** @todo copy() for BitArray so we don't have to work around like this */
/** @todo if the input would be mutable already, we could avoid the
allocation, but does that matter at all? */
Containers::Array<char> patchedInputAttributesToKeepData;
Containers::MutableBitArrayView patchedInputAttributesToKeep;
if(inputAttributesToKeep.data()) {
const std::size_t sizeInBytes = (inputAttributesToKeep.offset() + inputAttributesToKeep.size() + 7)/8;
patchedInputAttributesToKeepData = Containers::Array<char>{NoInit, sizeInBytes};
Utility::copy({inputAttributesToKeep.data(), sizeInBytes}, patchedInputAttributesToKeepData);
patchedInputAttributesToKeep = {patchedInputAttributesToKeepData.data(), inputAttributesToKeep.offset(), inputAttributesToKeep.size()};
} else {
patchedInputAttributesToKeepData = Containers::Array<char>{NoInit, (totalAttributeCount + 7)/8};
patchedInputAttributesToKeep = {patchedInputAttributesToKeepData.data(), 0, totalAttributeCount};
patchedInputAttributesToKeep.setAll();
}
/* Patch the attribute array to have zeros for all attributes in
filtered-out layers */
if(inputLayersToKeep.data()) for(UnsignedInt i = 0; i != material.layerCount(); ++i) {
if(!inputLayersToKeep[i]) patchedInputAttributesToKeep
.slice(material.attributeDataOffset(i),
material.attributeDataOffset(i + 1))
.resetAll();
}
/* Count of layers to keep. If the base layer is to be removed, it just
gets empty -- otherwise, say, a ClearColor layer would become a base
layer and that's generally unwanted */
std::size_t layerCount;
if(inputLayersToKeep.data()) {
layerCount = inputLayersToKeep.count();
if(!inputLayersToKeep[0]) ++layerCount;
} else layerCount = material.layerCount();
/* Fill in the layer offsets based on count of attributes in each, skipping
layers that are filtered away */
Containers::Array<UnsignedInt> layers{NoInit, layerCount};
/** @todo some "iterate set bits" utility, or "next set bit" */
UnsignedInt layerOffset = 0;
for(UnsignedInt i = 0; i != material.layerCount(); ++i) {
if(inputLayersToKeep.data() && !inputLayersToKeep[i]) {
/* The base layer stays, just gets empty */
if(i == 0) layers[layerOffset++] = 0;
continue;
}
layers[layerOffset++] = patchedInputAttributesToKeep.prefix(material.attributeDataOffset(i + 1)).count();
}
CORRADE_INTERNAL_ASSERT(layerOffset == layers.size());
/* Copy attributes that aren't filtered away */
Containers::Array<Trade::MaterialAttributeData> attributes{NoInit, patchedInputAttributesToKeep.count()};
/** @todo some copyMasked() utility */
UnsignedInt attributeOffset = 0;
for(UnsignedInt i = 0; i != totalAttributeCount; ++i) {
if(!patchedInputAttributesToKeep[i]) continue;
attributes[attributeOffset++] = material.attributeData()[i];
}
CORRADE_INTERNAL_ASSERT(attributeOffset == attributes.size());
return Trade::MaterialData{material.types(), std::move(attributes), std::move(layers)};
}
}
Trade::MaterialData filterAttributes(const Trade::MaterialData& material, const Containers::BitArrayView attributesToKeep) {
CORRADE_ASSERT(attributesToKeep.size() == material.attributeData().size(),
"MaterialTools::filterAttributes(): expected" << material.attributeData().size() << "bits but got" << attributesToKeep.size(), (Trade::MaterialData{{}, {}}));
return filterAttributesLayersImplementation(material, attributesToKeep, nullptr);
}
Trade::MaterialData filterLayers(const Trade::MaterialData& material, const Containers::BitArrayView layersToKeep) {
CORRADE_ASSERT(layersToKeep.size() == material.layerCount(),
"MaterialTools::filterLayers(): expected" << material.layerCount() << "bits but got" << layersToKeep.size(), (Trade::MaterialData{{}, {}}));
return filterAttributesLayersImplementation(material, nullptr, layersToKeep);
}
Trade::MaterialData filterAttributesLayers(const Trade::MaterialData& material, const Containers::BitArrayView attributesToKeep, const Containers::BitArrayView layersToKeep) {
CORRADE_ASSERT(attributesToKeep.size() == material.attributeData().size(),
"MaterialTools::filterAttributesLayers(): expected" << material.attributeData().size() << "attribute bits but got" << attributesToKeep.size(), (Trade::MaterialData{{}, {}}));
CORRADE_ASSERT(layersToKeep.size() == material.layerCount(),
"MaterialTools::filterAttributesLayers(): expected" << material.layerCount() << "layer bits but got" << layersToKeep.size(), (Trade::MaterialData{{}, {}}));
return filterAttributesLayersImplementation(material, attributesToKeep, layersToKeep);
}
}}

83
src/Magnum/MaterialTools/Filter.h

@ -0,0 +1,83 @@
#ifndef Magnum_MaterialTools_Filter_h
#define Magnum_MaterialTools_Filter_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
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 Function @ref Magnum::MaterialTools::filterAttributes(), @ref Magnum::MaterialTools::filterLayers(), @ref filterAttributesLayers()
* @m_since_latest
*/
#include "Magnum/MaterialTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace MaterialTools {
/**
@brief Filter material attributes
@m_since_latest
Returns a material with only the attributes for which the corresponding bit in
@p attributesToKeep was set. Attributes in additional layers are referenced by
bit ranges corresponding to @ref Trade::MaterialData::attributeDataOffset() for
a particular layer. The output layer ranges are then recalculated based on how
many attributes are left in those. Empty layers are kept,
@ref Trade::MaterialData::types() are transferred unchanged.
The size of @p attributesToKeep is expected to be equal to the number of
attributes in all layers (i.e., size of the
@ref Trade::MaterialData::attributeData() array).
@see @ref filterLayers(), @ref filterAttributesLayers()
*/
MAGNUM_MATERIALTOOLS_EXPORT Trade::MaterialData filterAttributes(const Trade::MaterialData& material, Containers::BitArrayView attributesToKeep);
/**
@brief Filter material layers
@m_since_latest
Returns a material with only the layers for which the corresponding bit in
@p layersToKeep was set. The only exception is the base layer, which is left
empty if removed. Attributes in other layers are kept untouched,
@ref Trade::MaterialData::types() are transferred unchanged.
The size of @p layerCount is expected to be equal to
@ref Trade::MaterialData::layerCount().
@see @ref filterAttributes(), @ref filterAttributesLayers()
*/
MAGNUM_MATERIALTOOLS_EXPORT Trade::MaterialData filterLayers(const Trade::MaterialData& material, Containers::BitArrayView layersToKeep);
/**
@brief Filter material attributes and layers
@m_since_latest
Performs what @ref filterAttributes() and @ref filterLayers() do, but in a
single step. Bits in @p attributesToKeep that correspond to layers that are
removed are ignored.
*/
MAGNUM_MATERIALTOOLS_EXPORT Trade::MaterialData filterAttributesLayers(const Trade::MaterialData& material, Containers::BitArrayView attributesToKeep, Containers::BitArrayView layersToKeep);
}}
#endif

1
src/Magnum/MaterialTools/Test/CMakeLists.txt

@ -27,4 +27,5 @@
# property that would have to be set on each target separately.
set(CMAKE_FOLDER "Magnum/MaterialTools/Test")
corrade_add_test(MaterialToolsFilterTest FilterTest.cpp LIBRARIES MagnumDebugTools MagnumMaterialToolsTestLib)
corrade_add_test(MaterialToolsPhongToPbrMetall___Test PhongToPbrMetallicRoughnessTest.cpp LIBRARIES MagnumDebugTools MagnumMaterialTools)

323
src/Magnum/MaterialTools/Test/FilterTest.cpp

@ -0,0 +1,323 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
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 <sstream>
#include <Corrade/Containers/BitArray.h>
#include <Corrade/Containers/BitArrayView.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/DebugTools/CompareMaterial.h"
#include "Magnum/MaterialTools/Filter.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Trade/MaterialData.h"
namespace Magnum { namespace MaterialTools { namespace Test { namespace {
struct FilterTest: TestSuite::Tester {
explicit FilterTest();
void attributes();
void attributesMultipleLayers();
void attributesWrongBitCount();
void layers();
void layersRemoveBase();
void layersWrongBitCount();
void attributesLayers();
void attributesLayersRemoveBaseLayer();
void attributesLayersWrongBitCount();
};
FilterTest::FilterTest() {
addTests({&FilterTest::attributes,
&FilterTest::attributesMultipleLayers,
&FilterTest::attributesWrongBitCount,
&FilterTest::layers,
&FilterTest::layersRemoveBase,
&FilterTest::layersWrongBitCount,
&FilterTest::attributesLayers,
&FilterTest::attributesLayersRemoveBaseLayer,
&FilterTest::attributesLayersWrongBitCount});
}
using namespace Math::Literals;
void FilterTest::attributes() {
/* Supplying the attributes as external in order to make sure they're
sorted for correct numbering */
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf}, /* 1 */
{Trade::MaterialAttribute::BaseColorTexture, 7u}, /* 2 */
{Trade::MaterialAttribute::TextureCoordinates, 11u}, /* 3 */
{Trade::MaterialAttribute::TextureLayer, 0u}, /* 4 */
};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::Flat, Trade::DataFlags{}, attributes};
Containers::BitArray attributesToKeep{DirectInit, 5, true};
attributesToKeep.reset(1);
attributesToKeep.reset(3);
attributesToKeep.reset(4);
/* The types are kept intact even if they don't make sense, that's a job
for some higher-level utility that understands their relations to
present attributes */
CORRADE_COMPARE_AS(filterAttributes(material, attributesToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::Flat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
}}), DebugTools::CompareMaterial);
/* Removing all shouldn't do anything unexpected */
CORRADE_COMPARE_AS(filterAttributes(material, Containers::BitArray{ValueInit, 5}), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::Flat, {
}}), DebugTools::CompareMaterial);
}
void FilterTest::attributesMultipleLayers() {
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf}, /* 1 */
{Trade::MaterialAttribute::BaseColorTexture, 7u}, /* 2 */
{Trade::MaterialLayer::ClearCoat}, /* 3 */
{Trade::MaterialAttribute::LayerFactor, 0.7f}, /* 4 */
{Trade::MaterialAttribute::Roughness, 0.25f}, /* 5 */
/* One empty layer here */
{"textureBlendMode", "strongly!"}, /* 6 */
{"texturePointer", nullptr}, /* 7 */
};
const UnsignedInt layers[]{3, 6, 6, 8};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat, Trade::DataFlags{}, attributes, Trade::DataFlags{}, layers};
Containers::BitArray attributesToKeep{DirectInit, 8, true};
attributesToKeep.reset(0);
attributesToKeep.reset(2);
attributesToKeep.reset(4);
attributesToKeep.reset(6);
CORRADE_COMPARE_AS(filterAttributes(material, attributesToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::Roughness, 0.25f},
/* Empty layer stays */
{"texturePointer", nullptr},
}, {1, 3, 3, 4}}), DebugTools::CompareMaterial);
/* Removing all shouldn't do anything unexpected */
CORRADE_COMPARE_AS(filterAttributes(material, Containers::BitArray{ValueInit, 8}), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
}, {0, 0, 0, 0}}), DebugTools::CompareMaterial);
}
void FilterTest::attributesWrongBitCount() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MaterialData material{{}, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.7f},
}, {2, 4}};
Containers::BitArrayView attributesToKeep{nullptr, 0, 5};
std::ostringstream out;
Error redirectError{&out};
filterAttributes(material, attributesToKeep);
CORRADE_COMPARE(out.str(), "MaterialTools::filterAttributes(): expected 4 bits but got 5\n");
}
void FilterTest::layers() {
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
/* One empty layer here */ /* 1 #3 */
{Trade::MaterialLayer::ClearCoat}, /* 2 #3 */
{Trade::MaterialAttribute::LayerFactor, 0.7f},
{Trade::MaterialAttribute::Roughness, 0.25f},
{"textureBlendMode", "strongly!"}, /* 3 #6 */
{"texturePointer", nullptr},
/* Another empty layer here */ /* 4 #8 */
{Trade::MaterialAttribute::NormalTextureSwizzle, /* 5 #8 */
Trade::MaterialTextureSwizzle::RG},
{"againSomething", false}, /* 6 #9 */
};
const UnsignedInt layers[]{3, 3, 6, 8, 8, 9, 10};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat, Trade::DataFlags{}, attributes, Trade::DataFlags{}, layers};
Containers::BitArray layersToKeep{DirectInit, 7, true};
layersToKeep.reset(1);
layersToKeep.reset(2);
layersToKeep.reset(5);
CORRADE_COMPARE_AS(filterLayers(material, layersToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{"textureBlendMode", "strongly!"},
{"texturePointer", nullptr},
/* Second empty layer stays */
{"againSomething", false},
}, {3, 5, 5, 6}}), DebugTools::CompareMaterial);
/* Removing all shouldn't do anything unexpected */
CORRADE_COMPARE_AS(filterLayers(material, Containers::BitArray{ValueInit, 7}), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
}}), DebugTools::CompareMaterial);
}
void FilterTest::layersRemoveBase() {
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{Trade::MaterialLayer::ClearCoat}, /* 1 #3 */
{Trade::MaterialAttribute::LayerFactor, 0.7f},
};
const UnsignedInt layers[]{3, 5};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat, Trade::DataFlags{}, attributes, Trade::DataFlags{}, layers};
Containers::BitArray layersToKeep{DirectInit, 2, true};
layersToKeep.reset(0);
CORRADE_COMPARE_AS(filterLayers(material, layersToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
/* The base layer stays but it's empty */
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.7f},
}, {0, 2}}), DebugTools::CompareMaterial);
}
void FilterTest::layersWrongBitCount() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MaterialData material{{}, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.7f}
}, {2, 4}};
Containers::BitArrayView layersToKeep{nullptr, 0, 3};
std::ostringstream out;
Error redirectError{&out};
filterLayers(material, layersToKeep);
CORRADE_COMPARE(out.str(), "MaterialTools::filterLayers(): expected 2 bits but got 3\n");
}
void FilterTest::attributesLayers() {
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 #0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf}, /* #1 */
{Trade::MaterialAttribute::BaseColorTexture, 7u}, /* #2 */
/* One empty layer here */ /* 1 #3 */
{Trade::MaterialLayer::ClearCoat}, /* 2 #3 */
{Trade::MaterialAttribute::LayerFactor, 0.7f}, /* #4 */
{Trade::MaterialAttribute::Roughness, 0.25f}, /* #5 */
{"textureBlendMode", "strongly!"}, /* 3 #6 */
{"texturePointer", nullptr}, /* #7 */
/* Another empty layer here */ /* 4 #8 */
{Trade::MaterialAttribute::NormalTextureSwizzle, /* 5 #8 */
Trade::MaterialTextureSwizzle::RG},
{"againSomething", false}, /* 6 #9 */
};
const UnsignedInt layers[]{3, 3, 6, 8, 8, 9, 10};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat, Trade::DataFlags{}, attributes, Trade::DataFlags{}, layers};
Containers::BitArray attributesToKeep{DirectInit, 10, true};
attributesToKeep.reset(1);
attributesToKeep.reset(4); /* in a removed layer, ignored */
attributesToKeep.reset(6);
attributesToKeep.reset(8); /* becomes an empty layer */
Containers::BitArray layersToKeep{DirectInit, 7, true};
layersToKeep.reset(1);
layersToKeep.reset(2);
CORRADE_COMPARE_AS(filterAttributesLayers(material, attributesToKeep, layersToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{"texturePointer", nullptr},
/* Second empty layer stays */
/* Layer 5 is now empty */
{"againSomething", false},
}, {2, 3, 3, 3, 4}}), DebugTools::CompareMaterial);
/* Removing all attributes should keep all layers but make them empty */
CORRADE_COMPARE_AS(filterAttributesLayers(material, Containers::BitArray{ValueInit, 10}, Containers::BitArray{DirectInit, 7, true}), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
}, {0, 0, 0, 0, 0, 0, 0}}), DebugTools::CompareMaterial);
/* Removing all layers should make the material completely empty */
CORRADE_COMPARE_AS(filterLayers(material, Containers::BitArray{ValueInit, 7}), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
}}), DebugTools::CompareMaterial);
}
void FilterTest::attributesLayersRemoveBaseLayer() {
const Trade::MaterialAttributeData attributes[]{
{Trade::MaterialAttribute::AlphaBlend, true}, /* 0 #0 */
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf}, /* #1 */
{Trade::MaterialAttribute::BaseColorTexture, 7u}, /* #2 */
{Trade::MaterialLayer::ClearCoat}, /* 1 #3 */
{Trade::MaterialAttribute::LayerFactor, 0.7f}, /* #4 */
};
const UnsignedInt layers[]{3, 5};
Trade::MaterialData material{Trade::MaterialType::PbrClearCoat, Trade::DataFlags{}, attributes, Trade::DataFlags{}, layers};
Containers::BitArray attributesToKeep{DirectInit, 5, true};
attributesToKeep.reset(1); /* in a removed base layer, ignored */
attributesToKeep.reset(3);
Containers::BitArray layersToKeep{DirectInit, 2, true};
layersToKeep.reset(0);
CORRADE_COMPARE_AS(filterAttributesLayers(material, attributesToKeep, layersToKeep), (Trade::MaterialData{Trade::MaterialType::PbrClearCoat, {
/* The base layer stays but it's empty */
{Trade::MaterialAttribute::LayerFactor, 0.7f},
}, {0, 1}}), DebugTools::CompareMaterial);
}
void FilterTest::attributesLayersWrongBitCount() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MaterialData material{{}, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 7u},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.7f},
}, {2, 4}};
Containers::BitArrayView attributesToKeep{nullptr, 0, 5};
Containers::BitArrayView layersToKeep{nullptr, 0, 3};
std::ostringstream out;
Error redirectError{&out};
filterAttributesLayers(material, attributesToKeep, layersToKeep.prefix(2));
filterAttributesLayers(material, attributesToKeep.prefix(4), layersToKeep);
CORRADE_COMPARE(out.str(),
"MaterialTools::filterAttributesLayers(): expected 4 attribute bits but got 5\n"
"MaterialTools::filterAttributesLayers(): expected 2 layer bits but got 3\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::MaterialTools::Test::FilterTest)
Loading…
Cancel
Save