mirror of https://github.com/mosra/magnum.git
Browse Source
These are extremely essential for about anything related to materials but were waiting for (also essential) BitArray APIs to get done.pull/601/head
5 changed files with 563 additions and 19 deletions
@ -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); |
||||
} |
||||
|
||||
}} |
||||
@ -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 |
||||
@ -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…
Reference in new issue