Browse Source

MaterialTools: add a merge() utility.

Merging two sorted sequences is is something I always struggle with to
write from scratch. Fortunately here I could just reuse what got done for
DebugTools::CompareMaterial already, haha.
pull/601/head
Vladimír Vondruš 3 years ago
parent
commit
467daa5aa5
  1. 4
      src/Magnum/MaterialTools/CMakeLists.txt
  2. 120
      src/Magnum/MaterialTools/Merge.cpp
  3. 96
      src/Magnum/MaterialTools/Merge.h
  4. 1
      src/Magnum/MaterialTools/Test/CMakeLists.txt
  5. 348
      src/Magnum/MaterialTools/Test/MergeTest.cpp

4
src/Magnum/MaterialTools/CMakeLists.txt

@ -33,10 +33,12 @@ set(MagnumMaterialTools_SRCS
# Files compiled with different flags for main library and unit test library
set(MagnumMaterialTools_GracefulAssert_SRCS
Filter.cpp)
Filter.cpp
Merge.cpp)
set(MagnumMaterialTools_HEADERS
Filter.h
Merge.h
PhongToPbrMetallicRoughness.h
visibility.h)

120
src/Magnum/MaterialTools/Merge.cpp

@ -0,0 +1,120 @@
/*
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 "Merge.h"
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Optional.h>
#include "Magnum/Trade/MaterialData.h"
namespace Magnum { namespace MaterialTools {
Containers::Optional<Trade::MaterialData> merge(const Trade::MaterialData& first, const Trade::MaterialData& second, MergeConflicts conflicts) {
Containers::Array<Trade::MaterialAttributeData> attributes;
arrayReserve(attributes, first.attributeData().size() + second.attributeData().size());
Containers::Array<UnsignedInt> layers{NoInit, Math::max(first.layerCount(), second.layerCount())};
/* Go over all layers that are in both materials */
std::size_t layer = 0;
for(const std::size_t layerMin = Math::min(first.layerCount(), second.layerCount()); layer != layerMin; ++layer) {
UnsignedInt attributeFirst = 0;
UnsignedInt attributeSecond = 0;
/* Take the earliest-sorted attribute from either material */
while(attributeFirst != first.attributeCount(layer) && attributeSecond != second.attributeCount(layer)) {
/* Attributes have the same name */
/** @todo add StringView::compare() returning -1, 0, 1 and do the
comparison just once instead of three times */
if(first.attributeName(layer, attributeFirst) == second.attributeName(layer, attributeSecond)) {
/* Fail if we are told to not merge attributes of the same
name */
if(conflicts == MergeConflicts::Fail) {
Error{} << "MaterialTools::merge(): conflicting attribute" << first.attributeName(layer, attributeFirst) << "in layer" << layer;
return {};
}
/* Fail if we are told to not merge attributes of the same name
but different type */
if(first.attributeType(layer, attributeFirst) != second.attributeType(layer, attributeSecond) && conflicts == MergeConflicts::KeepFirstIfSameType) {
Error{} << "MaterialTools::merge(): conflicting type" << first.attributeType(layer, attributeFirst) << "vs" << Debug::packed << second.attributeType(layer, attributeSecond) << "of attribute" << first.attributeName(layer, attributeFirst) << "in layer" << layer;
return {};
}
/* Add the first attribute, ignore the second */
arrayAppend(attributes, first.attributeData(layer, attributeFirst));
++attributeFirst;
++attributeSecond;
/* The attribute from first material should go first */
} else if(first.attributeName(layer, attributeFirst) < second.attributeName(layer, attributeSecond)) {
arrayAppend(attributes, first.attributeData(layer, attributeFirst));
++attributeFirst;
/* The attribute from second material should go first */
} else if(first.attributeName(layer, attributeFirst) > second.attributeName(layer, attributeSecond)) {
arrayAppend(attributes, second.attributeData(layer, attributeSecond));
++attributeSecond;
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
/* Consume remaining leftover attributes in either. Only one of these
loops get entered. */
while(attributeFirst < first.attributeCount(layer)) {
arrayAppend(attributes, first.attributeData(layer, attributeFirst));
++attributeFirst;
}
while(attributeSecond < second.attributeCount(layer)) {
arrayAppend(attributes, second.attributeData(layer, attributeSecond));
++attributeSecond;
}
layers[layer] = attributes.size();
}
/* Go over remaining layers which weren't in the other attribute and
add them as a whole. Only one of these loops get entered. */
for(; layer < first.layerCount(); ++layer) {
arrayAppend(attributes, first.attributeData().slice(
first.attributeDataOffset(layer),
first.attributeDataOffset(layer + 1)));
layers[layer] = attributes.size();
}
for(; layer < second.layerCount(); ++layer) {
arrayAppend(attributes, second.attributeData().slice(
second.attributeDataOffset(layer),
second.attributeDataOffset(layer + 1)));
layers[layer] = attributes.size();
}
CORRADE_INTERNAL_ASSERT(layer == layers.size());
return Trade::MaterialData{first.types()|second.types(), std::move(attributes), std::move(layers)};
}
}}

