From 2a707b8ea4df699c14778bf1fa8ec6f1a98b6312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 10 May 2023 19:26:19 +0200 Subject: [PATCH] MaterialTools: add copy(). --- src/Magnum/MaterialTools/CMakeLists.txt | 2 + src/Magnum/MaterialTools/Copy.cpp | 67 ++++++ src/Magnum/MaterialTools/Copy.h | 67 ++++++ src/Magnum/MaterialTools/Test/CMakeLists.txt | 1 + src/Magnum/MaterialTools/Test/CopyTest.cpp | 223 +++++++++++++++++++ 5 files changed, 360 insertions(+) create mode 100644 src/Magnum/MaterialTools/Copy.cpp create mode 100644 src/Magnum/MaterialTools/Copy.h create mode 100644 src/Magnum/MaterialTools/Test/CopyTest.cpp diff --git a/src/Magnum/MaterialTools/CMakeLists.txt b/src/Magnum/MaterialTools/CMakeLists.txt index 1767b90ad..c8e985d77 100644 --- a/src/Magnum/MaterialTools/CMakeLists.txt +++ b/src/Magnum/MaterialTools/CMakeLists.txt @@ -29,6 +29,7 @@ set(CMAKE_FOLDER "Magnum/MaterialTools") # Files shared between main library and unit test library set(MagnumMaterialTools_SRCS + Copy.cpp PhongToPbrMetallicRoughness.cpp) # Files compiled with different flags for main library and unit test library @@ -37,6 +38,7 @@ set(MagnumMaterialTools_GracefulAssert_SRCS Merge.cpp) set(MagnumMaterialTools_HEADERS + Copy.h Filter.h Merge.h PhongToPbrMetallicRoughness.h diff --git a/src/Magnum/MaterialTools/Copy.cpp b/src/Magnum/MaterialTools/Copy.cpp new file mode 100644 index 000000000..957d46050 --- /dev/null +++ b/src/Magnum/MaterialTools/Copy.cpp @@ -0,0 +1,67 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 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 "Copy.h" + +#include + +#include "Magnum/Trade/MaterialData.h" + +namespace Magnum { namespace MaterialTools { + +Trade::MaterialData copy(const Trade::MaterialData& material) { + return copy(Trade::MaterialData{material.types(), + {}, material.attributeData(), + {}, material.layerData(), + material.importerState()}); +} + +Trade::MaterialData copy(Trade::MaterialData&& material) { + /* Transfer attributes if they're owned & mutable, allocate a copy + otherwise */ + Containers::Array attributes; + if(material.attributeDataFlags() >= (Trade::DataFlag::Mutable|Trade::DataFlag::Owned)) + attributes = material.releaseAttributeData(); + else { + /* DefaultInit so we don't use a non-default deleter which could cause + problems in plugins */ + attributes = Containers::Array{DefaultInit, material.attributeData().size()}; + Utility::copy(material.attributeData(), attributes); + } + + /* Same for layers, here it can be NoInit; if the original has implicit + single layer (and empty data), this makes no allocation either */ + Containers::Array layers; + if(material.attributeDataFlags() >= (Trade::DataFlag::Mutable|Trade::DataFlag::Owned)) + layers = material.releaseLayerData(); + else { + layers = Containers::Array{NoInit, material.layerData().size()}; + Utility::copy(material.layerData(), layers); + } + + return Trade::MaterialData{material.types(), std::move(attributes), std::move(layers), material.importerState()}; +} + +}} diff --git a/src/Magnum/MaterialTools/Copy.h b/src/Magnum/MaterialTools/Copy.h new file mode 100644 index 000000000..249e8ae58 --- /dev/null +++ b/src/Magnum/MaterialTools/Copy.h @@ -0,0 +1,67 @@ +#ifndef Magnum_MaterialTools_Copy_h +#define Magnum_MaterialTools_Copy_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 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 Function @ref Magnum::MaterialTools::copy() + * @m_since_latest + */ + +#include "Magnum/MaterialTools/visibility.h" +#include "Magnum/Trade/Trade.h" + +namespace Magnum { namespace MaterialTools { + +/** +@brief Make an owned copy of the material +@m_since_latest + +Allocates a copy of @ref Trade::MaterialData::attributeData() and +@relativeref{Trade::MaterialData,layerData()} and returns a new material with +those. All other properties such as material types or importer state are passed +through unchanged. The resulting @ref Trade::MaterialData::attributeDataFlags() +and @relativeref{Trade::MaterialData,layerDataFlags()} are always +@ref Trade::DataFlag::Owned and @ref Trade::DataFlag::Mutable. +@see @ref copy(Trade::MaterialData&&) +*/ +MAGNUM_MATERIALTOOLS_EXPORT Trade::MaterialData copy(const Trade::MaterialData& material); + +/** +@brief Make a material with owned data +@m_since_latest + +If either @ref Trade::MaterialData::attributeDataFlags() or +@relativeref{Trade::MaterialData,layerDataFlags()} are not +@ref Trade::DataFlag::Owned and @ref Trade::DataFlag::Mutable, allocates a copy +of @ref Trade::MaterialData::attributeData() or +@relativeref{Trade::MaterialData,layerData()}, otherwise transfers their +ownership. The resulting data are always owned and mutable. +*/ +MAGNUM_MATERIALTOOLS_EXPORT Trade::MaterialData copy(Trade::MaterialData&& material); + +}} + +#endif diff --git a/src/Magnum/MaterialTools/Test/CMakeLists.txt b/src/Magnum/MaterialTools/Test/CMakeLists.txt index 8bffb1d70..fc5abe437 100644 --- a/src/Magnum/MaterialTools/Test/CMakeLists.txt +++ b/src/Magnum/MaterialTools/Test/CMakeLists.txt @@ -27,6 +27,7 @@ # property that would have to be set on each target separately. set(CMAKE_FOLDER "Magnum/MaterialTools/Test") +corrade_add_test(MaterialToolsCopyTest CopyTest.cpp LIBRARIES MagnumMaterialTools) 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) diff --git a/src/Magnum/MaterialTools/Test/CopyTest.cpp b/src/Magnum/MaterialTools/Test/CopyTest.cpp new file mode 100644 index 000000000..804390708 --- /dev/null +++ b/src/Magnum/MaterialTools/Test/CopyTest.cpp @@ -0,0 +1,223 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 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 + +#include "Magnum/MaterialTools/Copy.h" +#include "Magnum/Math/Color.h" +#include "Magnum/Trade/MaterialData.h" + +namespace Magnum { namespace MaterialTools { namespace Test { namespace { + +struct CopyTest: TestSuite::Tester { + explicit CopyTest(); + + void singleLayer(); + void singleLayerNoLayerData(); + + void multipleLayers(); + + void rvalueNotOwned(); + void rvalueOwnedAttributesLayers(); + /* There's currently no constructor (and no use case) that would need owned + attributes but not layers or vice versa, it's either all or none */ + void rvalueOwnedAttributesNoLayerData(); +}; + +CopyTest::CopyTest() { + addTests({&CopyTest::singleLayer, + &CopyTest::singleLayerNoLayerData, + + &CopyTest::multipleLayers, + + &CopyTest::rvalueNotOwned, + &CopyTest::rvalueOwnedAttributesLayers, + &CopyTest::rvalueOwnedAttributesNoLayerData}); +} + +using namespace Math::Literals; + +void CopyTest::singleLayer() { + Trade::MaterialData material{Trade::MaterialType::PbrMetallicRoughness, { + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }, {3}, reinterpret_cast(0xdeadbeef)}; + + Trade::MaterialData copy = MaterialTools::copy(material); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerCount(), 1); + CORRADE_COMPARE(copy.layerData().size(), 1); + CORRADE_COMPARE(copy.layerData()[0], 3); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeCount(), 3); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute("baseColorTextureName"), "yesss.png"); + + /* The data should have a default deleter to make this usable in plugins */ + Containers::Array attributeData = copy.releaseAttributeData(); + Containers::Array layerData = copy.releaseLayerData(); + CORRADE_VERIFY(!attributeData.deleter()); + CORRADE_VERIFY(!layerData.deleter()); +} + +void CopyTest::singleLayerNoLayerData() { + Trade::MaterialData material{Trade::MaterialType::PbrMetallicRoughness, { + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }, reinterpret_cast(0xdeadbeef)}; + + Trade::MaterialData copy = MaterialTools::copy(material); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerCount(), 1); + CORRADE_COMPARE(copy.layerData().size(), 0); + CORRADE_COMPARE(copy.layerData(), nullptr); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeCount(), 3); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute("baseColorTextureName"), "yesss.png"); +} + +void CopyTest::multipleLayers() { + Trade::MaterialData material{Trade::MaterialType::PbrMetallicRoughness, { + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }, {2, 3}, reinterpret_cast(0xdeadbeef)}; + + Trade::MaterialData copy = MaterialTools::copy(material); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerCount(), 2); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeCount(0), 2); + CORRADE_COMPARE(copy.attributeCount(1), 1); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute(1, "baseColorTextureName"), "yesss.png"); + + /* The data should have a default deleter to make this usable in plugins */ + Containers::Array attributeData = copy.releaseAttributeData(); + Containers::Array layerData = copy.releaseLayerData(); + CORRADE_VERIFY(!attributeData.deleter()); + CORRADE_VERIFY(!layerData.deleter()); +} + +void CopyTest::rvalueNotOwned() { + Trade::MaterialAttributeData attributes[]{ + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }; + UnsignedInt layers[]{2, 3}; + + Trade::MaterialData copy = MaterialTools::copy(Trade::MaterialData{Trade::MaterialType::PbrMetallicRoughness, + Trade::DataFlag::Mutable, attributes, + Trade::DataFlag::Mutable|Trade::DataFlag::ExternallyOwned, layers, + reinterpret_cast(0xdeadbeef)}); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerCount(), 2); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeCount(0), 2); + CORRADE_COMPARE(copy.attributeCount(1), 1); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute(1, "baseColorTextureName"), "yesss.png"); +} + +void CopyTest::rvalueOwnedAttributesLayers() { + Containers::Array attributes{InPlaceInit, { + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }}; + Containers::Array layers{InPlaceInit, {2, 3}}; + const void* originalAttributes = attributes.data(); + const void* originalLayers = layers.data(); + + Trade::MaterialData copy = MaterialTools::copy(Trade::MaterialData{Trade::MaterialType::PbrMetallicRoughness, std::move(attributes), std::move(layers), reinterpret_cast(0xdeadbeef)}); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerData().data(), originalLayers); + CORRADE_COMPARE(copy.layerCount(), 2); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeData().data(), originalAttributes); + CORRADE_COMPARE(copy.attributeCount(0), 2); + CORRADE_COMPARE(copy.attributeCount(1), 1); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(0, Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute(1, "baseColorTextureName"), "yesss.png"); +} + +void CopyTest::rvalueOwnedAttributesNoLayerData() { + Containers::Array attributes{InPlaceInit, { + {Trade::MaterialAttribute::AlphaBlend, true}, + {Trade::MaterialAttribute::BaseColor, 0xff3366ff_rgbaf}, + {"baseColorTextureName", "yesss.png"}, + }}; + Containers::Array layers{InPlaceInit, {2, 3}}; + const void* originalAttributes = attributes.data(); + + Trade::MaterialData copy = MaterialTools::copy(Trade::MaterialData{Trade::MaterialType::PbrMetallicRoughness, std::move(attributes), reinterpret_cast(0xdeadbeef)}); + CORRADE_COMPARE(copy.types(), Trade::MaterialType::PbrMetallicRoughness); + CORRADE_COMPARE(copy.importerState(), reinterpret_cast(0xdeadbeef)); + + CORRADE_COMPARE(copy.layerDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.layerCount(), 1); + CORRADE_COMPARE(copy.layerData().size(), 0); + CORRADE_COMPARE(copy.layerData(), nullptr); + + CORRADE_COMPARE(copy.attributeDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable); + CORRADE_COMPARE(copy.attributeData().data(), originalAttributes); + CORRADE_COMPARE(copy.attributeCount(), 3); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::AlphaBlend), true); + CORRADE_COMPARE(copy.attribute(Trade::MaterialAttribute::BaseColor), 0xff3366ff_rgbaf); + CORRADE_COMPARE(copy.attribute("baseColorTextureName"), "yesss.png"); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::MaterialTools::Test::CopyTest)