Browse Source

MeshTools: implement compressIndices() taking a MeshData.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
5481581c5e
  1. 5
      doc/changelog.dox
  2. 55
      src/Magnum/MeshTools/CompressIndices.cpp
  3. 25
      src/Magnum/MeshTools/CompressIndices.h
  4. 94
      src/Magnum/MeshTools/Test/CompressIndicesTest.cpp

5
doc/changelog.dox

@ -115,8 +115,9 @@ See also:
@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::interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>)
and @ref MeshTools::duplicate(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>)
- Added @ref MeshTools::interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>),
@ref MeshTools::duplicate(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>)
and @ref MeshTools::compressIndices(const Trade::MeshData&, MeshIndexType)
that work directly on the new @ref Trade::MeshData API
- Added @ref MeshTools::subdivideInPlace() for allocation-less mesh
subdivision

55
src/Magnum/MeshTools/CompressIndices.cpp

@ -28,8 +28,10 @@
#include <cstring>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/FunctionsBatch.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace MeshTools {
@ -115,6 +117,59 @@ std::pair<Containers::Array<char>, MeshIndexType> compressIndices(const Containe
return compressIndices(indices, MeshIndexType::UnsignedShort, offset);
}
Trade::MeshData compressIndices(Trade::MeshData&& data, MeshIndexType atLeast) {
CORRADE_ASSERT(data.isIndexed(), "MeshTools::compressIndices(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
/* Transfer vertex data as-is, as those don't need any changes. Release if
possible. */
Containers::Array<char> vertexData;
const UnsignedInt vertexCount = data.vertexCount();
if(data.vertexDataFlags() & Trade::DataFlag::Owned)
vertexData = data.releaseVertexData();
else {
vertexData = Containers::Array<char>{Containers::NoInit, data.vertexData().size()};
Utility::copy(data.vertexData(), vertexData);
}
/* Compress the indices */
UnsignedInt offset;
std::pair<Containers::Array<char>, MeshIndexType> result;
if(data.indexType() == MeshIndexType::UnsignedInt) {
auto indices = data.indices<UnsignedInt>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedInt>(indices, atLeast, offset);
} else if(data.indexType() == MeshIndexType::UnsignedShort) {
auto indices = data.indices<UnsignedShort>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedShort>(indices, atLeast, offset);
} else {
CORRADE_INTERNAL_ASSERT(data.indexType() == MeshIndexType::UnsignedByte);
auto indices = data.indices<UnsignedByte>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedByte>(indices, atLeast, offset);
}
/* Recreate the attribute array */
const UnsignedInt newVertexCount = vertexCount - offset;
Containers::Array<Trade::MeshAttributeData> attributeData{data.attributeCount()};
for(UnsignedInt i = 0, max = attributeData.size(); i != max; ++i) {
const UnsignedInt stride = data.attributeStride(i);
attributeData[i] = Trade::MeshAttributeData{data.attributeName(i),
data.attributeFormat(i),
Containers::StridedArrayView1D<const void>{vertexData, vertexData.data() + data.attributeOffset(i) + offset*stride, newVertexCount, stride}};
}
Trade::MeshIndexData indices{result.second, result.first};
return Trade::MeshData{data.primitive(), std::move(result.first), indices,
std::move(vertexData), std::move(attributeData)};
}
Trade::MeshData compressIndices(const Trade::MeshData& data, MeshIndexType atLeast) {
return compressIndices(Trade::MeshData{data.primitive(),
{}, data.indexData(), Trade::MeshIndexData{data.indices()},
{}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData())}, atLeast);
}
#ifdef MAGNUM_BUILD_DEPRECATED
std::tuple<Containers::Array<char>, MeshIndexType, UnsignedInt, UnsignedInt> compressIndices(const std::vector<UnsignedInt>& indices) {
const auto minmax = Math::minmax(indices);

25
src/Magnum/MeshTools/CompressIndices.h

@ -35,6 +35,7 @@
#include "Magnum/Mesh.h"
#include "Magnum/MeshTools/visibility.h"
#include "Magnum/Trade/Trade.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <tuple>
@ -136,6 +137,30 @@ with @p atLeast set to @ref MeshIndexType::UnsignedShort.
*/
MAGNUM_MESHTOOLS_EXPORT std::pair<Containers::Array<char>, MeshIndexType> compressIndices(const Containers::StridedArrayView2D<const char>& indices, Long offset);
/**
@brief Compress mesh data indices
@m_since_latest
Does the same as @ref compressIndices(const Containers::StridedArrayView2D<const char>&, MeshIndexType, Long),
but together with adjusting vertex attribute offsets in the passed
@ref Trade::MeshData instance. This function will unconditionally make a copy
of all vertex data, use @ref compressIndices(Trade::MeshData&&, MeshIndexType)
to avoid that copy.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(const Trade::MeshData& data, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
/**
@brief Compress mesh data indices
@m_since_latest
Compared to @ref compressIndices(const Trade::MeshData&, MeshIndexType) this
function can transfer ownership of @p data vertex buffer (in case it is
owned) to the returned instance instead of making a copy of it. Index and
attribute data are copied always.
@see @ref Trade::MeshData::vertexDataFlags()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(Trade::MeshData&& data, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Compress vertex indices

94
src/Magnum/MeshTools/Test/CompressIndicesTest.cpp

@ -32,8 +32,9 @@
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Endianness.h>
#include "Magnum/Math/TypeTraits.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/MeshTools/CompressIndices.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace MeshTools { namespace Test { namespace {
@ -53,6 +54,10 @@ struct CompressIndicesTest: TestSuite::Tester {
void compressDeprecated();
#endif
template<class T> void compressMeshData();
void compressMeshDataMove();
void compressMeshDataNonIndexed();
void compressAsShort();
};
@ -70,11 +75,16 @@ CompressIndicesTest::CompressIndicesTest() {
&CompressIndicesTest::compressOffsetNegative<UnsignedInt>,
&CompressIndicesTest::compressErasedNonContiguous,
&CompressIndicesTest::compressErasedWrongIndexSize,
#ifdef MAGNUM_BUILD_DEPRECATED
&CompressIndicesTest::compressDeprecated,
#endif
&CompressIndicesTest::compressMeshData<UnsignedByte>,
&CompressIndicesTest::compressMeshData<UnsignedShort>,
&CompressIndicesTest::compressMeshData<UnsignedInt>,
&CompressIndicesTest::compressMeshDataMove,
&CompressIndicesTest::compressMeshDataNonIndexed,
&CompressIndicesTest::compressAsShort});
}
@ -228,6 +238,86 @@ void CompressIndicesTest::compressDeprecated() {
}
#endif
template<class T> void CompressIndicesTest::compressMeshData() {
setTestCaseTemplateName(Math::TypeTraits<T>::name());
struct {
Vector2 positions[103];
Vector3 normals[103];
} vertexData{};
vertexData.positions[100] = {1.3f, 0.3f};
vertexData.positions[101] = {0.87f, 1.1f};
vertexData.positions[102] = {1.0f, -0.5f};
vertexData.normals[100] = Vector3::xAxis();
vertexData.normals[101] = Vector3::yAxis();
vertexData.normals[102] = Vector3::zAxis();
T indices[] = {102, 101, 100, 101, 102};
Trade::MeshData data{MeshPrimitive::TriangleFan,
{}, indices, Trade::MeshIndexData{indices},
{}, Containers::arrayView(&vertexData, 1), {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertexData.positions)},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, Containers::arrayView(vertexData.normals)}
}};
CORRADE_COMPARE(data.vertexCount(), 103);
CORRADE_COMPARE(data.attributeOffset(0), 0);
CORRADE_COMPARE(data.attributeOffset(1), 103*sizeof(Vector2));
Trade::MeshData compressed = compressIndices(data);
CORRADE_COMPARE(compressed.indexCount(), 5);
CORRADE_COMPARE(compressed.indexType(), MeshIndexType::UnsignedShort);
CORRADE_COMPARE_AS(compressed.indices<UnsignedShort>(),
Containers::arrayView<UnsignedShort>({2, 1, 0, 1, 2}),
TestSuite::Compare::Container);
CORRADE_COMPARE(compressed.vertexCount(), 3);
CORRADE_COMPARE(compressed.attributeOffset(0), 100*sizeof(Vector2));
CORRADE_COMPARE(compressed.attributeOffset(1), 103*sizeof(Vector2) + 100*sizeof(Vector3));
CORRADE_COMPARE_AS(compressed.attribute<Vector2>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector2>({{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f}}),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(compressed.attribute<Vector3>(Trade::MeshAttribute::Normal),
Containers::arrayView<Vector3>({Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()}),
TestSuite::Compare::Container);
}
void CompressIndicesTest::compressMeshDataMove() {
Containers::Array<char> vertexData{103*24};
Containers::StridedArrayView1D<Vector2> positionView{vertexData,
reinterpret_cast<Vector2*>(vertexData.data()), 103, 8};
Containers::StridedArrayView1D<Vector3> normalView{vertexData,
reinterpret_cast<Vector3*>(vertexData.data() + 103*sizeof(Vector2)), 103, 12};
UnsignedInt indices[] = {102, 101, 100, 101, 102};
Trade::MeshData data{MeshPrimitive::TriangleFan,
{}, indices, Trade::MeshIndexData{indices},
std::move(vertexData), {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, positionView},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normalView}
}};
CORRADE_COMPARE(data.vertexCount(), 103);
CORRADE_COMPARE(data.attributeOffset(0), 0);
CORRADE_COMPARE(data.attributeOffset(1), 103*sizeof(Vector2));
Trade::MeshData compressed = compressIndices(std::move(data));
CORRADE_COMPARE(compressed.indexCount(), 5);
CORRADE_COMPARE(compressed.indexType(), MeshIndexType::UnsignedShort);
CORRADE_COMPARE_AS(compressed.indices<UnsignedShort>(),
Containers::arrayView<UnsignedShort>({2, 1, 0, 1, 2}),
TestSuite::Compare::Container);
CORRADE_COMPARE(compressed.vertexCount(), 3);
CORRADE_COMPARE(compressed.attributeOffset(0), 100*sizeof(Vector2));
CORRADE_COMPARE(compressed.attributeOffset(1), 103*sizeof(Vector2) + 100*sizeof(Vector3));
/* The vertex data should be moved, not copied */
CORRADE_VERIFY(compressed.vertexData().data() == positionView.data());
}
void CompressIndicesTest::compressMeshDataNonIndexed() {
std::ostringstream out;
Error redirectError{&out};
MeshTools::compressIndices(Trade::MeshData{MeshPrimitive::TriangleFan, 5});
CORRADE_COMPARE(out.str(),
"MeshTools::compressIndices(): mesh data not indexed\n");
}
void CompressIndicesTest::compressAsShort() {
CORRADE_COMPARE_AS(MeshTools::compressIndicesAs<UnsignedShort>({123, 456}),
Containers::arrayView<UnsignedShort>({123, 456}),

Loading…
Cancel
Save