diff --git a/doc/changelog.dox b/doc/changelog.dox index b18fac2d5..d8e348d1b 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -219,6 +219,13 @@ See also: @ref MeshTools::removeDuplicatesInPlace() variant - Added @ref MeshTools::duplicateInto() variants that take type-erased 2D strided array views +- @ref MeshTools::flipNormalsInPlace() and @ref MeshTools::flipFaceWindingInPlace() + were renamed for clarity and now accept a + @ref Corrade::Containers::StridedArrayView instead of a @ref std::vector, + additionally working on 8- and 16-byte index types as well +- @ref MeshTools::tipsifyInPlace() was renamed for clarity and now accepts a + @ref Corrade::Containers::StridedArrayView instead of a @ref std::vector, + additionally working on 8- and 16-byte index types as well - Added @ref MeshTools::generateSmoothNormals() and @ref MeshTools::generateSmoothNormalsInto() variants taking type-erased index arrays @@ -313,8 +320,8 @@ See also: - It was not possible to override DPI scaling using @ref Platform::Sdl2Application::Configuration as command-line arguments always got a priority (see [mosra/magnum#416](https://github.com/mosra/magnum/issues/416)) -- Fixed an otherwise harmless OOB access in @ref MeshTools::tipsify() that - could trigger ASan or debug iterator errors +- Fixed an otherwise harmless OOB access in @ref MeshTools::tipsifyInPlace() + that could trigger ASan or debug iterator errors - With @ref Corrade/Utility/DebugStl.h not being included, @ref std::string instances could get accidentally printed as @ref ResourceKey instances. Added and explicit header dependency to avoid such cases. @@ -356,6 +363,12 @@ See also: @ref Text::FontConverterFeatures, @ref Trade::ImporterFeatures, @ref Trade::ImageConverterFeatures enum sets and their corresponding enums placed directly in the namespace to have them shorter and unambiguous +- @cpp MeshTools::flipNormals() @ce and @cpp MeshTools::flipFaceWinding() @ce + and @cpp MeshTools::tipsify() @ce are deprecated in favor of + @ref MeshTools::flipNormalsInPlace(), + @ref MeshTools::flipFaceWindingInPlace() and @ref MeshTools::tipsifyInPlace() + that accept a @ref Corrade::Containers::StridedArrayView instead of a + @ref std::vector and work with 8- and 16-byte index types as well. @subsection changelog-latest-compatibility Potential compatibility breakages, removed APIs diff --git a/src/Magnum/MeshTools/FlipNormals.cpp b/src/Magnum/MeshTools/FlipNormals.cpp index f6159135d..05089b132 100644 --- a/src/Magnum/MeshTools/FlipNormals.cpp +++ b/src/Magnum/MeshTools/FlipNormals.cpp @@ -25,11 +25,16 @@ #include "FlipNormals.h" +#include +#include + #include "Magnum/Math/Vector3.h" namespace Magnum { namespace MeshTools { -void flipFaceWinding(std::vector& indices) { +namespace { + +template inline void flipFaceWindingInPlaceImplementation(const Containers::StridedArrayView1D& indices) { CORRADE_ASSERT(!(indices.size()%3), "MeshTools::flipNormals(): index count is not divisible by 3!", ); using std::swap; @@ -37,9 +42,37 @@ void flipFaceWinding(std::vector& indices) { swap(indices[i+1], indices[i+2]); } -void flipNormals(std::vector& normals) { +} + +void flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices) { + flipFaceWindingInPlaceImplementation(indices); +} + +void flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices) { + flipFaceWindingInPlaceImplementation(indices); +} + +void flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices) { + flipFaceWindingInPlaceImplementation(indices); +} + +void flipNormalsInPlace(const Containers::StridedArrayView1D& normals) { for(Vector3& normal: normals) normal = -normal; } +#ifdef MAGNUM_BUILD_DEPRECATED +void flipNormals(std::vector& indices, std::vector& normals) { + flipNormalsInPlace(indices, normals); +} + +void flipFaceWinding(std::vector& indices) { + flipFaceWindingInPlace(indices); +} + +void flipNormals(std::vector& normals) { + flipNormalsInPlace(normals); +} +#endif + }} diff --git a/src/Magnum/MeshTools/FlipNormals.h b/src/Magnum/MeshTools/FlipNormals.h index 6fad4a4a2..de9e863ec 100644 --- a/src/Magnum/MeshTools/FlipNormals.h +++ b/src/Magnum/MeshTools/FlipNormals.h @@ -26,52 +26,119 @@ */ /** @file - * @brief Function @ref Magnum::MeshTools::flipFaceWinding(), @ref Magnum::MeshTools::flipNormals() + * @brief Function @ref Magnum::MeshTools::flipFaceWindingInPlace(), @ref Magnum::MeshTools::flipNormalsInPlace() */ -#include +#include #include "Magnum/Magnum.h" #include "Magnum/MeshTools/visibility.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#include +#include +#include +#endif + namespace Magnum { namespace MeshTools { /** -@brief Flip face winding +@brief Flip mesh normals and face winding in-place @param[in,out] indices Index array to operate on +@param[in,out] normals Normal array to operate on -The same as @ref flipNormals(std::vector&, std::vector&), -but flips only face winding. - -@attention The function requires the mesh to have triangle faces, thus index - count must be divisible by 3. +Flips normal vectors and face winding in index array for face culling to work +properly too. See also @ref flipNormalsInPlace(const Containers::StridedArrayView1D&) +and @ref flipFaceWindingInPlace(), which flip normals or face winding only. +Expects a triangle mesh, thus the index count has to be divisible by 3. */ -void MAGNUM_MESHTOOLS_EXPORT flipFaceWinding(std::vector& indices); +void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals); /** -@brief Flip mesh normals -@param[in,out] normals Normal array to operate on + * @overload + * @m_since_latest + */ +void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals); -The same as @ref flipNormals(std::vector&, std::vector&), -but flips only normals, not face winding. +/** + * @overload + * @m_since_latest + */ +void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals); + +#ifdef MAGNUM_BUILD_DEPRECATED +/** +@brief @copybrief flipNormalsInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +@m_deprecated_since_latest Use @ref flipNormalsInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) + instead. */ -void MAGNUM_MESHTOOLS_EXPORT flipNormals(std::vector& normals); +CORRADE_DEPRECATED("use flipNormalsInPlace() instead") MAGNUM_MESHTOOLS_EXPORT void flipNormals(std::vector& indices, std::vector& normals); +#endif /** -@brief Flip mesh normals and face winding +@brief Flip face winding in-place @param[in,out] indices Index array to operate on +@m_since_latest + +Same as @ref flipNormalsInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&), +but flips only face winding. Expects a triangle mesh, thus the index count has +to be divisible by 3. +*/ +void MAGNUM_MESHTOOLS_EXPORT flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +void MAGNUM_MESHTOOLS_EXPORT flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +void MAGNUM_MESHTOOLS_EXPORT flipFaceWindingInPlace(const Containers::StridedArrayView1D& indices); + +#ifdef MAGNUM_BUILD_DEPRECATED +/** +@brief @copybrief flipFaceWindingInPlace(const Containers::StridedArrayView1D&) +@m_deprecated_since_latest Use @ref flipFaceWindingInPlace(const Containers::StridedArrayView1D&) + instead. +*/ +CORRADE_DEPRECATED("use flipFaceWindingInPlace() instead") MAGNUM_MESHTOOLS_EXPORT void flipFaceWinding(std::vector& indices); +#endif + +/** +@brief Flip mesh normals in-place @param[in,out] normals Normal array to operate on -Flips normal vectors and face winding in index array for face culling to work -properly too. See also @ref flipNormals(std::vector&) and -@ref flipFaceWinding(), which flip normals or face winding only. +Same as @ref flipNormalsInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&), +but flips only normals, not face winding. +*/ +void MAGNUM_MESHTOOLS_EXPORT flipNormalsInPlace(const Containers::StridedArrayView1D& normals); -@attention The function requires the mesh to have triangle faces, thus index - count must be divisible by 3. +#ifdef MAGNUM_BUILD_DEPRECATED +/** +@copybrief flipNormalsInPlace(const Containers::StridedArrayView1D&) +@m_deprecated_since_latest Use @ref flipNormalsInPlace(const Containers::StridedArrayView1D&) + instead. */ -inline void flipNormals(std::vector& indices, std::vector& normals) { - flipFaceWinding(indices); - flipNormals(normals); +CORRADE_DEPRECATED("use flipNormalsInPlace() instead") MAGNUM_MESHTOOLS_EXPORT void flipNormals(std::vector& normals); +#endif + +inline void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals) { + flipFaceWindingInPlace(indices); + flipNormalsInPlace(normals); +} + +inline void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals) { + flipFaceWindingInPlace(indices); + flipNormalsInPlace(normals); +} + +inline void flipNormalsInPlace(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& normals) { + flipFaceWindingInPlace(indices); + flipNormalsInPlace(normals); } }} diff --git a/src/Magnum/MeshTools/Implementation/Tipsify.h b/src/Magnum/MeshTools/Implementation/Tipsify.h index 63def0dcd..214e385b0 100644 --- a/src/Magnum/MeshTools/Implementation/Tipsify.h +++ b/src/Magnum/MeshTools/Implementation/Tipsify.h @@ -25,7 +25,8 @@ DEALINGS IN THE SOFTWARE. */ -#include +#include +#include #include "Magnum/Magnum.h" @@ -33,11 +34,10 @@ namespace Magnum { namespace MeshTools { namespace Implementation { namespace { /* Vertex-triangle adjacency. Computes count and indices of adjacent triangles for each vertex (used internally by tipsify()) */ -void buildAdjacency(const std::vector& indices, const UnsignedInt vertexCount, std::vector& liveTriangleCount, std::vector& neighborOffset, std::vector& neighbors) { +template void buildAdjacency(const Containers::StridedArrayView1D& indices, const UnsignedInt vertexCount, Containers::Array& liveTriangleCount, Containers::Array& neighborOffset, Containers::Array& neighbors) { /* How many times is each vertex referenced == count of neighboring triangles for each vertex */ - liveTriangleCount.clear(); - liveTriangleCount.resize(vertexCount); + liveTriangleCount = Containers::Array{vertexCount}; for(std::size_t i = 0; i != indices.size(); ++i) ++liveTriangleCount[indices[i]]; @@ -45,19 +45,17 @@ void buildAdjacency(const std::vector& indices, const UnsignedInt v the end be in interval neighbors[neighborOffset[i]] ; neighbors[neighborOffset[i+1]]. Currently the values are shifted to right, because the next loop will shift them back left. */ - neighborOffset.clear(); - neighborOffset.reserve(vertexCount+1); - neighborOffset.push_back(0); + neighborOffset = Containers::Array{Containers::NoInit, vertexCount + 1}; + neighborOffset[0] = 0; UnsignedInt sum = 0; for(std::size_t i = 0; i != vertexCount; ++i) { - neighborOffset.push_back(sum); + neighborOffset[i + 1] = sum; sum += liveTriangleCount[i]; } /* Array of neighbors, using (and changing) neighborOffset array for positioning */ - neighbors.clear(); - neighbors.resize(sum); + neighbors = Containers::Array{Containers::NoInit, sum}; for(std::size_t i = 0; i != indices.size(); ++i) neighbors[neighborOffset[indices[i]+1]++] = i/3; } diff --git a/src/Magnum/MeshTools/Test/TipsifyTest.cpp b/src/Magnum/MeshTools/Test/TipsifyTest.cpp index 3b7e97299..15e571479 100644 --- a/src/Magnum/MeshTools/Test/TipsifyTest.cpp +++ b/src/Magnum/MeshTools/Test/TipsifyTest.cpp @@ -23,7 +23,9 @@ DEALINGS IN THE SOFTWARE. */ +#include #include +#include #include "Magnum/Magnum.h" #include "Magnum/MeshTools/Tipsify.h" @@ -54,7 +56,7 @@ struct TipsifyTest: TestSuite::Tester { */ -const std::vector Indices{ +constexpr UnsignedInt Indices[]{ 4, 1, 0, 10, 9, 13, 6, 3, 2, @@ -88,27 +90,26 @@ TipsifyTest::TipsifyTest() { } void TipsifyTest::buildAdjacency() { - std::vector indices = Indices; - std::vector liveTriangleCount, neighborOffset, neighbors; - Implementation::buildAdjacency(indices, VertexCount, liveTriangleCount, neighborOffset, neighbors); + Containers::Array liveTriangleCount, neighborOffset, neighbors; + Implementation::buildAdjacency(Containers::stridedArrayView(Indices), VertexCount, liveTriangleCount, neighborOffset, neighbors); - CORRADE_COMPARE(liveTriangleCount, (std::vector{ + CORRADE_COMPARE_AS(liveTriangleCount, Containers::arrayView({ 1, 3, 3, 2, 4, 6, 6, 2, 2, 6, 6, 4, 2, 3, 3, 1, 1, 1, 1 - })); + }), TestSuite::Compare::Container); - CORRADE_COMPARE(neighborOffset, (std::vector{ + CORRADE_COMPARE_AS(neighborOffset, Containers::arrayView({ 0, 1, 4, 7, 9, 13, 19, 25, 27, 29, 35, 41, 45, 47, 50, 53, 54, 55, 56, 57 - })); + }), TestSuite::Compare::Container); - CORRADE_COMPARE(neighbors, (std::vector{ + CORRADE_COMPARE_AS(neighbors, Containers::arrayView({ 0, 0, 7, 11, 2, 7, 13, @@ -130,11 +131,11 @@ void TipsifyTest::buildAdjacency() { 6, 18, 18, 18 - })); + }), TestSuite::Compare::Container); } void TipsifyTest::tipsify() { - std::vector indices = Indices; + std::vector indices{std::begin(Indices), std::end(Indices)}; MeshTools::tipsify(indices, VertexCount, 3); CORRADE_COMPARE(indices, (std::vector{ diff --git a/src/Magnum/MeshTools/Tipsify.cpp b/src/Magnum/MeshTools/Tipsify.cpp index b3d437363..418233518 100644 --- a/src/Magnum/MeshTools/Tipsify.cpp +++ b/src/Magnum/MeshTools/Tipsify.cpp @@ -25,36 +25,43 @@ #include "Tipsify.h" -#include +#include +#include #include "Magnum/MeshTools/Implementation/Tipsify.h" namespace Magnum { namespace MeshTools { -void tipsify(std::vector& indices, const UnsignedInt vertexCount, const std::size_t cacheSize) { +namespace { + +template void tipsifyInPlaceImplementation(const Containers::StridedArrayView1D& indices, const UnsignedInt vertexCount, const std::size_t cacheSize) { /* Neighboring triangles for each vertex, per-vertex live triangle count */ - std::vector liveTriangleCount, neighborOffset, neighbors; - Implementation::buildAdjacency(indices, vertexCount, liveTriangleCount, neighborOffset, neighbors); + Containers::Array liveTriangleCount, neighborOffset, neighbors; + Implementation::buildAdjacency(indices, vertexCount, liveTriangleCount, neighborOffset, neighbors); /* Global time, per-vertex caching timestamps, per-triangle emmited flag */ UnsignedInt time = cacheSize+1; - std::vector timestamp(vertexCount); - std::vector emitted(indices.size()/3); + Containers::Array timestamp{vertexCount}; + /** @todo Have some bitset/staticbitset class for this */ + Containers::Array emitted{indices.size()/3}; /* Dead-end vertex stack */ - std::stack deadEndStack; + Containers::Array deadEndStack; /* Output index buffer */ - std::vector outputIndices; - outputIndices.reserve(indices.size()); + Containers::Array outputIndices{Containers::NoInit, indices.size()}; + std::size_t outputIndex = 0; + + /* Array with candidates for next fanning vertex (in 1-ring around + fanning vertex) */ + Containers::Array candidates; /* Starting vertex for fanning, cursor */ UnsignedInt fanningVertex = 0; UnsignedInt i = 0; while(fanningVertex != 0xFFFFFFFFu) { - /* Array with candidates for next fanning vertex (in 1-ring around - fanning vertex) */ - std::vector candidates; + /* Reset the candidates for this vertex */ + arrayResize(candidates, 0); /* For all neighbors of fanning vertex */ for(UnsignedInt ti = neighborOffset[fanningVertex]; ti != neighborOffset[fanningVertex+1]; ++ti) { @@ -68,12 +75,12 @@ void tipsify(std::vector& indices, const UnsignedInt vertexCount, c for(UnsignedInt vi = 0; vi != 3; ++vi) { const UnsignedInt v = indices[vi + t*3]; - outputIndices.push_back(v); + outputIndices[outputIndex++] = v; /* Add to dead end stack and candidates array */ /** @todo Limit size of dead end stack to cache size */ - deadEndStack.push(v); - candidates.push_back(v); + arrayAppend(deadEndStack, v); + arrayAppend(candidates, v); /* Decrease live triangle count */ --liveTriangleCount[v]; @@ -109,8 +116,8 @@ void tipsify(std::vector& indices, const UnsignedInt vertexCount, c if(fanningVertex == 0xFFFFFFFFu) { /* Find vertex with live triangles in dead-end stack */ while(!deadEndStack.empty()) { - unsigned int d = deadEndStack.top(); - deadEndStack.pop(); + UnsignedInt d = deadEndStack.back(); + arrayRemoveSuffix(deadEndStack); if(!liveTriangleCount[d]) continue; fanningVertex = d; @@ -129,8 +136,21 @@ void tipsify(std::vector& indices, const UnsignedInt vertexCount, c } /* Swap original index buffer with optimized */ - using std::swap; - swap(indices, outputIndices); + Utility::copy(outputIndices, indices); +} + +} + +void tipsifyInPlace(const Containers::StridedArrayView1D& indices, const UnsignedInt vertexCount, const std::size_t cacheSize) { + tipsifyInPlaceImplementation(indices, vertexCount, cacheSize); +} + +void tipsifyInPlace(const Containers::StridedArrayView1D& indices, const UnsignedInt vertexCount, const std::size_t cacheSize) { + tipsifyInPlaceImplementation(indices, vertexCount, cacheSize); +} + +void tipsifyInPlace(const Containers::StridedArrayView1D& indices, const UnsignedInt vertexCount, const std::size_t cacheSize) { + tipsifyInPlaceImplementation(indices, vertexCount, cacheSize); } }} diff --git a/src/Magnum/MeshTools/Tipsify.h b/src/Magnum/MeshTools/Tipsify.h index 4855d175f..54885a677 100644 --- a/src/Magnum/MeshTools/Tipsify.h +++ b/src/Magnum/MeshTools/Tipsify.h @@ -26,30 +26,59 @@ */ /** @file - * @brief Function @ref Magnum::MeshTools::tipsify() + * @brief Function @ref Magnum::MeshTools::tipsifyInPlace() */ -#include +#include -#include "Magnum/Types.h" +#include "Magnum/Magnum.h" #include "Magnum/MeshTools/visibility.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#include +#include +#include +#endif + namespace Magnum { namespace MeshTools { /** -@brief Tipsify the mesh +@brief Tipsify the mesh in-place @param[in,out] indices Indices array to operate on @param[in] vertexCount Vertex count @param[in] cacheSize Post-transform vertex cache size Optimizes the mesh for vertex-bound applications by rearranging its index array for beter usage of post-transform vertex cache. Algorithm used: -*Pedro V. Sander, Diego Nehab, and Joshua Barczak --- Fast Triangle Reordering +* *Pedro V. Sander, Diego Nehab, and Joshua Barczak --- Fast Triangle Reordering for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007, http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/index.php*. @todo Ability to compute vertex count automatically */ -MAGNUM_MESHTOOLS_EXPORT void tipsify(std::vector& indices, UnsignedInt vertexCount, std::size_t cacheSize); +MAGNUM_MESHTOOLS_EXPORT void tipsifyInPlace(const Containers::StridedArrayView1D& indices, UnsignedInt vertexCount, std::size_t cacheSize); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void tipsifyInPlace(const Containers::StridedArrayView1D& indices, UnsignedInt vertexCount, std::size_t cacheSize); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void tipsifyInPlace(const Containers::StridedArrayView1D& indices, UnsignedInt vertexCount, std::size_t cacheSize); + +#ifdef MAGNUM_BUILD_DEPRECATED +/** + * @brief @copybrief tipsifyInPlace() + * @m_deprecated_since_latest Use @ref tipsifyInPlace() instead. + */ +inline CORRADE_DEPRECATED("use tipsifyInPlace() instead") void tipsify(std::vector& indices, UnsignedInt vertexCount, std::size_t cacheSize) { + tipsifyInPlace(indices, vertexCount, cacheSize); +} +#endif }}