Browse Source

MeshTools: isInterleaved() and interleavedData() work with custom formats.

The interleavedLayout() etc don't yet (those need to explicitly assert),
added a TODO there.
pull/449/head
Vladimír Vondruš 6 years ago
parent
commit
101e8fd11b
  1. 24
      src/Magnum/MeshTools/Interleave.cpp
  2. 98
      src/Magnum/MeshTools/Test/InterleaveTest.cpp

24
src/Magnum/MeshTools/Interleave.cpp

@ -50,14 +50,32 @@ Containers::Optional<Containers::StridedArrayView2D<const char>> interleavedData
const UnsignedInt stride = data.attributeStride(0);
std::size_t minOffset = ~std::size_t{};
std::size_t maxOffset = 0;
bool hasImplementationSpecificVertexFormat = false;
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(data.attributeStride(i) != stride) return Containers::NullOpt;
const std::size_t offset = data.attributeOffset(i);
minOffset = Math::min(minOffset, offset);
maxOffset = Math::max(maxOffset, offset + attributeSize(data, i));
/* If the attribute has implementation-specific format, remember that
for later and optimistically use size of 1 byte for calculations */
std::size_t size;
if(isVertexFormatImplementationSpecific(data.attributeFormat(i))) {
hasImplementationSpecificVertexFormat = true;
size = 1;
} else size = attributeSize(data, i);
maxOffset = Math::max(maxOffset, offset + size);
}
/* If there's an attribute with implementation-specific format,
conservatively use the whole stride for it. This should work for
majority of cases except when the stride has a padding at the end and
the padding isn't included in the vertexData array for the last vertex,
but that'd probably blow up in many other cases (and drivers) as well. */
if(hasImplementationSpecificVertexFormat)
maxOffset = Math::max(maxOffset, minOffset + stride);
/* The offsets can't fit into the stride, report failure */
if(maxOffset - minOffset > stride) return Containers::NullOpt;
@ -110,6 +128,9 @@ Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&&
} else {
stride = 0;
minOffset = 0;
/** @todo explitily assert on impl-specific vertex formats here --
however it should work when the original is already interleaved and
nothing in extras is impl-specific */
for(UnsignedInt i = 0, max = data.attributeCount(); i != max; ++i)
stride += attributeSize(data, i);
}
@ -122,6 +143,7 @@ Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&&
"MeshTools::interleavedLayout(): negative padding" << extra[i].stride() << "in extra attribute" << i << "too large for stride" << stride, {});
stride += extra[i].stride();
} else {
/** @todo explitily assert on impl-specific vertex formats here */
stride += attributeSize(extra[i]);
++extraAttributeCount;
}

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

