diff --git a/doc/changelog.dox b/doc/changelog.dox index 4104e348e..572de1d3e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -212,6 +212,9 @@ See also: @ref MeshTools::removeDuplicatesInPlace() variant - Added @ref MeshTools::duplicateInto() variants that take type-erased 2D strided array views +- Added @ref MeshTools::generateSmoothNormals() and + @ref MeshTools::generateSmoothNormalsInto() variants taking type-erased + index arrays @subsubsection changelog-latest-changes-platform Platform libraries diff --git a/src/Magnum/MeshTools/GenerateNormals.cpp b/src/Magnum/MeshTools/GenerateNormals.cpp index de924b808..7aacd35ec 100644 --- a/src/Magnum/MeshTools/GenerateNormals.cpp +++ b/src/Magnum/MeshTools/GenerateNormals.cpp @@ -234,6 +234,18 @@ void generateSmoothNormalsInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& normals) { + CORRADE_ASSERT(indices.isContiguous<1>(), "MeshTools::generateSmoothNormalsInto(): second index view dimension is not contiguous", ); + if(indices.size()[1] == 4) + return generateSmoothNormalsIntoImplementation(Containers::arrayCast<1, const UnsignedInt>(indices), positions, normals); + else if(indices.size()[1] == 2) + return generateSmoothNormalsIntoImplementation(Containers::arrayCast<1, const UnsignedShort>(indices), positions, normals); + else { + CORRADE_ASSERT(indices.size()[1] == 1, "MeshTools::generateSmoothNormalsInto(): expected index type size 1, 2 or 4 but got" << indices.size()[1], ); + return generateSmoothNormalsIntoImplementation(Containers::arrayCast<1, const UnsignedByte>(indices), positions, normals); + } +} + namespace { template inline Containers::Array generateSmoothNormalsImplementation(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& positions) { @@ -257,4 +269,10 @@ Containers::Array generateSmoothNormals(const Containers::StridedArrayV return generateSmoothNormalsImplementation(indices, positions); } +Containers::Array generateSmoothNormals(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView1D& positions) { + Containers::Array out{Containers::NoInit, positions.size()}; + generateSmoothNormalsInto(indices, positions, out); + return out; +} + }} diff --git a/src/Magnum/MeshTools/GenerateNormals.h b/src/Magnum/MeshTools/GenerateNormals.h index fa1ccdffb..219bdfe73 100644 --- a/src/Magnum/MeshTools/GenerateNormals.h +++ b/src/Magnum/MeshTools/GenerateNormals.h @@ -132,6 +132,17 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateSmoothNormals(const C */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateSmoothNormals(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& positions); +/** +@brief Generate smooth normals using a type-erased index array +@m_since_latest + +Expects that the second dimension of @p indices is contiguous and represents +the actual 1/2/4-byte index type. Based on its size then calls one of the +@ref generateSmoothNormals(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +etc. overloads. +*/ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateSmoothNormals(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView1D& positions); + /** @brief Generate smooth normals into an existing array @param[in] indices Triangle face indices @@ -167,6 +178,18 @@ MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::Strided */ MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& normals); +/** +@brief Generate smooth normals into an existing array using a type-erased index array +@m_since_latest + +Expects that @p normals has the same size as @p positions and that the second +dimension of @p indices is contiguous and represents the actual 1/2/4-byte +index type. Based on its size then calls one of the +@ref generateSmoothNormalsInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +etc. overloads. +*/ +MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& normals); + }} #endif diff --git a/src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp b/src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp index 486582c9f..bc80b787a 100644 --- a/src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp +++ b/src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp @@ -61,6 +61,10 @@ struct GenerateNormalsTest: TestSuite::Tester { void smoothOutOfBounds(); void smoothIntoWrongSize(); + template void smoothErased(); + void smoothErasedNonContiguous(); + void smoothErasedWrongIndexSize(); + void benchmarkFlat(); void benchmarkSmooth(); }; @@ -83,7 +87,13 @@ GenerateNormalsTest::GenerateNormalsTest() { &GenerateNormalsTest::smoothNanPosition, &GenerateNormalsTest::smoothWrongCount, &GenerateNormalsTest::smoothOutOfBounds, - &GenerateNormalsTest::smoothIntoWrongSize}); + &GenerateNormalsTest::smoothIntoWrongSize, + + &GenerateNormalsTest::smoothErased, + &GenerateNormalsTest::smoothErased, + &GenerateNormalsTest::smoothErased, + &GenerateNormalsTest::smoothErasedNonContiguous, + &GenerateNormalsTest::smoothErasedWrongIndexSize}); addBenchmarks({&GenerateNormalsTest::benchmarkFlat, &GenerateNormalsTest::benchmarkSmooth}, 150); @@ -425,6 +435,45 @@ void GenerateNormalsTest::benchmarkSmooth() { CORRADE_COMPARE(Math::min(normals), (Vector3{-0.996072f, -0.997808f, -0.996072f})); } +template void GenerateNormalsTest::smoothErased() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + const T indices[]{0, 1, 2, 3, 4, 5}; + + /* Should generate the same output as flat normals */ + CORRADE_COMPARE_AS(generateSmoothNormals(Containers::arrayCast<2, const char>(Containers::stridedArrayView(indices)), TwoTriangles), + Containers::arrayView({ + Vector3::zAxis(), + Vector3::zAxis(), + Vector3::zAxis(), + -Vector3::zAxis(), + -Vector3::zAxis(), + -Vector3::zAxis() + }), TestSuite::Compare::Container); +} + +void GenerateNormalsTest::smoothErasedNonContiguous() { + const char indices[6*4]{}; + const Vector3 positions[3]; + + std::stringstream out; + Error redirectError{&out}; + generateSmoothNormals(Containers::StridedArrayView2D{indices, {6, 2}, {4, 2}}, positions); + CORRADE_COMPARE(out.str(), + "MeshTools::generateSmoothNormalsInto(): second index view dimension is not contiguous\n"); +} + +void GenerateNormalsTest::smoothErasedWrongIndexSize() { + const char indices[6*3]{}; + const Vector3 positions[3]; + + std::stringstream out; + Error redirectError{&out}; + generateSmoothNormals(Containers::StridedArrayView2D{indices, {6, 3}}.every(2), positions); + CORRADE_COMPARE(out.str(), + "MeshTools::generateSmoothNormalsInto(): expected index type size 1, 2 or 4 but got 3\n"); +} + }}}} CORRADE_TEST_MAIN(Magnum::MeshTools::Test::GenerateNormalsTest)