mirror of https://github.com/mosra/magnum.git
Browse Source
Apmong other things where it's useful for end users as a more convenient alternative to recreating the MeshData by hand, I need to use this inside the transform() utilities to preserve all index buffer properties without copypasting nasty code everywhere.pull/547/head
6 changed files with 933 additions and 0 deletions
@ -0,0 +1,216 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021 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 "FilterAttributes.h" |
||||
|
||||
#include <Corrade/Containers/ArrayView.h> |
||||
#include <Corrade/Containers/GrowableArray.h> |
||||
|
||||
#include "Magnum/Trade/MeshData.h" |
||||
|
||||
namespace Magnum { namespace MeshTools { |
||||
|
||||
namespace { |
||||
|
||||
bool hasAttribute(const Containers::ArrayView<const Trade::MeshAttribute> attributes, const Trade::MeshAttribute attribute) { |
||||
for(const Trade::MeshAttribute i: attributes) |
||||
if(i == attribute) return true; |
||||
return false; |
||||
} |
||||
|
||||
/** @todo drop this insanity in favor of a BitArray */ |
||||
bool hasAttribute(const Containers::ArrayView<const UnsignedInt> attributes, const UnsignedInt attribute) { |
||||
for(const UnsignedInt i: attributes) |
||||
if(i == attribute) return true; |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
|
||||
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttribute> attributes) { |
||||
/* Not asserting here for existence of attributes since that'd be another
|
||||
O(n^2) operation */ |
||||
/** @todo but that's not consistent with the ID-based variant, or maybe do
|
||||
this via a BitArray in the second loop and check that all attributes |
||||
got referenced afterwards? */ |
||||
|
||||
/* Pick just attributes from the list */ |
||||
Containers::Array<Trade::MeshAttributeData> filtered; |
||||
arrayReserve(filtered, data.attributeCount()); |
||||
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) { |
||||
if(hasAttribute(attributes, data.attributeName(i))) |
||||
arrayAppend(filtered, data.attributeData(i)); |
||||
} |
||||
|
||||
/* Convert back to a default deleter to make this usable in plugins */ |
||||
arrayShrink(filtered, DefaultInit); |
||||
|
||||
/* Can't do just Trade::MeshIndexData{data.indices()} as that would discard
|
||||
implementation-specific types. And can't do |
||||
Trade::meshIndexData{data.indexType(), view} |
||||
because asking for index type would assert on non-indexed meshes. */ |
||||
Trade::MeshIndexData indices; |
||||
if(data.isIndexed()) indices = Trade::MeshIndexData{ |
||||
data.indexType(), |
||||
Containers::StridedArrayView1D<const void>{ |
||||
data.indexData(), |
||||
data.indexData().data() + data.indexOffset(), |
||||
data.indexCount(), |
||||
data.indexStride()}}; |
||||
|
||||
return Trade::MeshData{data.primitive(), |
||||
{}, data.indexData(), indices, |
||||
{}, data.vertexData(), std::move(filtered), |
||||
data.vertexCount()}; |
||||
} |
||||
|
||||
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes) { |
||||
return filterOnlyAttributes(data, Containers::arrayView(attributes)); |
||||
} |
||||
|
||||
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containers::ArrayView<const UnsignedInt> attributes) { |
||||
#ifndef CORRADE_NO_ASSERT |
||||
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < data.attributeCount(), |
||||
"MeshTools::filterOnlyAttributes(): index" << i << "out of range for" << data.attributeCount() << "attributes", |
||||
(Trade::MeshData{MeshPrimitive{}, 0})); |
||||
#endif |
||||
|
||||
/* Pick just attributes from the list */ |
||||
Containers::Array<Trade::MeshAttributeData> filtered; |
||||
arrayReserve(filtered, data.attributeCount()); |
||||
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) { |
||||
if(hasAttribute(attributes, i)) |
||||
arrayAppend(filtered, data.attributeData(i)); |
||||
} |
||||
|
||||
/* Convert back to a default deleter to make this usable in plugins */ |
||||
arrayShrink(filtered, DefaultInit); |
||||
|
||||
/* Can't do just Trade::MeshIndexData{data.indices()} as that would discard
|
||||
implementation-specific types. And can't do |
||||
Trade::meshIndexData{data.indexType(), view} |
||||
because asking for index type would assert on non-indexed meshes. */ |
||||
Trade::MeshIndexData indices; |
||||
if(data.isIndexed()) indices = Trade::MeshIndexData{ |
||||
data.indexType(), |
||||
Containers::StridedArrayView1D<const void>{ |
||||
data.indexData(), |
||||
data.indexData().data() + data.indexOffset(), |
||||
data.indexCount(), |
||||
data.indexStride()}}; |
||||
|
||||
return Trade::MeshData{data.primitive(), |
||||
{}, data.indexData(), indices, |
||||
{}, data.vertexData(), std::move(filtered), |
||||
data.vertexCount()}; |
||||
} |
||||
|
||||
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes) { |
||||
return filterOnlyAttributes(data, Containers::arrayView(attributes)); |
||||
} |
||||
|
||||
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttribute> attributes) { |
||||
/* Not asserting here for existence of attributes since that'd be another
|
||||
O(n^2) operation */ |
||||
/** @todo but that's not consistent with the ID-based variant, or maybe do
|
||||
this via a BitArray in the second loop and check that all attributes |
||||
got referenced afterwards? */ |
||||
|
||||
/* Pick just attributes from the list */ |
||||
Containers::Array<Trade::MeshAttributeData> filtered; |
||||
arrayReserve(filtered, data.attributeCount()); |
||||
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) { |
||||
if(!hasAttribute(attributes, data.attributeName(i))) |
||||
arrayAppend(filtered, data.attributeData(i)); |
||||
} |
||||
|
||||
/* Convert back to a default deleter to make this usable in plugins */ |
||||
arrayShrink(filtered, DefaultInit); |
||||
|
||||
/* Can't do just Trade::MeshIndexData{data.indices()} as that would discard
|
||||
implementation-specific types. And can't do |
||||
Trade::meshIndexData{data.indexType(), view} |
||||
because asking for index type would assert on non-indexed meshes. */ |
||||
Trade::MeshIndexData indices; |
||||
if(data.isIndexed()) indices = Trade::MeshIndexData{ |
||||
data.indexType(), |
||||
Containers::StridedArrayView1D<const void>{ |
||||
data.indexData(), |
||||
data.indexData().data() + data.indexOffset(), |
||||
data.indexCount(), |
||||
data.indexStride()}}; |
||||
|
||||
return Trade::MeshData{data.primitive(), |
||||
{}, data.indexData(), indices, |
||||
{}, data.vertexData(), std::move(filtered), |
||||
data.vertexCount()}; |
||||
} |
||||
|
||||
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes) { |
||||
return filterExceptAttributes(data, Containers::arrayView(attributes)); |
||||
} |
||||
|
||||
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Containers::ArrayView<const UnsignedInt> attributes) { |
||||
#ifndef CORRADE_NO_ASSERT |
||||
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < data.attributeCount(), |
||||
"MeshTools::filterExceptAttributes(): index" << i << "out of range for" << data.attributeCount() << "attributes", |
||||
(Trade::MeshData{MeshPrimitive{}, 0})); |
||||
#endif |
||||
|
||||
/* Pick just attributes from the list */ |
||||
Containers::Array<Trade::MeshAttributeData> filtered; |
||||
arrayReserve(filtered, data.attributeCount()); |
||||
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) { |
||||
if(!hasAttribute(attributes, i)) |
||||
arrayAppend(filtered, data.attributeData(i)); |
||||
} |
||||
|
||||
/* Convert back to a default deleter to make this usable in plugins */ |
||||
arrayShrink(filtered, DefaultInit); |
||||
|
||||
/* Can't do just Trade::MeshIndexData{data.indices()} as that would discard
|
||||
implementation-specific types. And can't do |
||||
Trade::meshIndexData{data.indexType(), view} |
||||
because asking for index type would assert on non-indexed meshes. */ |
||||
Trade::MeshIndexData indices; |
||||
if(data.isIndexed()) indices = Trade::MeshIndexData{ |
||||
data.indexType(), |
||||
Containers::StridedArrayView1D<const void>{ |
||||
data.indexData(), |
||||
data.indexData().data() + data.indexOffset(), |
||||
data.indexCount(), |
||||
data.indexStride()}}; |
||||
|
||||
return Trade::MeshData{data.primitive(), |
||||
{}, data.indexData(), indices, |
||||
{}, data.vertexData(), std::move(filtered), |
||||
data.vertexCount()}; |
||||
} |
||||
|
||||
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes) { |
||||
return filterExceptAttributes(data, Containers::arrayView(attributes)); |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,140 @@
|
||||
#ifndef Magnum_MeshTools_FilterAttributes_h |
||||
#define Magnum_MeshTools_FilterAttributes_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021 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::MeshTools::filterOnlyAttributes(), @ref Magnum::MeshTools::filterExceptAttributes() |
||||
* @m_since_latest |
||||
*/ |
||||
|
||||
#include <initializer_list> |
||||
|
||||
#include "Magnum/MeshTools/visibility.h" |
||||
#include "Magnum/Trade/Trade.h" |
||||
|
||||
namespace Magnum { namespace MeshTools { |
||||
|
||||
/**
|
||||
@brief Filter a mesh to contain only the selected subset of named attributes |
||||
@m_since_latest |
||||
|
||||
Returns a non-owning reference to the vertex and index buffer from @p data with |
||||
only the attributes that are listed in @p attributes. The index buffer, if |
||||
present, is left untouched. Attributes from the list that are not present in |
||||
@p data are skipped. All duplicates of a listed attribute are kept --- if you |
||||
want a different behavior, use the @ref filterOnlyAttributes(const Trade::MeshData&, Containers::ArrayView<const UnsignedInt>) |
||||
overload and pick attributes by their IDs instead. |
||||
|
||||
This function only operates on the attribute metadata --- if you'd like to have |
||||
the vertex data repacked to contain just the remaining attributes as well, pass |
||||
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()" |
||||
without @ref InterleaveFlag::PreserveInterleavedAttributes set. |
||||
@see @ref reference() |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttribute> attributes); |
||||
|
||||
/**
|
||||
* @overload |
||||
* @m_since_latest |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes); |
||||
|
||||
/**
|
||||
@brief Filter a mesh to contain only the selected subset of attributes |
||||
@m_since_latest |
||||
|
||||
Returns a non-owning reference to the vertex and index buffer from @p data with |
||||
only the attribute IDs listed in @p attributes. IDs specified more than once |
||||
don't result in given attribute being added multiple times. The index buffer, |
||||
if present, is left untouched. All attribute IDs are expected to be smaller |
||||
than @ref Trade::MeshData::attributeCount() const. |
||||
|
||||
This function only operates on the attribute metadata --- if you'd like to have |
||||
the vertex data repacked to contain just the remaining attributes as well, pass |
||||
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()" |
||||
without @ref InterleaveFlag::PreserveInterleavedAttributes set. |
||||
@see @ref reference() |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, Containers::ArrayView<const UnsignedInt> attributes); |
||||
|
||||
/**
|
||||
* @overload |
||||
* @m_since_latest |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes); |
||||
|
||||
/**
|
||||
@brief Filter a mesh to contain everything except the selected subset of named attributes |
||||
@m_since_latest |
||||
|
||||
Returns a non-owning reference to the vertex and index buffer from @p data with |
||||
only the attributes that are not listed in @p attributes. The index buffer, if |
||||
present, is left untouched. Attributes from the list that are not present in |
||||
@p data are skipped. All duplicates of a listed attribute are removed --- if |
||||
you want a different behavior, use the @ref filterExceptAttributes(const Trade::MeshData&, Containers::ArrayView<const UnsignedInt>) |
||||
overload and pick attributes by their IDs instead. If @p attributes is empty, |
||||
the behavior is equivalent to @ref reference(). |
||||
|
||||
This function only operates on the attribute metadata --- if you'd like to have |
||||
the vertex data repacked to contain just the remaining attributes as well, pass |
||||
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()" |
||||
without @ref InterleaveFlag::PreserveInterleavedAttributes set. |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttribute> attributes); |
||||
|
||||
/**
|
||||
* @overload |
||||
* @m_since_latest |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes); |
||||
|
||||
/**
|
||||
@brief Filter a mesh to contain everything except the selected subset of attributes |
||||
@m_since_latest |
||||
|
||||
Returns a non-owning reference to the vertex and index buffer from @p data with |
||||
only the attribute IDs that are not listed in @p attributes. IDs specified |
||||
multiple times behave like if specified just once. The index buffer, if |
||||
present, is left untouched. All attribute IDs are expected to be smaller than |
||||
@ref Trade::MeshData::attributeCount() const. If @p attributes is empty, the |
||||
behavior is equivalent to @ref reference(). |
||||
|
||||
This function only operates on the attribute metadata --- if you'd like to have |
||||
the vertex data repacked to contain just the remaining attributes as well, pass |
||||
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()" |
||||
without @ref InterleaveFlag::PreserveInterleavedAttributes set. |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, Containers::ArrayView<const UnsignedInt> attributes); |
||||
|
||||
/**
|
||||
* @overload |
||||
* @m_since_latest |
||||
*/ |
||||
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes); |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,570 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021 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/Math/Vector4.h" |
||||
#include "Magnum/MeshTools/FilterAttributes.h" |
||||
#include "Magnum/Trade/MeshData.h" |
||||
|
||||
namespace Magnum { namespace MeshTools { namespace Test { namespace { |
||||
|
||||
struct FilterAttributesTest: TestSuite::Tester { |
||||
explicit FilterAttributesTest(); |
||||
|
||||
void filterOnlyAttributeNames(); |
||||
void filterOnlyAttributeNamesNoIndexData(); |
||||
void filterOnlyAttributeNamesNoAttributeData(); |
||||
|
||||
void filterOnlyAttributeIds(); |
||||
void filterOnlyAttributeIdsOutOfBounds(); |
||||
void filterOnlyAttributeIdsNoIndexData(); |
||||
void filterOnlyAttributeIdsNoAttributeData(); |
||||
|
||||
void filterExceptAttributeNames(); |
||||
void filterExceptAttributeNamesNoIndexData(); |
||||
void filterExceptAttributeNamesNoAttributeData(); |
||||
|
||||
void filterExceptAttributeIds(); |
||||
void filterExceptAttributeIdsOutOfBounds(); |
||||
void filterExceptAttributeIdsNoIndexData(); |
||||
void filterExceptAttributeIdsNoAttributeData(); |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
MeshIndexType indexType; |
||||
} ImplementationSpecificIndexTypeData[]{ |
||||
{"", MeshIndexType::UnsignedShort}, |
||||
{"implementation-specific index type", meshIndexTypeWrap(0xcaca)} |
||||
}; |
||||
|
||||
FilterAttributesTest::FilterAttributesTest() { |
||||
addInstancedTests({&FilterAttributesTest::filterOnlyAttributeNames}, |
||||
Containers::arraySize(ImplementationSpecificIndexTypeData)); |
||||
|
||||
addTests({&FilterAttributesTest::filterOnlyAttributeNamesNoIndexData, |
||||
&FilterAttributesTest::filterOnlyAttributeNamesNoAttributeData}); |
||||
|
||||
addInstancedTests({&FilterAttributesTest::filterOnlyAttributeIds}, |
||||
Containers::arraySize(ImplementationSpecificIndexTypeData)); |
||||
|
||||
addTests({&FilterAttributesTest::filterOnlyAttributeIdsOutOfBounds, |
||||
&FilterAttributesTest::filterOnlyAttributeIdsNoIndexData, |
||||
&FilterAttributesTest::filterOnlyAttributeIdsNoAttributeData}); |
||||
|
||||
addInstancedTests({&FilterAttributesTest::filterExceptAttributeNames}, |
||||
Containers::arraySize(ImplementationSpecificIndexTypeData)); |
||||
|
||||
addTests({&FilterAttributesTest::filterExceptAttributeNamesNoIndexData, |
||||
&FilterAttributesTest::filterExceptAttributeNamesNoAttributeData}); |
||||
|
||||
addInstancedTests({&FilterAttributesTest::filterExceptAttributeIds}, |
||||
Containers::arraySize(ImplementationSpecificIndexTypeData)); |
||||
|
||||
addTests({&FilterAttributesTest::filterExceptAttributeIdsOutOfBounds, |
||||
&FilterAttributesTest::filterExceptAttributeIdsNoIndexData, |
||||
&FilterAttributesTest::filterExceptAttributeIdsNoAttributeData}); |
||||
} |
||||
|
||||
struct Vertex { |
||||
Vector3 position; |
||||
Vector4 tangent; |
||||
Vector2 textureCoordinates1, textureCoordinates2; |
||||
}; |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeNames() { |
||||
auto&& data = ImplementationSpecificIndexTypeData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleStrip, |
||||
std::move(indexData), Trade::MeshIndexData{data.indexType, indices}, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertices.slice(&Vertex::tangent)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates2)}, |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, { |
||||
Trade::MeshAttribute::Position, |
||||
Trade::MeshAttribute::Normal, /* not present, ignored */ |
||||
Trade::MeshAttribute::TextureCoordinates, /* present twice */ |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleStrip); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), data.indexType); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 3); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::Position); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, position)); |
||||
CORRADE_COMPARE(filtered.attributeName(1), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(1), offsetof(Vertex, textureCoordinates1)); |
||||
CORRADE_COMPARE(filtered.attributeName(2), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(2), offsetof(Vertex, textureCoordinates2)); |
||||
|
||||
/* The attribute data should not be a growable array to make this usable in
|
||||
plugins */ |
||||
Containers::Array<Trade::MeshAttributeData> attributeData = filtered.releaseAttributeData(); |
||||
CORRADE_VERIFY(!attributeData.deleter()); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeNamesNoIndexData() { |
||||
/* A trivial subset of filterOnlyAttributeNames() testing it doesn't blow
|
||||
up if the mesh is not indexed */ |
||||
|
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, { |
||||
Trade::MeshAttribute::TextureCoordinates |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleFan); |
||||
|
||||
CORRADE_VERIFY(!filtered.isIndexed()); |
||||
/* Consistent with behavior in reference() for index-less meshes */ |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 1); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, textureCoordinates1)); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeNamesNoAttributeData() { |
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::Points, |
||||
std::move(indexData), Trade::MeshIndexData{indices}, 15}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, { |
||||
Trade::MeshAttribute::Position |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::Points); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), MeshIndexType::UnsignedShort); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* The vertex count should get preserved even if there are no attributes */ |
||||
CORRADE_COMPARE(filtered.vertexCount(), 15); |
||||
/* Consistent with behavior in reference() for vertex-less meshes */ |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.attributeCount(), 0); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeIds() { |
||||
auto&& data = ImplementationSpecificIndexTypeData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleStrip, |
||||
std::move(indexData), Trade::MeshIndexData{data.indexType, indices}, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertices.slice(&Vertex::tangent)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates2)}, |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, { |
||||
/* The attribute 1 is specified twice, but that won't result in the
|
||||
same attribute being added twice */ |
||||
1, 1, 3 |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleStrip); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), data.indexType); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 2); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::Tangent); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, tangent)); |
||||
CORRADE_COMPARE(filtered.attributeName(1), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(1), offsetof(Vertex, textureCoordinates2)); |
||||
|
||||
/* The attribute data should not be a growable array to make this usable in
|
||||
plugins */ |
||||
Containers::Array<Trade::MeshAttributeData> attributeData = filtered.releaseAttributeData(); |
||||
CORRADE_VERIFY(!attributeData.deleter()); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeIdsOutOfBounds() { |
||||
#ifdef CORRADE_NO_ASSERT |
||||
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); |
||||
#endif |
||||
|
||||
Vertex vertices[3]{}; |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
{}, vertices, { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(vertices).slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::stridedArrayView(vertices).slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
filterOnlyAttributes(mesh, {0, 0, 2}); |
||||
CORRADE_COMPARE(out.str(), "MeshTools::filterOnlyAttributes(): index 2 out of range for 2 attributes\n"); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeIdsNoIndexData() { |
||||
/* A trivial subset of filterOnlyAttributeIds() testing it doesn't blow up
|
||||
if the mesh is not indexed */ |
||||
|
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, { |
||||
0 |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleFan); |
||||
|
||||
CORRADE_VERIFY(!filtered.isIndexed()); |
||||
/* Consistent with behavior in reference() for index-less meshes */ |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 1); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, textureCoordinates1)); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterOnlyAttributeIdsNoAttributeData() { |
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::Points, |
||||
std::move(indexData), Trade::MeshIndexData{indices}, 15}; |
||||
|
||||
Trade::MeshData filtered = filterOnlyAttributes(mesh, std::initializer_list<UnsignedInt>{}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::Points); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), MeshIndexType::UnsignedShort); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* The vertex count should get preserved even if there are no attributes */ |
||||
CORRADE_COMPARE(filtered.vertexCount(), 15); |
||||
/* Consistent with behavior in reference() for vertex-less meshes */ |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.attributeCount(), 0); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeNames() { |
||||
auto&& data = ImplementationSpecificIndexTypeData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleStrip, |
||||
std::move(indexData), Trade::MeshIndexData{data.indexType, indices}, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertices.slice(&Vertex::tangent)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates2)}, |
||||
/* Positions again, just under a different name. Should be kept. */ |
||||
Trade::MeshAttributeData{Trade::meshAttributeCustom(0xbaf), vertices.slice(&Vertex::position)}, |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, { |
||||
Trade::MeshAttribute::Position, |
||||
Trade::MeshAttribute::Normal, /* not present, ignored */ |
||||
Trade::MeshAttribute::TextureCoordinates, /* present twice */ |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleStrip); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), data.indexType); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 2); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::Tangent); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, tangent)); |
||||
CORRADE_COMPARE(filtered.attributeName(1), Trade::meshAttributeCustom(0xbaf)); |
||||
CORRADE_COMPARE(filtered.attributeOffset(1), offsetof(Vertex, position)); |
||||
|
||||
/* The attribute data should not be a growable array to make this usable in
|
||||
plugins */ |
||||
Containers::Array<Trade::MeshAttributeData> attributeData = filtered.releaseAttributeData(); |
||||
CORRADE_VERIFY(!attributeData.deleter()); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeNamesNoIndexData() { |
||||
/* A trivial subset of filterExceptAttributeNames() testing it doesn't blow
|
||||
up if the mesh is not indexed */ |
||||
|
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, { |
||||
Trade::MeshAttribute::Position |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleFan); |
||||
|
||||
CORRADE_VERIFY(!filtered.isIndexed()); |
||||
/* Consistent with behavior in reference() for index-less meshes */ |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 1); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, textureCoordinates1)); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeNamesNoAttributeData() { |
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::Points, |
||||
std::move(indexData), Trade::MeshIndexData{indices}, 15}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, { |
||||
Trade::MeshAttribute::Position |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::Points); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), MeshIndexType::UnsignedShort); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* The vertex count should get preserved even if there are no attributes */ |
||||
CORRADE_COMPARE(filtered.vertexCount(), 15); |
||||
/* Consistent with behavior in reference() for vertex-less meshes */ |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.attributeCount(), 0); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeIds() { |
||||
auto&& data = ImplementationSpecificIndexTypeData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleStrip, |
||||
std::move(indexData), Trade::MeshIndexData{data.indexType, indices}, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertices.slice(&Vertex::tangent)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates2)}, |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, { |
||||
/* The attribute 1 is specified twice, but that won't result in
|
||||
attribute 1 being removed and then again */ |
||||
1, 1, 3 |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleStrip); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), data.indexType); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 2); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::Position); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, position)); |
||||
CORRADE_COMPARE(filtered.attributeName(1), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(1), offsetof(Vertex, textureCoordinates1)); |
||||
|
||||
/* The attribute data should not be a growable array to make this usable in
|
||||
plugins */ |
||||
Containers::Array<Trade::MeshAttributeData> attributeData = filtered.releaseAttributeData(); |
||||
CORRADE_VERIFY(!attributeData.deleter()); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeIdsOutOfBounds() { |
||||
#ifdef CORRADE_NO_ASSERT |
||||
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); |
||||
#endif |
||||
|
||||
Vertex vertices[3]{}; |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
{}, vertices, { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(vertices).slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::stridedArrayView(vertices).slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
filterExceptAttributes(mesh, {0, 0, 2}); |
||||
CORRADE_COMPARE(out.str(), "MeshTools::filterExceptAttributes(): index 2 out of range for 2 attributes\n"); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeIdsNoIndexData() { |
||||
/* A trivial subset of filterExceptAttributeIds() testing it doesn't blow up
|
||||
if the mesh is not indexed */ |
||||
|
||||
Containers::Array<char> vertexData{3*sizeof(Vertex)}; |
||||
Containers::StridedArrayView1D<Vertex> vertices = Containers::arrayCast<Vertex>(vertexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::TriangleFan, |
||||
std::move(vertexData), { |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates1)} |
||||
}}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, { |
||||
0 |
||||
}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::TriangleFan); |
||||
|
||||
CORRADE_VERIFY(!filtered.isIndexed()); |
||||
/* Consistent with behavior in reference() for index-less meshes */ |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.vertexCount(), 3); |
||||
CORRADE_COMPARE(filtered.vertexData().data(), vertices.data()); |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* Testing just the offset if it matches expectations, the
|
||||
MeshAttributeData is copied directly so no metadata should get lost */ |
||||
CORRADE_COMPARE(filtered.attributeCount(), 1); |
||||
CORRADE_COMPARE(filtered.attributeName(0), Trade::MeshAttribute::TextureCoordinates); |
||||
CORRADE_COMPARE(filtered.attributeOffset(0), offsetof(Vertex, textureCoordinates1)); |
||||
} |
||||
|
||||
void FilterAttributesTest::filterExceptAttributeIdsNoAttributeData() { |
||||
Containers::Array<char> indexData{5*sizeof(UnsignedShort)}; |
||||
Containers::StridedArrayView1D<UnsignedShort> indices = Containers::arrayCast<UnsignedShort>(indexData); |
||||
|
||||
Trade::MeshData mesh{MeshPrimitive::Points, |
||||
std::move(indexData), Trade::MeshIndexData{indices}, 15}; |
||||
|
||||
Trade::MeshData filtered = filterExceptAttributes(mesh, std::initializer_list<UnsignedInt>{}); |
||||
CORRADE_COMPARE(filtered.primitive(), MeshPrimitive::Points); |
||||
|
||||
CORRADE_VERIFY(filtered.isIndexed()); |
||||
CORRADE_COMPARE(filtered.indexCount(), 5); |
||||
CORRADE_COMPARE(filtered.indexType(), MeshIndexType::UnsignedShort); |
||||
CORRADE_COMPARE(filtered.indexData().data(), indices.data()); |
||||
CORRADE_COMPARE(filtered.indexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
/* The vertex count should get preserved even if there are no attributes */ |
||||
CORRADE_COMPARE(filtered.vertexCount(), 15); |
||||
/* Consistent with behavior in reference() for vertex-less meshes */ |
||||
CORRADE_COMPARE(filtered.vertexDataFlags(), Trade::DataFlags{}); |
||||
|
||||
CORRADE_COMPARE(filtered.attributeCount(), 0); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::FilterAttributesTest) |
||||
Loading…
Reference in new issue