diff --git a/src/Magnum/MeshTools/Subdivide.h b/src/Magnum/MeshTools/Subdivide.h index 41b7e42d8..1796c16f4 100644 --- a/src/Magnum/MeshTools/Subdivide.h +++ b/src/Magnum/MeshTools/Subdivide.h @@ -31,12 +31,15 @@ #include #include +#include #include +#include "Magnum/Magnum.h" + namespace Magnum { namespace MeshTools { #ifndef DOXYGEN_GENERATING_OUTPUT -template void subdivideInPlace(Containers::ArrayView indices, Containers::ArrayView vertices, Interpolator interpolator); +template void subdivideInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& vertices, Interpolator interpolator); #endif /** @@ -50,14 +53,14 @@ template void subdivideInPlace(Containers::Arr Goes through all triangle faces and subdivides them into four new. Removing duplicate vertices in the mesh is up to the user. -@see @ref subdivideInPlace() +@see @ref subdivideInPlace(), @ref removeDuplicatesInPlace() */ template void subdivide(std::vector& indices, std::vector& vertices, Interpolator interpolator) { - CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3!", ); + CORRADE_ASSERT(!(indices.size()%3), "MeshTools::subdivide(): index count is not divisible by 3", ); vertices.resize(vertices.size() + indices.size()); indices.resize(indices.size()*4); - subdivideInPlace(Containers::arrayView(indices), Containers::arrayView(vertices), interpolator); + subdivideInPlace(Containers::stridedArrayView(indices), Containers::stridedArrayView(vertices), interpolator); } /** @@ -68,16 +71,32 @@ template void subdivide(std::vector void subdivideInPlace(Containers::ArrayView indices, Containers::ArrayView vertices, Interpolator interpolator) { - CORRADE_ASSERT(!(indices.size()%12), "MeshTools::subdivideInto(): can't divide" << indices.size() << "indices to four parts with each having triangle faces", ); +template void subdivideInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& vertices, Interpolator interpolator) { + CORRADE_ASSERT(!(indices.size()%12), "MeshTools::subdivideInPlace(): can't divide" << indices.size() << "indices to four parts with each having triangle faces", ); + /* Somehow ~IndexType{} doesn't work for < 4byte types, as the result is + int(-1) instead of the type I want */ + CORRADE_ASSERT(vertices.size() <= IndexType(-1), "MeshTools::subdivideInPlace(): a" << sizeof(IndexType) << Debug::nospace << "-byte index type is too small for" << vertices.size() << "vertices", ); /* Subdivide each face to four new */ const std::size_t indexCount = indices.size()/4; @@ -85,7 +104,7 @@ template void subdivideInPlace(Containers::Arr std::size_t vertexOffset = vertices.size() - indexCount; for(std::size_t i = 0; i != indexCount; i += 3) { /* Interpolate each side */ - UnsignedInt newVertices[3]; + IndexType newVertices[3]; for(int j = 0; j != 3; ++j) { newVertices[j] = vertexOffset; vertices[vertexOffset++] = interpolator(vertices[indices[i+j]], vertices[indices[i+(j+1)%3]]); @@ -120,6 +139,14 @@ template void subdivideInPlace(Containers::Arr } } +/** + * @overload + * @m_since_latest + */ +template void subdivideInPlace(const Containers::ArrayView& indices, const Containers::StridedArrayView1D& vertices, Interpolator interpolator) { + subdivideInPlace(Containers::stridedArrayView(indices), vertices, interpolator); +} + }} #endif diff --git a/src/Magnum/MeshTools/Test/SubdivideTest.cpp b/src/Magnum/MeshTools/Test/SubdivideTest.cpp index 34665591f..9617af221 100644 --- a/src/Magnum/MeshTools/Test/SubdivideTest.cpp +++ b/src/Magnum/MeshTools/Test/SubdivideTest.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include "Magnum/MeshTools/RemoveDuplicates.h" @@ -35,8 +36,11 @@ namespace Magnum { namespace MeshTools { namespace Test { namespace { struct SubdivideTest: TestSuite::Tester { explicit SubdivideTest(); - void wrongIndexCount(); void subdivide(); + void subdivideWrongIndexCount(); + template void subdivideInPlace(); + void subdivideInPlaceWrongIndexCount(); + void subdivideInPlaceSmallIndexType(); }; typedef Math::Vector<1, Int> Vector1; @@ -44,29 +48,74 @@ typedef Math::Vector<1, Int> Vector1; inline Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; } SubdivideTest::SubdivideTest() { - addTests({&SubdivideTest::wrongIndexCount, - &SubdivideTest::subdivide}); + addTests({&SubdivideTest::subdivide, + &SubdivideTest::subdivideWrongIndexCount, + &SubdivideTest::subdivideInPlace, + &SubdivideTest::subdivideInPlace, + &SubdivideTest::subdivideInPlace, + &SubdivideTest::subdivideInPlaceWrongIndexCount, + &SubdivideTest::subdivideInPlaceSmallIndexType}); } -void SubdivideTest::wrongIndexCount() { - std::stringstream ss; - Error redirectError{&ss}; +void SubdivideTest::subdivide() { + std::vector positions{0, 2, 6, 8}; + std::vector indices{0, 1, 2, 1, 2, 3}; + MeshTools::subdivide(indices, positions, interpolator); + + CORRADE_COMPARE_AS(indices, + (std::vector{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(positions, + (std::vector{0, 2, 6, 8, 1, 4, 3, 4, 7, 5}), + TestSuite::Compare::Container); +} + +void SubdivideTest::subdivideWrongIndexCount() { + std::stringstream out; + Error redirectError{&out}; std::vector positions; std::vector indices{0, 1}; MeshTools::subdivide(indices, positions, interpolator); - CORRADE_COMPARE(ss.str(), "MeshTools::subdivide(): index count is not divisible by 3!\n"); + CORRADE_COMPARE(out.str(), "MeshTools::subdivide(): index count is not divisible by 3\n"); } -void SubdivideTest::subdivide() { - std::vector positions{0, 2, 6, 8}; - std::vector indices{0, 1, 2, 1, 2, 3}; - MeshTools::subdivide(indices, positions, interpolator); +template void SubdivideTest::subdivideInPlace() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + T indices[6*4]{0, 1, 2, 1, 2, 3, /* and 18 more */}; + Vector1 positions[4 + 6]{0, 2, 6, 8, /* and 6 more */}; + MeshTools::subdivideInPlace(Containers::stridedArrayView(indices), + Containers::stridedArrayView(positions), interpolator); + + CORRADE_COMPARE_AS(Containers::arrayView(indices), + Containers::arrayView({4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(Containers::arrayView(positions), + Containers::arrayView({0, 2, 6, 8, 1, 4, 3, 4, 7, 5}), + TestSuite::Compare::Container); +} + +void SubdivideTest::subdivideInPlaceWrongIndexCount() { + std::stringstream out; + Error redirectError{&out}; + + UnsignedInt indices[6*4 + 1]{0, 1, 2, 1, 2, 3, /* and 18+1 more */}; + Vector1 positions[]{0}; + MeshTools::subdivideInPlace(Containers::stridedArrayView(indices), + Containers::stridedArrayView(positions), interpolator); + CORRADE_COMPARE(out.str(), "MeshTools::subdivideInPlace(): can't divide 25 indices to four parts with each having triangle faces\n"); +} - CORRADE_COMPARE(indices.size(), 24); +void SubdivideTest::subdivideInPlaceSmallIndexType() { + std::stringstream out; + Error redirectError{&out}; - CORRADE_VERIFY(positions == (std::vector{0, 2, 6, 8, 1, 4, 3, 4, 7, 5})); - CORRADE_COMPARE(indices, (std::vector{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3})); + UnsignedByte indices[6*4]{0, 1, 2, 1, 2, 3, /* and 18 more */}; + Vector1 positions[256]{}; + MeshTools::subdivideInPlace(Containers::stridedArrayView(indices), + Containers::stridedArrayView(positions), interpolator); + CORRADE_COMPARE(out.str(), "MeshTools::subdivideInPlace(): a 1-byte index type is too small for 256 vertices\n"); } }}}}