@ -60,6 +60,7 @@ struct InterleaveTest: Corrade::TestSuite::Tester {
void isInterleavedUnordered();
void isInterleavedAttributeAcrossStride();
void isInterleavedVertexDataWholeMemory();
void isInterleavedImplementationSpecificVertexFormat();
void interleavedData();
void interleavedDataArrayAttributes();
@ -68,6 +69,7 @@ struct InterleaveTest: Corrade::TestSuite::Tester {
void interleavedDataNotInterleaved();
void interleavedDataVertexDataWholeMemory();
void interleavedMutableDataNotMutable();
void interleavedDataImplementationSpecificVertexFormat();
void interleavedLayout();
void interleavedLayoutExtra();
@ -112,6 +114,7 @@ InterleaveTest::InterleaveTest() {
&InterleaveTest::isInterleavedUnordered,
&InterleaveTest::isInterleavedAttributeAcrossStride,
&InterleaveTest::isInterleavedVertexDataWholeMemory,
&InterleaveTest::isInterleavedImplementationSpecificVertexFormat,
&InterleaveTest::interleavedData,
&InterleaveTest::interleavedDataArrayAttributes,
@ -120,6 +123,7 @@ InterleaveTest::InterleaveTest() {
&InterleaveTest::interleavedDataNotInterleaved,
&InterleaveTest::interleavedDataVertexDataWholeMemory,
&InterleaveTest::interleavedMutableDataNotMutable,
&InterleaveTest::interleavedDataImplementationSpecificVertexFormat,
&InterleaveTest::interleavedLayout,
&InterleaveTest::interleavedLayoutExtra,
@ -383,6 +387,63 @@ void InterleaveTest::isInterleavedVertexDataWholeMemory() {
CORRADE_VERIFY(MeshTools::isInterleaved(data));
}
void InterleaveTest::isInterleavedImplementationSpecificVertexFormat() {
/* Interleaved; fits into one byte at the end of stride */
{
Containers::Array<char> vertexData{100 + 3*9};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 9}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
vertexFormatWrap(0x1234),
Containers::StridedArrayView1D<char>{vertexData,
vertexData.data() + 100 + 8, 3, 9}};
/* The result should be independent on the order of calculations */
Trade::MeshData data{MeshPrimitive::Triangles, {}, vertexData,
{positions, normals}};
Trade::MeshData dataDifferentOrder{MeshPrimitive::Triangles, {}, vertexData,
{normals, positions}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
CORRADE_VERIFY(MeshTools::isInterleaved(dataDifferentOrder));
}
/* Doesn't have even one byte of space in the stride, invalid */
{
Containers::Array<char> vertexData{100 + 3*8};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 8}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
vertexFormatWrap(0x1234),
Containers::StridedArrayView1D<char>{vertexData,
vertexData.data() + 100 + 8, 3, 8}};
Trade::MeshData data{MeshPrimitive::Triangles, std::move(vertexData), {positions, normals}};
CORRADE_VERIFY(!MeshTools::isInterleaved(data));
}
/* A non-interleaved (or not?) attribute with a implementation-specific
format after interleaved ones is also invalid */
{
Containers::Array<char> vertexData{100 + 3*20 + 3};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 20}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::StridedArrayView1D<Vector3>{vertexData,
reinterpret_cast<Vector3*>(vertexData.data() + 100 + 8), 3, 20}};
Trade::MeshAttributeData extra{Trade::meshAttributeCustom(1234),
vertexFormatWrap(0x1234),
Containers::StridedArrayView1D<char>{vertexData,
vertexData.data() + 100 + 3*20, 3, 1}};
Trade::MeshData data{MeshPrimitive::Triangles, {}, vertexData,
{positions, normals, extra}};
CORRADE_VERIFY(!MeshTools::isInterleaved(data));
}
}
void InterleaveTest::interleavedData() {
Containers::Array<char> vertexData{100 + 3*40};
Containers::StridedArrayView1D<Vector3> normals{vertexData,
@ -543,6 +604,43 @@ void InterleaveTest::interleavedMutableDataNotMutable() {
CORRADE_COMPARE(out.str(), "MeshTools::interleavedMutableData(): vertex data is not mutable\n");
}
void InterleaveTest::interleavedDataImplementationSpecificVertexFormat() {
Containers::Array<char> vertexData{100 + 3*50};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::StridedArrayView1D<Vector2>{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + 100), 3, 50}};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
vertexFormatWrap(0x1234),
Containers::StridedArrayView1D<char>{vertexData,
vertexData.data() + 100 + 8, 3, 50}};
{
Trade::MeshData data{MeshPrimitive::Triangles, {}, vertexData,
{positions, normals}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Containers::StridedArrayView2D<const char> interleaved = MeshTools::interleavedData(data);
CORRADE_COMPARE(interleaved.data(), positions.data().data());
CORRADE_COMPARE(interleaved.size()[0], 3);
/* The implementation-specific format is conservatively assumed to
occupy the whole stride (even if may be is excessive) */
CORRADE_COMPARE(interleaved.size()[1], 50);
CORRADE_COMPARE(interleaved.stride()[0], 50);
CORRADE_COMPARE(interleaved.stride()[1], 1);
/* The result should be the same independent on the order of attributes */
} {
Trade::MeshData data{MeshPrimitive::Triangles, {}, vertexData,
{normals, positions}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Containers::StridedArrayView2D<const char> interleaved = MeshTools::interleavedData(data);
CORRADE_COMPARE(interleaved.data(), positions.data().data());
CORRADE_COMPARE(interleaved.size()[0], 3);
CORRADE_COMPARE(interleaved.size()[1], 50);
CORRADE_COMPARE(interleaved.stride()[0], 50);
CORRADE_COMPARE(interleaved.stride()[1], 1);
}
}
void InterleaveTest::interleavedLayout() {
Containers::Array<char> indexData{6};
Containers::Array<char> vertexData{3*24};

Loading…
Cancel
Save