Browse Source

MeshTools: implement duplicate() taking a MeshData.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
e8692af4a6
  1. 3
      doc/changelog.dox
  2. 41
      src/Magnum/MeshTools/Duplicate.cpp
  3. 26
      src/Magnum/MeshTools/Duplicate.h
  4. 156
      src/Magnum/MeshTools/Test/DuplicateTest.cpp

3
doc/changelog.dox

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

41
src/Magnum/MeshTools/Duplicate.cpp

@ -26,6 +26,10 @@
#include "Duplicate.h"
#include <cstring>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace MeshTools {
@ -73,4 +77,41 @@ void duplicateInto(const Containers::StridedArrayView2D<const char>& indices, co
}
}
Trade::MeshData duplicate(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {
CORRADE_ASSERT(data.isIndexed(), "MeshTools::duplicate(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
/* Calculate the layout */
Trade::MeshData layout = interleavedLayout(data, data.indexCount(), extra);
/* Copy existing attributes to new locations */
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
duplicateInto(data.indices(), data.attribute(i), layout.mutableAttribute(i));
/* Mix in the extra attributes */
UnsignedInt attributeIndex = data.attributeCount();
for(UnsignedInt i = 0; i != extra.size(); ++i) {
/* Padding, ignore */
if(extra[i].format() == VertexFormat{}) continue;
/* Copy the attribute in, if it is non-empty, otherwise keep the
memory uninitialized */
if(extra[i].data()) {
CORRADE_ASSERT(extra[i].data().size() == data.vertexCount(),
"MeshTools::duplicate(): extra attribute" << i << "expected to have" << data.vertexCount() << "items but got" << extra[i].data().size(),
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const Containers::StridedArrayView2D<const char> attributeData =
Containers::arrayCast<2, const char>(extra[i].data(), vertexFormatSize(extra[i].format()));
duplicateInto(data.indices(), attributeData, layout.mutableAttribute(attributeIndex));
}
++attributeIndex;
}
return layout;
}
Trade::MeshData duplicate(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttributeData> extra) {
return duplicate(data, Containers::arrayView(extra));
}
}}

26
src/Magnum/MeshTools/Duplicate.h

@ -36,6 +36,7 @@
#include "Magnum/Magnum.h"
#include "Magnum/MeshTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace MeshTools {
@ -126,6 +127,31 @@ etc. overloads.
*/
MAGNUM_MESHTOOLS_EXPORT void duplicateInto(const Containers::StridedArrayView2D<const char>& indices, const Containers::StridedArrayView2D<const char>& data, const Containers::StridedArrayView2D<char>& out);
/**
@brief Duplicate indexed mesh data
@m_since_latest
Returns a copy of @p data that's not indexed and has all attributes interleaved
and duplicated according to @p data's index buffer. The @p extra attributes, if
any, are duplicated and interleaved together with existing attributes (or, in
case the attribute view is empty, only the corresponding space for given
attribute type is reserved, with memory left uninitialized). The data layouting
is done by @ref interleavedLayout(), see its documentation for detailed
behavior description.
Expects that @p data is indexed and each attribute in @p extra has either the
same amount of elements as @p data vertex count (*not* index count) or has
none.
@see @ref Trade::MeshData::attributeData()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttributeData> extra = {});
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttributeData> extra);
template<class IndexType, class T> inline void duplicateInto(const Containers::StridedArrayView1D<const IndexType>& indices, const Containers::StridedArrayView1D<const T>& data, const Containers::StridedArrayView1D<T>& out) {
duplicateInto(indices, Containers::arrayCast<2, const char>(data), Containers::arrayCast<2, char>(out));
}

156
src/Magnum/MeshTools/Test/DuplicateTest.cpp

@ -27,10 +27,13 @@
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Magnum.h"
#include "Magnum/Math/TypeTraits.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/MeshTools/Duplicate.h"
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace MeshTools { namespace Test { namespace {
@ -51,6 +54,13 @@ struct DuplicateTest: TestSuite::Tester {
template<class T> void duplicateErasedIndicesIntoErased();
void duplicateErasedIndicesIntoErasedNonContiguous();
void duplicateErasedIndicesIntoErasedWrongTypeSize();
template<class T> void duplicateMeshData();
void duplicateMeshDataNotIndexed();
void duplicateMeshDataExtra();
void duplicateMeshDataExtraEmpty();
void duplicateMeshDataExtraWrongCount();
void duplicateMeshDataNoAttributes();
};
DuplicateTest::DuplicateTest() {
@ -71,7 +81,16 @@ DuplicateTest::DuplicateTest() {
&DuplicateTest::duplicateErasedIndicesIntoErased<UnsignedShort>,
&DuplicateTest::duplicateErasedIndicesIntoErased<UnsignedInt>,
&DuplicateTest::duplicateErasedIndicesIntoErasedNonContiguous,
&DuplicateTest::duplicateErasedIndicesIntoErasedWrongTypeSize});
&DuplicateTest::duplicateErasedIndicesIntoErasedWrongTypeSize,
&DuplicateTest::duplicateMeshData<UnsignedByte>,
&DuplicateTest::duplicateMeshData<UnsignedShort>,
&DuplicateTest::duplicateMeshData<UnsignedInt>,
&DuplicateTest::duplicateMeshDataNotIndexed,
&DuplicateTest::duplicateMeshDataExtra,
&DuplicateTest::duplicateMeshDataExtraEmpty,
&DuplicateTest::duplicateMeshDataExtraWrongCount,
&DuplicateTest::duplicateMeshDataNoAttributes});
}
void DuplicateTest::duplicate() {
@ -220,6 +239,139 @@ void DuplicateTest::duplicateErasedIndicesIntoErasedNonContiguous() {
"MeshTools::duplicateInto(): second index view dimension is not contiguous\n");
}
template<class T> void DuplicateTest::duplicateMeshData() {
setTestCaseTemplateName(Math::TypeTraits<T>::name());
T indices[]{0, 1, 2, 2, 1, 0};
struct {
Vector2 positions[3];
Vector3 normals[3];
} vertexData{
{{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f}},
{Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()}
};
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)}
}};
Trade::MeshData duplicated = MeshTools::duplicate(data);
CORRADE_VERIFY(MeshTools::isInterleaved(duplicated));
CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::TriangleFan);
CORRADE_VERIFY(!duplicated.isIndexed());
CORRADE_COMPARE(duplicated.vertexCount(), 6);
CORRADE_COMPARE(duplicated.attributeCount(), 2);
CORRADE_COMPARE_AS(duplicated.attribute<Vector2>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector2>({
{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f},
{1.0f, -0.5f}, {0.87f, 1.1f}, {1.3f, 0.3f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(duplicated.attribute<Vector3>(Trade::MeshAttribute::Normal),
Containers::arrayView<Vector3>({
Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(),
Vector3::zAxis(), Vector3::yAxis(), Vector3::xAxis()
}), TestSuite::Compare::Container);
}
void DuplicateTest::duplicateMeshDataNotIndexed() {
std::ostringstream out;
Error redirectError{&out};
MeshTools::duplicate(Trade::MeshData{MeshPrimitive::Points, 0});
CORRADE_COMPARE(out.str(), "MeshTools::duplicate(): mesh data not indexed\n");
}
void DuplicateTest::duplicateMeshDataExtra() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Vector2 positions[]{{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f}};
Trade::MeshData data{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices},
{}, positions, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(positions)}
}};
const Vector3 normals[]{Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()};
Trade::MeshData duplicated = MeshTools::duplicate(data, {
Trade::MeshAttributeData{4},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, Containers::arrayView(normals)}
});
CORRADE_VERIFY(MeshTools::isInterleaved(duplicated));
CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::Lines);
CORRADE_VERIFY(!duplicated.isIndexed());
CORRADE_COMPARE(duplicated.vertexCount(), 6);
CORRADE_COMPARE(duplicated.attributeCount(), 2);
CORRADE_COMPARE_AS(duplicated.attribute<Vector2>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector2>({
{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f},
{1.0f, -0.5f}, {0.87f, 1.1f}, {1.3f, 0.3f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(duplicated.attribute<Vector3>(Trade::MeshAttribute::Normal),
Containers::arrayView<Vector3>({
Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(),
Vector3::zAxis(), Vector3::yAxis(), Vector3::xAxis()
}), TestSuite::Compare::Container);
}
void DuplicateTest::duplicateMeshDataExtraEmpty() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Vector2 positions[]{{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f}};
Trade::MeshData data{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices},
{}, positions, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(positions)}
}};
Trade::MeshData duplicated = MeshTools::duplicate(data, {
Trade::MeshAttributeData{4},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
VertexFormat::Vector3, nullptr}
});
CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::Lines);
CORRADE_VERIFY(!duplicated.isIndexed());
CORRADE_COMPARE(duplicated.vertexCount(), 6);
CORRADE_COMPARE(duplicated.attributeCount(), 2);
CORRADE_COMPARE_AS(duplicated.attribute<Vector2>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector2>({
{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f},
{1.0f, -0.5f}, {0.87f, 1.1f}, {1.3f, 0.3f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE(duplicated.attributeStride(Trade::MeshAttribute::Normal), 24);
CORRADE_COMPARE(duplicated.attributeOffset(Trade::MeshAttribute::Normal), 12);
}
void DuplicateTest::duplicateMeshDataExtraWrongCount() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Vector2 positions[]{{1.3f, 0.3f}, {0.87f, 1.1f}, {1.0f, -0.5f}};
Trade::MeshData data{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices},
{}, positions, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(positions)}
}};
const Vector3 normals[]{Vector3::xAxis(), Vector3::yAxis()};
std::ostringstream out;
Error redirectError{&out};
MeshTools::duplicate(data, {
Trade::MeshAttributeData{10},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, Containers::arrayView(normals)}
});
CORRADE_COMPARE(out.str(), "MeshTools::duplicate(): extra attribute 1 expected to have 3 items but got 2\n");
}
void DuplicateTest::duplicateMeshDataNoAttributes() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Trade::MeshData data{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
Trade::MeshData duplicated = MeshTools::duplicate(data, {});
CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::Lines);
CORRADE_VERIFY(!duplicated.isIndexed());
CORRADE_COMPARE(duplicated.vertexCount(), 6);
CORRADE_COMPARE(duplicated.attributeCount(), 0);
CORRADE_VERIFY(!duplicated.vertexData());
}
}}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::DuplicateTest)

Loading…
Cancel
Save