Browse Source

MeshTools: new interleavedData() utility.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
9a6ef0a220
  1. 5
      doc/changelog.dox
  2. 40
      src/Magnum/MeshTools/Interleave.cpp
  3. 14
      src/Magnum/MeshTools/Interleave.h
  4. 80
      src/Magnum/MeshTools/Test/InterleaveTest.cpp

5
doc/changelog.dox

@ -116,8 +116,9 @@ See also:
- Added @ref MeshTools::compile(const Trade::MeshData&) operating on the new
@ref Trade::MeshData API
- New @ref MeshTools::isInterleaved() utility for checking if
@ref Trade::MeshData is interleaved
- New @ref MeshTools::isInterleaved() and @ref MeshTools::interleavedData()
utilities for checking if @ref Trade::MeshData is interleaved and for
getting an interleaved view
- Added @ref MeshTools::interleavedLayout() for convenient creation of an
interleaved mesh layout using the new @ref Trade::MeshData API
- Added @ref MeshTools::interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>),

40
src/Magnum/MeshTools/Interleave.cpp

@ -32,23 +32,47 @@
namespace Magnum { namespace MeshTools {
bool isInterleaved(const Trade::MeshData& data) {
/* There is nothing, so yes it is (because there is nothing we could do
to make it interleaved anyway) */
if(!data.attributeCount()) return true;
namespace {
Containers::StridedArrayView2D<const char> interleavedDataInternal(const Trade::MeshData& data) {
/* There is no attributes, return a non-nullptr zero-sized view to indicate
a success */
if(!data.attributeCount() || !data.vertexData())
return Containers::StridedArrayView2D<const char>{data.vertexData(), {data.vertexCount(), 0}};
const UnsignedInt stride = data.attributeStride(0);
std::size_t minOffset = data.attributeOffset(0);
std::size_t maxOffset = minOffset;
for(UnsignedInt i = 1; i != data.attributeCount(); ++i) {
if(data.attributeStride(i) != stride) return false;
std::size_t maxOffset = minOffset + vertexFormatSize(data.attributeFormat(0));
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(data.attributeStride(i) != stride) return nullptr;
const std::size_t offset = data.attributeOffset(i);
minOffset = Math::min(minOffset, offset);
maxOffset = Math::max(maxOffset, offset + vertexFormatSize(data.attributeFormat(i)));
}
return maxOffset - minOffset <= stride;
/* The offsets can't fit into the stride, report failure */
if(maxOffset - minOffset > stride) return nullptr;
return Containers::StridedArrayView2D<const char>{
data.vertexData(), data.vertexData().data() + minOffset,
{data.vertexCount(), maxOffset - minOffset},
{std::ptrdiff_t(stride), 1}};
}
}
bool isInterleaved(const Trade::MeshData& data) {
/* If a nullptr value is returned but the mesh vertex data is not nullptr,
the mesh is not interleaved. Otherwise it is */
return !!interleavedDataInternal(data).data() == !!data.vertexData().data();
}
Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& data) {
auto out = interleavedDataInternal(data);
CORRADE_ASSERT(out || !data.vertexData(),
"MeshTools::interleavedData(): the mesh is not interleaved", {});
return out;
}
Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {

14
src/Magnum/MeshTools/Interleave.h

@ -196,10 +196,22 @@ between minimal and maximal offset is not larger than the stride, @cpp false @ce
otherwise. In particular, returns @cpp true @ce also if the mesh has just one
or no attributes.
@see @ref Trade::MeshData::attributeStride(),
@ref Trade::MeshData::attributeOffset()
@ref Trade::MeshData::attributeOffset(), @ref interleavedData()
*/
MAGNUM_MESHTOOLS_EXPORT bool isInterleaved(const Trade::MeshData& data);
/**
@brief Type-erased view on interleaved mesh data
@m_since_latest
Returns a 2D view on @ref Trade::MeshData::vertexData() that spans all
interleaved attributes, with the first dimension being the vertex count and the
second being the attribute stride that's common for all attributes. Expects
that the mesh is interleaved.
@see @ref isInterleaved()
*/
MAGNUM_MESHTOOLS_EXPORT Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& data);
/**
@brief Create an interleaved mesh layout
@m_since_latest

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

@ -58,6 +58,11 @@ struct InterleaveTest: Corrade::TestSuite::Tester {
void isInterleavedUnordered();
void isInterleavedAttributeAcrossStride();
void interleavedData();
void interleavedDataNoAttributes();
void interleavedDataNoVertices();
void interleavedDataNotInterleaved();
void interleavedLayout();
void interleavedLayoutExtra();
void interleavedLayoutExtraAliased();
@ -100,6 +105,11 @@ InterleaveTest::InterleaveTest() {
&InterleaveTest::isInterleavedUnordered,
&InterleaveTest::isInterleavedAttributeAcrossStride,
&InterleaveTest::interleavedData,
&InterleaveTest::interleavedDataNoAttributes,
&InterleaveTest::interleavedDataNoVertices,
&InterleaveTest::interleavedDataNotInterleaved,
&InterleaveTest::interleavedLayout,
&InterleaveTest::interleavedLayoutExtra,
&InterleaveTest::interleavedLayoutExtraAliased,
@ -337,6 +347,76 @@ void InterleaveTest::isInterleavedAttributeAcrossStride() {
CORRADE_VERIFY(!MeshTools::isInterleaved(data2));
}
void InterleaveTest::interleavedData() {
Containers::Array<char> vertexData{100 + 3*40};
Containers::StridedArrayView1D<Vector3> normals{vertexData,
reinterpret_cast<Vector3*>(vertexData.data() + 100 + 24), 3, 40};
Containers::StridedArrayView1D<Vector2> positions{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + 100 + 5), 3, 40};
Trade::MeshData data{MeshPrimitive::Triangles, std::move(vertexData), {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normals},
Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}
}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Containers::StridedArrayView2D<const char> interleaved = MeshTools::interleavedData(data);
CORRADE_COMPARE(interleaved.data(), positions.data());
CORRADE_COMPARE(interleaved.size()[0], 3);
CORRADE_COMPARE(interleaved.size()[1], 31);
CORRADE_COMPARE(interleaved.stride()[0], 40);
CORRADE_COMPARE(interleaved.stride()[1], 1);
}
void InterleaveTest::interleavedDataNoAttributes() {
char a[1];
Trade::MeshData data{MeshPrimitive::Lines, {}, a, {}, 15};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Containers::StridedArrayView2D<const char> interleaved = MeshTools::interleavedData(data);
CORRADE_COMPARE(interleaved.data(), static_cast<void*>(a));
CORRADE_COMPARE(interleaved.size()[0], 15);
CORRADE_COMPARE(interleaved.size()[1], 0);
CORRADE_COMPARE(interleaved.stride()[0], 0);
CORRADE_COMPARE(interleaved.stride()[1], 1);
}
void InterleaveTest::interleavedDataNoVertices() {
struct Vertex {
Vector3 normal;
Vector3 position;
};
Vertex a[1];
Trade::MeshData data{MeshPrimitive::Triangles, {}, a, {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
Containers::stridedArrayView(a, &a[0].normal, 0, sizeof(Vertex))},
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
Containers::stridedArrayView(a, &a[0].position, 0, sizeof(Vertex))}
}};
CORRADE_VERIFY(MeshTools::isInterleaved(data));
Containers::StridedArrayView2D<const char> interleaved = MeshTools::interleavedData(data);
CORRADE_COMPARE(interleaved.data(), static_cast<void*>(a));
CORRADE_COMPARE(interleaved.size()[0], 0);
CORRADE_COMPARE(interleaved.size()[1], sizeof(Vertex));
CORRADE_COMPARE(interleaved.stride()[0], sizeof(Vertex));
CORRADE_COMPARE(interleaved.stride()[1], 1);
}
void InterleaveTest::interleavedDataNotInterleaved() {
Containers::Array<char> vertexData{100 + 3*20};
Trade::MeshAttributeData positions{Trade::MeshAttribute::Position,
Containers::arrayCast<Vector2>(vertexData.suffix(100).prefix(3*8))};
Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal,
Containers::arrayCast<Vector3>(vertexData.suffix(100).suffix(3*8))};
Trade::MeshData data{MeshPrimitive::Triangles, std::move(vertexData), {positions, normals}};
std::ostringstream out;
Error redirectError{&out};
MeshTools::interleavedData(data);
CORRADE_COMPARE(out.str(), "MeshTools::interleavedData(): the mesh is not interleaved\n");
}
void InterleaveTest::interleavedLayout() {
Containers::Array<char> indexData{6};
Containers::Array<char> vertexData{3*20};

Loading…
Cancel
Save