Browse Source

MeshTools: implement interleavedLayout().

This was originally meant to be an interleave() that operates on
MeshData, but later I realized I need the same logic in duplicate(), so
turned it into a private function. Now I am pretty sure I'll be using
this function in *many* importer plugins :D
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
1e85279872
  1. 2
      doc/changelog.dox
  2. 35
      doc/snippets/MagnumMeshTools.cpp
  3. 2
      src/Magnum/MeshTools/CMakeLists.txt
  4. 85
      src/Magnum/MeshTools/Interleave.cpp
  5. 37
      src/Magnum/MeshTools/Interleave.h
  6. 2
      src/Magnum/MeshTools/Test/CMakeLists.txt
  7. 283
      src/Magnum/MeshTools/Test/InterleaveTest.cpp

2
doc/changelog.dox

@ -111,6 +111,8 @@ See also:
- New @ref MeshTools::isInterleaved() utility for checking if
@ref Trade::MeshData is interleaved
- Added @ref MeshTools::interleavedLayout() for convenient creation of an
interleaved mesh layout using the new @ref Trade::MeshData API
- Added @ref MeshTools::subdivideInPlace() for allocation-less mesh
subdivision
- New @ref MeshTools::removeDuplicatesInPlace() variant that works on

35
doc/snippets/MagnumMeshTools.cpp

@ -32,6 +32,7 @@
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/MeshTools/RemoveDuplicates.h"
#include "Magnum/MeshTools/Transform.h"
#include "Magnum/Trade/MeshData.h"
using namespace Magnum;
using namespace Magnum::Math::Literals;
@ -96,6 +97,40 @@ auto data = MeshTools::interleave(positions, weights, 2, vertexColors, 1);
/* [interleave2] */
}
{
Trade::MeshData data{MeshPrimitive::Lines, 0};
UnsignedInt vertexCount{};
Containers::Array<char> indexData;
/* [interleavedLayout-extra] */
Containers::ArrayView<const Trade::MeshAttributeData> attributes =
data.attributeData();
/* Take just positions and normals and add a four-byte padding in between */
Trade::MeshData layout = MeshTools::interleavedLayout(
Trade::MeshData{MeshPrimitive::Triangles, 0}, vertexCount, {
attributes[data.attributeId(Trade::MeshAttribute::Position)],
Trade::MeshAttributeData{4},
attributes[data.attributeId(Trade::MeshAttribute::Normal)]
});
/* [interleavedLayout-extra] */
}
{
Trade::MeshData data{MeshPrimitive::Lines, 0};
Containers::ArrayView<Trade::MeshAttributeData> extraAttributes;
UnsignedInt vertexCount{};
Containers::Array<char> indexData;
/* [interleavedLayout-indices] */
Trade::MeshData layout =
MeshTools::interleavedLayout(data, vertexCount, extraAttributes);
Trade::MeshIndexData indices;
Trade::MeshData indexed{data.primitive(),
std::move(indexData), indices,
layout.releaseVertexData(), layout.releaseAttributeData()};
/* [interleavedLayout-indices] */
}
{
/* [removeDuplicates] */
Containers::ArrayView<Vector3i> data;

2
src/Magnum/MeshTools/CMakeLists.txt

@ -25,7 +25,6 @@
# Files shared between main library and unit test library
set(MagnumMeshTools_SRCS
Interleave.cpp
Tipsify.cpp)
# Files compiled with different flags for main library and unit test library
@ -35,6 +34,7 @@ set(MagnumMeshTools_GracefulAssert_SRCS
Duplicate.cpp
FlipNormals.cpp
GenerateNormals.cpp
Interleave.cpp
RemoveDuplicates.cpp)
set(MagnumMeshTools_HEADERS

85
src/Magnum/MeshTools/Interleave.cpp

@ -49,4 +49,89 @@ bool isInterleaved(const Trade::MeshData& data) {
return maxOffset - minOffset <= stride;
}
Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {
/* If there are no attributes, bail -- return an empty mesh with desired
vertex count but nothing else */
if(!data.attributeCount() && extra.empty())
return Trade::MeshData{data.primitive(), vertexCount};
const bool interleaved = isInterleaved(data);
/* If the mesh is already interleaved, use the original stride to
preserve all padding, but remove the initial offset. Otherwise calculate
a tightly-packed stride. */
std::size_t stride;
std::size_t minOffset;
if(interleaved && data.attributeCount()) {
stride = data.attributeStride(0);
minOffset = ~std::size_t{};
for(UnsignedInt i = 0, max = data.attributeCount(); i != max; ++i)
minOffset = Math::min(minOffset, data.attributeOffset(i));
} else {
stride = 0;
minOffset = 0;
for(UnsignedInt i = 0, max = data.attributeCount(); i != max; ++i)
stride += vertexFormatSize(data.attributeFormat(i));
}
/* Add the extra attributes and explicit padding */
std::size_t extraAttributeCount = 0;
for(std::size_t i = 0; i != extra.size(); ++i) {
if(extra[i].format() == VertexFormat{}) {
CORRADE_ASSERT(extra[i].data().stride() > 0 || stride >= std::size_t(-extra[i].data().stride()),
"MeshTools::interleavedLayout(): negative padding" << extra[i].data().stride() << "in extra attribute" << i << "too large for stride" << stride, (Trade::MeshData{MeshPrimitive::Points, 0}));
stride += extra[i].data().stride();
} else {
stride += vertexFormatSize(extra[i].format());
++extraAttributeCount;
}
}
/* Allocate new data and attribute array */
Containers::Array<char> vertexData{Containers::NoInit, stride*vertexCount};
Containers::Array<Trade::MeshAttributeData> attributeData{data.attributeCount() + extraAttributeCount};
/* Copy existing attribute layout. If the original is already interleaved,
preserve relative attribute offsets, otherwise pack tightly. */
std::size_t offset = 0;
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(interleaved) offset = data.attributeOffset(i) - minOffset;
attributeData[i] = Trade::MeshAttributeData{
data.attributeName(i), data.attributeFormat(i),
Containers::StridedArrayView1D<void>{vertexData, vertexData + offset,
vertexCount, std::ptrdiff_t(stride)}};
if(!interleaved) offset += vertexFormatSize(data.attributeFormat(i));
}
/* In case the original is already interleaved, set the offset for extra
attribs to the original stride to preserve also potential padding at the
end. */
if(interleaved && data.attributeCount())
offset = data.attributeStride(0);
/* Mix in the extra attributes */
UnsignedInt attributeIndex = data.attributeCount();
for(UnsignedInt i = 0; i != extra.size(); ++i) {
/* Padding, only adjust the offset for next attribute */
if(extra[i].format() == VertexFormat{}) {
offset += extra[i].data().stride();
continue;
}
attributeData[attributeIndex++] = Trade::MeshAttributeData{
extra[i].name(), extra[i].format(), Containers::StridedArrayView1D<void>{vertexData, vertexData + offset,
vertexCount, std::ptrdiff_t(stride)}};
offset += vertexFormatSize(extra[i].format());
}
return Trade::MeshData{data.primitive(), std::move(vertexData), std::move(attributeData)};
}
Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const std::initializer_list<Trade::MeshAttributeData> extra) {
return interleavedLayout(data, vertexCount, Containers::arrayView(extra));
}
}}