96
src/Magnum/MaterialTools/Merge.h

@ -0,0 +1,96 @@
#ifndef Magnum_MaterialTools_Merge_h
#define Magnum_MaterialTools_Merge_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::merge(), enum @ref Magnum::MaterialTools::MergeConflicts
* @m_since_latest
*/
#include "Magnum/MaterialTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace MaterialTools {
/**
@brief Material merge conflict resolution
@m_since_latest
@see @ref merge()
*/
enum MergeConflicts: UnsignedInt {
/**
* Print a message to @relativeref{Magnum,Error} and return
* @ref Containers::NullOpt in case both materials contain an attribute of
* the same name in the same layer index. Neither its type nor its value is
* checked, so this fails also in case the values are the same.
*/
Fail,
/**
* Keep the value from the first material in case both materials contain an
* attribute of the same name in the same layer index and both attributes
* have the same type. Print a message to @relativeref{Magnum,Error} and
* return @ref Containers::NullOpt if they have a different type, for
* example in case of custom attributes.
*
* If you want to keep the value from the second material instead, call
* @ref merge() with this option and the materials swapped.
*/
KeepFirstIfSameType,
/**
* Keep the value from the first material in case both materials contain an
* attribute of the same name in the same layer index, regardless of their
* type. With this option the operation always succeeds.
*
* If you want to keep the value from the second material instead, call
* @ref merge() with this option and the materials swapped.
*/
KeepFirstIgnoreType
};
/**
@brief Merge two materials
@m_since_latest
Takes attributes from @p second and inserts them to layers of the same index in
@p first. If @p second has more layers than @p first, the additional layers are
added at the end of @p first. @ref Trade::MaterialTypes from @p first and
@p second are merged together. If both materials contain an attribute of the
same name in the same layer index, conflict resolution is performed according
to the @p conflicts option.
As the input materials have the attributes sorted already, the operation is
done in an @f$ \mathcal{O}(m + n) @f$ execution time and memory complexity,
with @f$ m @f$ and @f$ n @f$ being count of all attributes and layers in
@p first and @p second, respectively.
*/
Containers::Optional<Trade::MaterialData> MAGNUM_MATERIALTOOLS_EXPORT merge(const Trade::MaterialData& first, const Trade::MaterialData& second, MergeConflicts conflicts = MergeConflicts::Fail);
}}
#endif

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

@ -28,4 +28,5 @@
set(CMAKE_FOLDER "Magnum/MaterialTools/Test")
corrade_add_test(MaterialToolsFilterTest FilterTest.cpp LIBRARIES MagnumDebugTools MagnumMaterialToolsTestLib)
corrade_add_test(MaterialToolsMergeTest MergeTest.cpp LIBRARIES MagnumDebugTools MagnumMaterialToolsTestLib)
corrade_add_test(MaterialToolsPhongToPbrMetall___Test PhongToPbrMetallicRoughnessTest.cpp LIBRARIES MagnumDebugTools MagnumMaterialTools)

348
src/Magnum/MaterialTools/Test/MergeTest.cpp

@ -0,0 +1,348 @@
/*
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/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/DebugTools/CompareMaterial.h"
#include "Magnum/Math/Color.h"
#include "Magnum/MaterialTools/Merge.h"
#include "Magnum/Trade/MaterialData.h"
namespace Magnum { namespace MaterialTools { namespace Test { namespace {
struct MergeTest: TestSuite::Tester {
explicit MergeTest();
void singleLayer();
void multipleLayersIntoSingleLayer();
void multipleLayers();
void conflictsSameType();
void conflictsDifferentType();
void conflictsFail();
void emptyInput();
};
using namespace Math::Literals;
MergeTest::MergeTest() {
addTests({&MergeTest::singleLayer,
&MergeTest::multipleLayersIntoSingleLayer,
&MergeTest::multipleLayers,
&MergeTest::conflictsSameType,
&MergeTest::conflictsDifferentType,
&MergeTest::conflictsFail,
&MergeTest::emptyInput});
}
void MergeTest::singleLayer() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
/* These two go at the end */
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::Roughness, 0.3f}
}};
Trade::MaterialData b{Trade::MaterialType::Phong|Trade::MaterialType::Flat, {
/* This attribute goes first */
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::DiffuseColor, 0x808080ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 3u},
{Trade::MaterialAttribute::BaseColorTextureCoordinates, 2u},
}};
Trade::MaterialData expected{Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::Phong|Trade::MaterialType::Flat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::BaseColorTexture, 3u},
{Trade::MaterialAttribute::BaseColorTextureCoordinates, 2u},
{Trade::MaterialAttribute::DiffuseColor, 0x808080ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.3f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
}};
/* It should give the same result both ways */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, b);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(b, a);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
}
}
void MergeTest::multipleLayersIntoSingleLayer() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::Roughness, 0.3f},
}};
Trade::MaterialData b{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::AlphaBlend, true},
/* These two layers are only in this material */
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.1f},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"layerBlendApproach", "irreversibly"}
}, {1, 4, 6}};
Trade::MaterialData expected{Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.3f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.1f},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"layerBlendApproach", "irreversibly"}
}, {4, 7, 9}};
/* It should give the same result both ways */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, b);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(b, a);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
}
}
void MergeTest::multipleLayers() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::Roughness, 0.3f},
/* This layer has no name but it'll get it from the other material
(and that's fine) */
{Trade::MaterialAttribute::LayerFactor, 0.1f},
{Trade::MaterialAttribute::Roughness, 0.5f},
}, {3, 5}};
Trade::MaterialData b{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::AlphaBlend, true},
/* These two layers are only in this material */
{Trade::MaterialLayer::ClearCoat},
/* Here's an empty layer that ends up being empty as well */
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"layerBlendApproach", "irreversibly"}
}, {1, 2, 2, 4}};
Trade::MaterialData expected{Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::AlphaBlend, true},
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.3f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.1f},
{Trade::MaterialAttribute::Roughness, 0.5f},
/* Empty layer here */
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"layerBlendApproach", "irreversibly"}
}, {4, 7, 7, 9}};
/* It should give the same result both ways */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, b);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(b, a);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
}
}
void MergeTest::conflictsSameType() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
/* Second layer */
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 15.0f},
}, {2, 4}};
Trade::MaterialData b{Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 777u},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"customAttribute", 223.0f},
}, {2, 4}};
/* If called swapped it'll use the other values */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, b, MergeConflicts::KeepFirstIfSameType);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, (Trade::MaterialData {Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 15.0f},
}, {3, 6}}), DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(b, a, MergeConflicts::KeepFirstIfSameType);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, (Trade::MaterialData {Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 777u}, /* different */
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 223.0f}, /* different */
}, {3, 6}}), DebugTools::CompareMaterial);
}
}
void MergeTest::conflictsDifferentType() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
/* Second layer */
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 15.0f},
}, {2, 4}};
/* Builtin attributes have an enforced type so this can only happen with
custom ones. It should however handle (builtin) attributes of the same
type as well */
Trade::MaterialData b{Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 777u},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{"customAttribute", "hello!"},
}, {2, 4}};
/* If called swapped it'll use the other values */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, b, MergeConflicts::KeepFirstIgnoreType);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, (Trade::MaterialData {Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 15.0f},
}, {3, 6}}), DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(b, a, MergeConflicts::KeepFirstIgnoreType);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, (Trade::MaterialData {Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 777u}, /* different */
{Trade::MaterialAttribute::LayerFactor, 1.0f},
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", "hello!"}, /* different */
}, {3, 6}}), DebugTools::CompareMaterial);
}
}
void MergeTest::conflictsFail() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MaterialData a{{}, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
/* Second layer */
{Trade::MaterialAttribute::Roughness, 0.3f},
{"customAttribute", 15.0f},
}, {2, 4}};
/* Contains Roughness but in another layer (which should be fine),
but has a conflicitng BaseColorTexture even though it's the same
value */
Trade::MaterialData b{{}, {
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 7u},
{Trade::MaterialAttribute::LayerFactor, 1.0f},
}, {2, 3}};
/* Contains customAttribute in second layer which is of a different type.
The RoughnessTexture is also conflicting but that shouldn't produce a
message since it's the same type. */
Trade::MaterialData c{{}, {
{Trade::MaterialAttribute::Roughness, 0.5f},
{Trade::MaterialAttribute::RoughnessTexture, 1u},
{"customAttribute", "hello"},
}, {2, 3}};
/* Verify that it fails in all variants */
std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!merge(a, b));
CORRADE_VERIFY(!merge(b, a));
CORRADE_VERIFY(!merge(a, c, MergeConflicts::KeepFirstIfSameType));
CORRADE_VERIFY(!merge(c, a, MergeConflicts::KeepFirstIfSameType));
CORRADE_COMPARE(out.str(),
"MaterialTools::merge(): conflicting attribute RoughnessTexture in layer 0\n"
"MaterialTools::merge(): conflicting attribute RoughnessTexture in layer 0\n"
"MaterialTools::merge(): conflicting type Trade::MaterialAttributeType::Float vs String of attribute customAttribute in layer 1\n"
"MaterialTools::merge(): conflicting type Trade::MaterialAttributeType::String vs Float of attribute customAttribute in layer 1\n");
}
void MergeTest::emptyInput() {
Trade::MaterialData a{Trade::MaterialType::PbrMetallicRoughness, {
{Trade::MaterialAttribute::BaseColor, 0xffcc66ff_rgbaf},
{Trade::MaterialAttribute::Roughness, 0.3f},
{Trade::MaterialLayer::ClearCoat},
{Trade::MaterialAttribute::LayerFactor, 0.1f},
}, {2, 4}};
Trade::MaterialData empty{Trade::MaterialType::PbrClearCoat, {}};
/* The result has just the types changed, nothing else */
Trade::MaterialData expected{Trade::MaterialType::PbrMetallicRoughness|Trade::MaterialType::PbrClearCoat, {}, a.attributeData(), {}, a.layerData()};
/* It should give the same result both ways */
{
Containers::Optional<Trade::MaterialData> actual = merge(a, empty);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
} {
Containers::Optional<Trade::MaterialData> actual = merge(empty, a);
CORRADE_VERIFY(actual);
CORRADE_COMPARE_AS(*actual, expected, DebugTools::CompareMaterial);
}
}
}}}}
CORRADE_TEST_MAIN(Magnum::MaterialTools::Test::MergeTest)
Loading…
Cancel
Save