37
src/Magnum/MeshTools/Interleave.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Function @ref Magnum::MeshTools::interleave(), @ref Magnum::MeshTools::interleaveInto(), @ref Magnum::MeshTools::isInterleaved()
* @brief Function @ref Magnum::MeshTools::interleave(), @ref Magnum::MeshTools::interleaveInto(), @ref Magnum::MeshTools::isInterleaved(), @ref Magnum::MeshTools::interleavedLayout()
*/
#include <cstring>
@ -199,6 +199,41 @@ or no attributes.
*/
MAGNUM_MESHTOOLS_EXPORT bool isInterleaved(const Trade::MeshData& data);
/**
@brief Create an interleaved mesh layout
@m_since_latest
Returns a @ref Trade::MeshData instance with its vertex data allocated for
@p vertexCount vertices containing attributes from both @p data and @p extra
interleaved together. No data is actually copied, only an interleaved layout is
created. If @p data is already interleaved, keeps the attributes in the same
layout, potentially extending them with @p extra. The @p extra attributes, if
any, are interleaved together with existing attributes. Returned instance
vertex data flags have both @ref Trade::DataFlag::Mutable and @ref Trade::DataFlag::Owned, so mutable attribute access is guaranteed.
For greater control you can also pass an empty @ref Trade::MeshData instance
and fill @p extra with attributes cherry-picked from
@ref Trade::MeshData::attributeData() of an existing instance. By default the
attributes are tightly packed, you can add arbitrary padding using instances
constructed via @ref Trade::MeshAttributeData::MeshAttributeData(Int).
Example:
@snippet MagnumMeshTools.cpp interleavedLayout-extra
This function doesn't preserve index data information in any way, making the
output non-indexed. If you want to preserve index data, create a new indexed
instance with attribute and vertex data transferred from the returned instance:
@snippet MagnumMeshTools.cpp interleavedLayout-indices
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& data, UnsignedInt vertexCount, Containers::ArrayView<const Trade::MeshAttributeData> extra = {});
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& data, UnsignedInt vertexCount, std::initializer_list<Trade::MeshAttributeData> extra);
}}
#endif

2
src/Magnum/MeshTools/Test/CMakeLists.txt

@ -28,7 +28,7 @@ corrade_add_test(MeshToolsCompressIndicesTest CompressIndicesTest.cpp LIBRARIES
corrade_add_test(MeshToolsDuplicateTest DuplicateTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsFlipNormalsTest FlipNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsGenerateNormalsTest GenerateNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib MagnumPrimitives)
corrade_add_test(MeshToolsInterleaveTest InterleaveTest.cpp LIBRARIES MagnumMeshTools)
corrade_add_test(MeshToolsInterleaveTest InterleaveTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsRemoveDuplicatesTest RemoveDuplicatesTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsSubdivideTest SubdivideTest.cpp LIBRARIES Magnum)
corrade_add_test(MeshToolsTipsifyTest TipsifyTest.cpp LIBRARIES MagnumMeshTools)

283
src/Magnum/MeshTools/Test/InterleaveTest.cpp

@ -55,6 +55,16 @@ struct InterleaveTest: Corrade::TestSuite::Tester {
void isInterleavedAliased();
void isInterleavedUnordered();
void isInterleavedAttributeAcrossStride();
void interleavedLayout();
void interleavedLayoutExtra();
void interleavedLayoutExtraAliased();
void interleavedLayoutExtraTooNegativePadding();
void interleavedLayoutExtraOnly();
void interleavedLayoutAlreadyInterleaved();
void interleavedLayoutAlreadyInterleavedAliased();
void interleavedLayoutAlreadyInterleavedExtra();
void interleavedLayoutNothing();
};
InterleaveTest::InterleaveTest() {
@ -73,7 +83,17 @@ InterleaveTest::InterleaveTest() {
&InterleaveTest::isInterleavedGaps,
&InterleaveTest::isInterleavedAliased,
&InterleaveTest::isInterleavedUnordered,
&InterleaveTest::isInterleavedAttributeAcrossStride});
&InterleaveTest::isInterleavedAttributeAcrossStride,
&InterleaveTest::interleavedLayout,
&InterleaveTest::interleavedLayoutExtra,
&InterleaveTest::interleavedLayoutExtraAliased,
&InterleaveTest::interleavedLayoutExtraTooNegativePadding,
&InterleaveTest::interleavedLayoutExtraOnly,
&InterleaveTest::interleavedLayoutAlreadyInterleaved,
&InterleaveTest::interleavedLayoutAlreadyInterleavedAliased,
&InterleaveTest::interleavedLayoutAlreadyInterleavedExtra,
&InterleaveTest::interleavedLayoutNothing});
}
void InterleaveTest::attributeCount() {
@ -285,6 +305,267 @@ void InterleaveTest::isInterleavedAttributeAcrossStride() {
CORRADE_VERIFY(!MeshTools::isInterleaved(data2));
}
void InterleaveTest::interleavedLayout() {
Containers::Array<char> indexData{6};
Containers::Array<char> vertexData{3*20};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::arrayCast<Vector2>(vertexData.prefix(3*8))};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::arrayCast<Vector3>(vertexData.suffix(3*8))};
Trade::MeshIndexData indices{Containers::arrayCast<UnsignedShort>(indexData)};
Trade::MeshData data{MeshPrimitive::TriangleFan,
std::move(indexData), indices,
std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(!MeshTools::isInterleaved(data));
Trade::MeshData layout = MeshTools::interleavedLayout(data, 10);
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.primitive(), MeshPrimitive::TriangleFan);
CORRADE_VERIFY(!layout.isIndexed()); /* Indices are not preserved */
CORRADE_COMPARE(layout.attributeCount(), 2);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeStride(0), 20);
CORRADE_COMPARE(layout.attributeStride(1), 20);
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 8);
CORRADE_COMPARE(layout.vertexCount(), 10);
/* Needs to be like this so we can modify the data */
CORRADE_COMPARE(layout.vertexDataFlags(), Trade::DataFlag::Mutable|Trade::DataFlag::Owned);
CORRADE_VERIFY(layout.vertexData());
CORRADE_COMPARE(layout.vertexData().size(), 10*20);
}
void InterleaveTest::interleavedLayoutExtra() {
Containers::Array<char> vertexData{3*20};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::arrayCast<Vector2>(vertexData.prefix(3*8))};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::arrayCast<Vector3>(vertexData.suffix(3*8))};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(!MeshTools::isInterleaved(data));
Trade::MeshData layout = MeshTools::interleavedLayout(data, 7, {
Trade::MeshAttributeData{1},
Trade::MeshAttributeData{Trade::meshAttributeCustom(15),
VertexFormat::UnsignedShort, nullptr},
Trade::MeshAttributeData{1},
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{4}
});
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.attributeCount(), 4);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeName(2), Trade::meshAttributeCustom(15));
CORRADE_COMPARE(layout.attributeName(3), Trade::MeshAttribute::Color);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeFormat(2), VertexFormat::UnsignedShort);
CORRADE_COMPARE(layout.attributeFormat(3), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeStride(0), 40);
CORRADE_COMPARE(layout.attributeStride(1), 40);
CORRADE_COMPARE(layout.attributeStride(2), 40);
CORRADE_COMPARE(layout.attributeStride(3), 40);
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 8);
CORRADE_COMPARE(layout.attributeOffset(2), 21);
CORRADE_COMPARE(layout.attributeOffset(3), 24);
CORRADE_COMPARE(layout.vertexCount(), 7);
CORRADE_COMPARE(layout.vertexData().size(), 7*40);
}
void InterleaveTest::interleavedLayoutExtraAliased() {
Containers::Array<char> vertexData{3*12};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData, reinterpret_cast<Vector2*>(vertexData.data()), 3, 12}};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(vertexData), {positions}};
Trade::MeshData layout = MeshTools::interleavedLayout(data, 100, {
/* Normals at the same place as positions */
Trade::MeshAttributeData{-12},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
VertexFormat::Vector3, positions.data()}
});
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.attributeCount(), 2);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeStride(0), 12);
CORRADE_COMPARE(layout.attributeStride(1), 12);
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 0); /* aliases */
CORRADE_COMPARE(layout.vertexCount(), 100);
CORRADE_COMPARE(layout.vertexData().size(), 100*12);
}
void InterleaveTest::interleavedLayoutExtraTooNegativePadding() {
Containers::Array<char> vertexData{3*12};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData, reinterpret_cast<Vector2*>(vertexData.data()), 3, 12}};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(vertexData), {positions}};
std::ostringstream out;
Error redirectError{&out};
MeshTools::interleavedLayout(data, 100, {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
VertexFormat::Vector3, positions.data()},
Trade::MeshAttributeData{-25}
});
CORRADE_COMPARE(out.str(), "MeshTools::interleavedLayout(): negative padding -25 in extra attribute 1 too large for stride 24\n");
}
void InterleaveTest::interleavedLayoutExtraOnly() {
Trade::MeshData data{MeshPrimitive::Triangles, 0};
Trade::MeshData layout = MeshTools::interleavedLayout(data, 10, {
Trade::MeshAttributeData{4},
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
VertexFormat::Vector2, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
VertexFormat::Vector3, nullptr}
});
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.attributeCount(), 2);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeStride(0), 24);
CORRADE_COMPARE(layout.attributeStride(1), 24);
CORRADE_COMPARE(layout.attributeOffset(0), 4);
CORRADE_COMPARE(layout.attributeOffset(1), 12);
CORRADE_COMPARE(layout.vertexCount(), 10);
CORRADE_COMPARE(layout.vertexData().size(), 10*24);
}
void InterleaveTest::interleavedLayoutAlreadyInterleaved() {
Containers::Array<char> indexData{6};
/* Test also removing the initial offset */
Containers::Array<char> vertexData{100 + 3*24};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData, reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 24}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::StridedArrayView1D<Vector3>{vertexData, reinterpret_cast<Vector3*>(vertexData.data() + 100 + 10), 3, 24}};
Trade::MeshIndexData indices{Containers::arrayCast<UnsignedShort>(indexData)};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(indexData), indices,
std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Trade::MeshData layout = MeshTools::interleavedLayout(data, 10);
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_VERIFY(!layout.isIndexed()); /* Indices are not preserved */
CORRADE_COMPARE(layout.attributeCount(), 2);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
/* Original stride should be preserved */
CORRADE_COMPARE(layout.attributeStride(0), 24);
CORRADE_COMPARE(layout.attributeStride(1), 24);
/* Relative offsets should be preserved, but the initial one removed */
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 10);
CORRADE_COMPARE(layout.vertexCount(), 10);
CORRADE_COMPARE(layout.vertexData().size(), 10*24);
}
void InterleaveTest::interleavedLayoutAlreadyInterleavedAliased() {
Containers::Array<char> indexData{6};
Containers::Array<char> vertexData{3*12};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData, reinterpret_cast<Vector2*>(vertexData.data()), 3, 12}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::StridedArrayView1D<Vector3>{vertexData, reinterpret_cast<Vector3*>(vertexData.data()), 3, 12}};
Trade::MeshIndexData indices{Containers::arrayCast<UnsignedShort>(indexData)};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(indexData), indices,
std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Trade::MeshData layout = MeshTools::interleavedLayout(data, 10);
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_VERIFY(!layout.isIndexed()); /* Indices are not preserved */
CORRADE_COMPARE(layout.attributeCount(), 2);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeStride(0), 12);
CORRADE_COMPARE(layout.attributeStride(1), 12);
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 0); /* aliases */
CORRADE_COMPARE(layout.vertexCount(), 10);
CORRADE_COMPARE(layout.vertexData().size(), 10*12);
}
void InterleaveTest::interleavedLayoutAlreadyInterleavedExtra() {
Containers::Array<char> vertexData{100 + 3*24};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData, reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 24}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::StridedArrayView1D<Vector3>{vertexData, reinterpret_cast<Vector3*>(vertexData.data() + 100 + 10), 3, 24}};
Trade::MeshData data{MeshPrimitive::Triangles,
std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Trade::MeshData layout = MeshTools::interleavedLayout(data, 10, {
Trade::MeshAttributeData{1},
Trade::MeshAttributeData{Trade::meshAttributeCustom(15),
VertexFormat::UnsignedShort, nullptr},
Trade::MeshAttributeData{1},
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{4}
});
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.attributeCount(), 4);
CORRADE_COMPARE(layout.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(layout.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(layout.attributeName(2), Trade::meshAttributeCustom(15));
CORRADE_COMPARE(layout.attributeName(3), Trade::MeshAttribute::Color);
CORRADE_COMPARE(layout.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(layout.attributeFormat(1), VertexFormat::Vector3);
CORRADE_COMPARE(layout.attributeFormat(2), VertexFormat::UnsignedShort);
CORRADE_COMPARE(layout.attributeFormat(3), VertexFormat::Vector3);
/* Original stride should be preserved, with stride from extra attribs
added */
CORRADE_COMPARE(layout.attributeStride(0), 24 + 20);
CORRADE_COMPARE(layout.attributeStride(1), 24 + 20);
CORRADE_COMPARE(layout.attributeStride(2), 24 + 20);
CORRADE_COMPARE(layout.attributeStride(3), 24 + 20);
/* Relative offsets should be preserved, but the initial one removed */
CORRADE_COMPARE(layout.attributeOffset(0), 0);
CORRADE_COMPARE(layout.attributeOffset(1), 10);
CORRADE_COMPARE(layout.attributeOffset(2), 25);
CORRADE_COMPARE(layout.attributeOffset(3), 28);
CORRADE_COMPARE(layout.vertexCount(), 10);
CORRADE_COMPARE(layout.vertexData().size(), 10*44);
}
void InterleaveTest::interleavedLayoutNothing() {
Trade::MeshData layout = MeshTools::interleavedLayout(Trade::MeshData{MeshPrimitive::Points, 25}, 10);
CORRADE_VERIFY(MeshTools::isInterleaved(layout));
CORRADE_COMPARE(layout.attributeCount(), 0);
CORRADE_COMPARE(layout.vertexCount(), 10);
CORRADE_VERIFY(!layout.vertexData());
CORRADE_COMPARE(layout.vertexData().size(), 0);
}
}}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::InterleaveTest)

Loading…
Cancel
Save