diff --git a/doc/changelog.dox b/doc/changelog.dox index c0843866f..cd6d693f7 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -551,6 +551,12 @@ See also: @relativeref{MeshTools,generateIndices()} now allow empty input, producing an empty index buffer as a result. Disallowing empty input was an unnecessary restriction that was inconsistent with other APIs. +- Added overloads to @ref MeshTools::generateLineStripIndices(), + @relativeref{MeshTools,generateLineLoopIndices()}, + @relativeref{MeshTools,generateTriangleStripIndices()} and + @relativeref{MeshTools,generateTriangleFanIndices()} that take an existing + index buffer instead of vertex count as an input to generate an index + buffer for a mesh that's already indexed. @subsubsection changelog-latest-changes-platform Platform libraries diff --git a/src/Magnum/MeshTools/GenerateIndices.cpp b/src/Magnum/MeshTools/GenerateIndices.cpp index 00b7f98f3..1573c6e4f 100644 --- a/src/Magnum/MeshTools/GenerateIndices.cpp +++ b/src/Magnum/MeshTools/GenerateIndices.cpp @@ -104,12 +104,62 @@ void generateLineStripIndicesInto(const UnsignedInt vertexCount, const Container } } +namespace { + +template void generateLineStripIndicesIntoImplementation(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + CORRADE_ASSERT(indices.size() == 0 || indices.size() >= 2, + "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two indices, got" << indices.size(), ); + + const UnsignedInt iMax = Math::max(indices.size(), std::size_t{1}) - 1; + CORRADE_ASSERT(output.size() == 2*iMax, + "MeshTools::generateLineStripIndicesInto(): bad output size, expected" << 2*iMax << "but got" << output.size(), ); + + /* Same as generateLineStripIndicesInto() above, just with the index array + indirection on top */ + for(std::size_t i = 0; i != iMax; ++i) { + output[i*2 + 0] = indices[i]; + output[i*2 + 1] = indices[i + 1]; + } +} + +} + +void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineStripIndicesIntoImplementation(indices, output); +} + +void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineStripIndicesIntoImplementation(indices, output); +} + +void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineStripIndicesIntoImplementation(indices, output); +} + Containers::Array generateLineStripIndices(const UnsignedInt vertexCount) { Containers::Array output{NoInit, 2*(Math::max(vertexCount, 1u) - 1)}; generateLineStripIndicesInto(vertexCount, output); return output; } +Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*(Math::max(indices.size(), std::size_t{1}) - 1)}; + generateLineStripIndicesInto(indices, output); + return output; +} + +Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*(Math::max(indices.size(), std::size_t{1}) - 1)}; + generateLineStripIndicesInto(indices, output); + return output; +} + +Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*(Math::max(indices.size(), std::size_t{1}) - 1)}; + generateLineStripIndicesInto(indices, output); + return output; +} + void generateLineLoopIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& output) { CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 2, "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two vertices, got" << vertexCount, ); @@ -135,12 +185,64 @@ void generateLineLoopIndicesInto(const UnsignedInt vertexCount, const Containers } } +namespace { + +template void generateLineLoopIndicesIntoImplementation(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + CORRADE_ASSERT(indices.size() == 0 || indices.size() >= 2, + "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two indices, got" << indices.size(), ); + CORRADE_ASSERT(output.size() == 2*indices.size(), + "MeshTools::generateLineLoopIndicesInto(): bad output size, expected" << 2*indices.size() << "but got" << output.size(), ); + + /* Same as generateLineLoopIndicesInto() above, just with the index array + indirection on top */ + for(std::size_t i = 0, iMax = Math::max(indices.size(), std::size_t{1}) - 1; i != iMax; ++i) { + output[i*2 + 0] = indices[i]; + output[i*2 + 1] = indices[i + 1]; + } + if(indices.size() >= 2) { + output[2*indices.size() - 2] = indices[indices.size() - 1]; + output[2*indices.size() - 1] = indices[0]; + } +} + +} + +void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineLoopIndicesIntoImplementation(indices, output); +} + +void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineLoopIndicesIntoImplementation(indices, output); +} + +void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateLineLoopIndicesIntoImplementation(indices, output); +} + Containers::Array generateLineLoopIndices(const UnsignedInt vertexCount) { Containers::Array output{NoInit, 2*vertexCount}; generateLineLoopIndicesInto(vertexCount, output); return output; } +Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*indices.size()}; + generateLineLoopIndicesInto(indices, output); + return output; +} + +Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*indices.size()}; + generateLineLoopIndicesInto(indices, output); + return output; +} + +Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 2*indices.size()}; + generateLineLoopIndicesInto(indices, output); + return output; +} + void generateTriangleStripIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& output) { CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 3, "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three vertices, got" << vertexCount, ); @@ -166,12 +268,63 @@ void generateTriangleStripIndicesInto(const UnsignedInt vertexCount, const Conta } } +namespace { + +template void generateTriangleStripIndicesIntoImplementation(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + CORRADE_ASSERT(indices.size() == 0 || indices.size() >= 3, + "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three indices, got" << indices.size(), ); + + const UnsignedInt iMax = Math::max(indices.size(), std::size_t{2}) - 2; + CORRADE_ASSERT(output.size() == 3*iMax, + "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected" << 3*iMax << "but got" << output.size(), ); + + /* Same as generateTriangleStripIndicesInto() above, just with the index + array indirection on top */ + for(std::size_t i = 0; i != iMax; ++i) { + output[i*3 + 0] = indices[i % 2 ? i + 1 : i]; + output[i*3 + 1] = indices[i % 2 ? i : i + 1]; + output[i*3 + 2] = indices[i + 2]; + } +} + +} + +void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleStripIndicesIntoImplementation(indices, output); +} + +void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleStripIndicesIntoImplementation(indices, output); +} + +void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleStripIndicesIntoImplementation(indices, output); +} + Containers::Array generateTriangleStripIndices(const UnsignedInt vertexCount) { Containers::Array output{NoInit, 3*(Math::max(vertexCount, 2u) - 2u)}; generateTriangleStripIndicesInto(vertexCount, output); return output; } +Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleStripIndicesInto(indices, output); + return output; +} + +Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleStripIndicesInto(indices, output); + return output; +} + +Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleStripIndicesInto(indices, output); + return output; +} + void generateTriangleFanIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& output) { CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 3, "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three vertices, got" << vertexCount, ); @@ -198,12 +351,63 @@ void generateTriangleFanIndicesInto(const UnsignedInt vertexCount, const Contain } } +namespace { + +template void generateTriangleFanIndicesIntoImplementation(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + CORRADE_ASSERT(indices.size() == 0 || indices.size() >= 3, + "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three indices, got" << indices.size(), ); + + const UnsignedInt iMax = Math::max(indices.size(), std::size_t{2}) - 2; + CORRADE_ASSERT(output.size() == 3*iMax, + "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected" << 3*iMax << "but got" << output.size(), ); + + /* Same as generateTriangleStripIndicesInto() above, just with the index + array indirection on top */ + for(std::size_t i = 0; i != iMax; ++i) { + output[i*3 + 0] = indices[0]; + output[i*3 + 1] = indices[i + 1]; + output[i*3 + 2] = indices[i + 2]; + } +} + +} + +void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleFanIndicesIntoImplementation(indices, output); +} + +void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleFanIndicesIntoImplementation(indices, output); +} + +void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output) { + generateTriangleFanIndicesIntoImplementation(indices, output); +} + Containers::Array generateTriangleFanIndices(const UnsignedInt vertexCount) { Containers::Array output{NoInit, 3*(Math::max(vertexCount, 2u) - 2)}; generateTriangleFanIndicesInto(vertexCount, output); return output; } +Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleFanIndicesInto(indices, output); + return output; +} + +Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleFanIndicesInto(indices, output); + return output; +} + +Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices) { + Containers::Array output{NoInit, 3*(Math::max(indices.size(), std::size_t{2}) - 2)}; + generateTriangleFanIndicesInto(indices, output); + return output; +} + namespace { template inline void generateQuadIndicesIntoImplementation(const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& quads, const Containers::StridedArrayView1D& output) { diff --git a/src/Magnum/MeshTools/GenerateIndices.h b/src/Magnum/MeshTools/GenerateIndices.h index 48b727e0e..fda1245b4 100644 --- a/src/Magnum/MeshTools/GenerateIndices.h +++ b/src/Magnum/MeshTools/GenerateIndices.h @@ -55,13 +55,36 @@ MAGNUM_MESHTOOLS_EXPORT UnsignedInt primitiveCount(MeshPrimitive primitive, Unsi Can be used to convert a @ref MeshPrimitive::LineStrip mesh to @ref MeshPrimitive::Lines. The @p vertexCount is expected to be either -@cpp 0 @ce or at least @cpp 2 @ce. Primitive restart is not supported. +@cpp 0 @ce or at least @cpp 2 @ce. Primitive restart is not supported. If the +mesh is already indexed, use @ref generateLineStripIndices(const Containers::StridedArrayView1D&) +and overloads instead. @see @ref generateLineStripIndicesInto(), @ref generateLineLoopIndices(), @ref generateTriangleStripIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices(UnsignedInt vertexCount); +/** +@brief Create index buffer for an indexed line strip primitive +@m_since_latest + +Like @ref generateLineStripIndices(UnsignedInt), but merges @p indices into the +generated line strip index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices(const Containers::StridedArrayView1D& indices); + /** @brief Create index buffer for a line strip primitive into an existing array @m_since{2020,06} @@ -69,23 +92,69 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices( A variant of @ref generateLineStripIndicesInto() that fills existing memory instead of allocating a new array. The @p vertexCount is expected to be either @cpp 0 @ce or at least @cpp 2 @ce, the @p output array is expected to have a -size of @cpp 2*(vertexCount - 1) @ce. Primitive restart is not supported. +size of @cpp 2*(vertexCount - 1) @ce. Primitive restart is not supported. If +the mesh is already indexed, use @ref generateLineStripIndicesInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +and overloads instead. */ MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& output); +/** +@brief Create index buffer for an indexed line strip primitive into an existing array +@m_since_latest + +Like @ref generateLineStripIndicesInto(UnsignedInt, const Containers::StridedArrayView1D&), +but merges @p indices into the generated line strip index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + /** @brief Create index buffer for a line loop primitive @m_since{2020,06} Can be used to convert a @ref MeshPrimitive::LineLoop mesh to @ref MeshPrimitive::Lines. The @p vertexCount is expected to be either -@cpp 0 @ce or at least @cpp 2 @ce. Primitive restart is not supported. +@cpp 0 @ce or at least @cpp 2 @ce. Primitive restart is not supported. If the +mesh is already indexed, use @ref generateLineLoopIndices(const Containers::StridedArrayView1D&) +and overloads instead. @see @ref generateLineLoopIndicesInto(), @ref generateLineStripIndices(), @ref generateTriangleStripIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(UnsignedInt vertexCount); +/** +@brief Create index buffer for an indexed line loop primitive +@m_since_latest + +Like @ref generateLineLoopIndices(UnsignedInt), but merges @p indices into the +generated line loop index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(const Containers::StridedArrayView1D& indices); + /** @brief Create index buffer for a line loop primitive into an existing array @m_since{2020,06} @@ -93,23 +162,69 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(U A variant of @ref generateLineLoopIndicesInto() that fills existing memory instead of allocating a new array. The @p vertexCount is expected to be either @cpp 0 @ce or at least @cpp 2 @ce, the @p output array is expected to have a -size of @cpp 2*vertexCount @ce. Primitive restart is not supported. +size of @cpp 2*vertexCount @ce. Primitive restart is not supported.If +the mesh is already indexed, use @ref generateLineLoopIndicesInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +and overloads instead. */ MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& output); +/** +@brief Create index buffer for an indexed line loop primitive into an existing array +@m_since_latest + +Like @ref generateLineLoopIndicesInto(UnsignedInt, const Containers::StridedArrayView1D&), +but merges @p indices into the generated line loop index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + /** @brief Create index buffer for a triangle strip primitive @m_since{2020,06} Can be used to convert a @ref MeshPrimitive::TriangleStrip mesh to @ref MeshPrimitive::Triangles. The @p vertexCount is expected to be either -@cpp 0 @ce or at least @cpp 3 @ce. Primitive restart is not supported. +@cpp 0 @ce or at least @cpp 3 @ce. Primitive restart is not supported. If the +mesh is already indexed, use @ref generateTriangleStripIndices(const Containers::StridedArrayView1D&) +and overloads instead. @see @ref generateTriangleStripIndicesInto(), @ref generateLineStripIndices(), @ref generateLineLoopIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndices(UnsignedInt vertexCount); +/** +@brief Create index buffer for an indexed triangle strip primitive +@m_since_latest + +Like @ref generateTriangleStripIndices(UnsignedInt), but merges @p indices into +the generated triangle strip index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndices(const Containers::StridedArrayView1D& indices); + /** @brief Create index buffer for a triangle strip primitive into an existing array @m_since{2020,06} @@ -117,23 +232,69 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndi A variant of @ref generateTriangleStripIndicesInto() that fills existing memory instead of allocating a new array. The @p vertexCount is expected to be either @cpp 0 @ce or at least @cpp 3 @ce, the @p output array is expected to have a -size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. +size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. If +the mesh is already indexed, use @ref generateTriangleStripIndicesInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +and overloads instead. */ MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& output); +/** +@brief Create index buffer for an indexed triangle strip primitive into an existing array +@m_since_latest + +Like @ref generateTriangleStripIndicesInto(UnsignedInt, const Containers::StridedArrayView1D&), +but merges @p indices into the generated triangle strip index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + /** @brief Create index buffer for a triangle fan primitive @m_since{2020,06} Can be used to convert a @ref MeshPrimitive::TriangleFan mesh to @ref MeshPrimitive::Triangles. The @p vertexCount is expected to be either -@cpp 0 @ce or at least @cpp 3 @ce. Primitive restart is not supported. +@cpp 0 @ce or at least @cpp 3 @ce. Primitive restart is not supported. If the +mesh is already indexed, use @ref generateTriangleFanIndices(const Containers::StridedArrayView1D&) +and overloads instead. @see @ref generateTriangleFanIndicesInto(), @ref generateLineStripIndices(), @ref generateLineLoopIndices(), @ref generateTriangleStripIndices(), @ref generateIndices() */ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndices(UnsignedInt vertexCount); +/** +@brief Create index buffer for an indexed triangle fan primitive +@m_since_latest + +Like @ref generateTriangleFanIndices(UnsignedInt), but merges @p indices into +the generated triangle fan index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndices(const Containers::StridedArrayView1D& indices); + /** @brief Create index buffer for a triangle fan primitive into an existing array @m_since{2020,06} @@ -141,10 +302,33 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndice A variant of @ref generateTriangleFanIndicesInto() that fills existing memory instead of allocating a new array. The @p vertexCount is expected to be either @cpp 0 @ce or at least @cpp 3 @ce, the @p output array is expected to have a -size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. +size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. If +the mesh is already indexed, use @ref generateTriangleFanIndicesInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +and overloads instead. */ MAGNUM_MESHTOOLS_EXPORT void generateTriangleFanIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& output); +/** +@brief Create index buffer for an indexed triangle fan primitive into an existing array +@m_since_latest + +Like @ref generateTriangleFanIndicesInto(UnsignedInt, const Containers::StridedArrayView1D&), +but merges @p indices into the generated triangle fan index buffer. +*/ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_MESHTOOLS_EXPORT void generateTriangleFanIndicesInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& output); + /** @brief Create a triangle index buffer for quad primitives @m_since_latest diff --git a/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp b/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp index 074ffa72e..55f6fbd6f 100644 --- a/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp +++ b/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp @@ -46,18 +46,22 @@ struct GenerateIndicesTest: TestSuite::Tester { void primitiveCountInvalidPrimitive(); void generateLineStripIndices(); + template void generateLineStripIndicesIndexed(); void generateLineStripIndicesWrongVertexCount(); void generateLineStripIndicesIntoWrongSize(); void generateLineLoopIndices(); + template void generateLineLoopIndicesIndexed(); void generateLineLoopIndicesWrongVertexCount(); void generateLineLoopIndicesIntoWrongSize(); void generateTriangleStripIndices(); + template void generateTriangleStripIndicesIndexed(); void generateTriangleStripIndicesWrongVertexCount(); void generateTriangleStripIndicesIntoWrongSize(); void generateTriangleFanIndices(); + template void generateTriangleFanIndicesIndexed(); void generateTriangleFanIndicesWrongVertexCount(); void generateTriangleFanIndicesIntoWrongSize(); @@ -180,18 +184,30 @@ GenerateIndicesTest::GenerateIndicesTest() { &GenerateIndicesTest::primitiveCountInvalidPrimitive, &GenerateIndicesTest::generateLineStripIndices, + &GenerateIndicesTest::generateLineStripIndicesIndexed, + &GenerateIndicesTest::generateLineStripIndicesIndexed, + &GenerateIndicesTest::generateLineStripIndicesIndexed, &GenerateIndicesTest::generateLineStripIndicesWrongVertexCount, &GenerateIndicesTest::generateLineStripIndicesIntoWrongSize, &GenerateIndicesTest::generateLineLoopIndices, + &GenerateIndicesTest::generateLineLoopIndicesIndexed, + &GenerateIndicesTest::generateLineLoopIndicesIndexed, + &GenerateIndicesTest::generateLineLoopIndicesIndexed, &GenerateIndicesTest::generateLineLoopIndicesWrongVertexCount, &GenerateIndicesTest::generateLineLoopIndicesIntoWrongSize, &GenerateIndicesTest::generateTriangleStripIndices, + &GenerateIndicesTest::generateTriangleStripIndicesIndexed, + &GenerateIndicesTest::generateTriangleStripIndicesIndexed, + &GenerateIndicesTest::generateTriangleStripIndicesIndexed, &GenerateIndicesTest::generateTriangleStripIndicesWrongVertexCount, &GenerateIndicesTest::generateTriangleStripIndicesIntoWrongSize, &GenerateIndicesTest::generateTriangleFanIndices, + &GenerateIndicesTest::generateTriangleFanIndicesIndexed, + &GenerateIndicesTest::generateTriangleFanIndicesIndexed, + &GenerateIndicesTest::generateTriangleFanIndicesIndexed, &GenerateIndicesTest::generateTriangleFanIndicesWrongVertexCount, &GenerateIndicesTest::generateTriangleFanIndicesIntoWrongSize}); @@ -307,27 +323,76 @@ void GenerateIndicesTest::generateLineStripIndices() { }), TestSuite::Compare::Container); } +template void GenerateIndicesTest::generateLineStripIndicesIndexed() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + /* The second digit is 0, 1, 2, 3, 4, 5 for easier ordering. The output in + the second digit should then be the same as in + generateLineStripIndices() above. */ + T indexData[]{60, 21, 72, 93, 44, 85}; + auto indices = Containers::arrayView(indexData); + + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(indices.prefix(std::size_t{})), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(indices.prefix(2)), + Containers::arrayView({ + 60, 21 + }), TestSuite::Compare::Container); + + /* Odd */ + CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(indices.prefix(5)), + Containers::arrayView({ + 60, 21, + 21, 72, + 72, 93, + 93, 44 + }), TestSuite::Compare::Container); + + /* Even */ + CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(indices), + Containers::arrayView({ + 60, 21, + 21, 72, + 72, 93, + 93, 44, + 44, 85 + }), TestSuite::Compare::Container); +} + void GenerateIndicesTest::generateLineStripIndicesWrongVertexCount() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedShort indices[1]; + std::ostringstream out; Error redirectError{&out}; MeshTools::generateLineStripIndicesInto(1, nullptr); + MeshTools::generateLineStripIndicesInto(indices, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two vertices, got 1\n"); + "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two vertices, got 1\n" + "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two indices, got 1\n"); } void GenerateIndicesTest::generateLineStripIndicesIntoWrongSize() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedByte indices[5]; UnsignedInt output[7]; std::ostringstream out; Error redirectError{&out}; MeshTools::generateLineStripIndicesInto(0, output); + MeshTools::generateLineStripIndicesInto(Containers::arrayView(indices).prefix(std::size_t{}), output); MeshTools::generateLineStripIndicesInto(5, output); + MeshTools::generateLineStripIndicesInto(indices, output); CORRADE_COMPARE(out.str(), "MeshTools::generateLineStripIndicesInto(): bad output size, expected 0 but got 7\n" + "MeshTools::generateLineStripIndicesInto(): bad output size, expected 0 but got 7\n" + "MeshTools::generateLineStripIndicesInto(): bad output size, expected 8 but got 7\n" "MeshTools::generateLineStripIndicesInto(): bad output size, expected 8 but got 7\n"); } @@ -366,27 +431,79 @@ void GenerateIndicesTest::generateLineLoopIndices() { }), TestSuite::Compare::Container); } +template void GenerateIndicesTest::generateLineLoopIndicesIndexed() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + /* The second digit is 0, 1, 2, 3, 4, 5 for easier ordering. The output in + the second digit should then be the same as in generateLineLoopIndices() + above. */ + T indexData[]{60, 21, 72, 93, 44, 85}; + auto indices = Containers::arrayView(indexData); + + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(indices.prefix(std::size_t{})), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(indices.prefix(2)), + Containers::arrayView({ + 60, 21, + 21, 60 + }), TestSuite::Compare::Container); + + /* Odd */ + CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(indices.prefix(5)), + Containers::arrayView({ + 60, 21, + 21, 72, + 72, 93, + 93, 44, + 44, 60 + }), TestSuite::Compare::Container); + + /* Even */ + CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(indices), + Containers::arrayView({ + 60, 21, + 21, 72, + 72, 93, + 93, 44, + 44, 85, + 85, 60 + }), TestSuite::Compare::Container); +} + void GenerateIndicesTest::generateLineLoopIndicesWrongVertexCount() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedInt indices[1]; + std::ostringstream out; Error redirectError{&out}; MeshTools::generateLineLoopIndicesInto(1, nullptr); + MeshTools::generateLineLoopIndicesInto(indices, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two vertices, got 1\n"); + "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two vertices, got 1\n" + "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two indices, got 1\n"); } void GenerateIndicesTest::generateLineLoopIndicesIntoWrongSize() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedShort indices[5]; UnsignedInt output[9]; std::ostringstream out; Error redirectError{&out}; MeshTools::generateLineLoopIndicesInto(0, output); + MeshTools::generateLineLoopIndicesInto(Containers::arrayView(indices).prefix(std::size_t{}), output); MeshTools::generateLineLoopIndicesInto(5, output); + MeshTools::generateLineLoopIndicesInto(indices, output); CORRADE_COMPARE(out.str(), "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 0 but got 9\n" + "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 0 but got 9\n" + "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 10 but got 9\n" "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 10 but got 9\n"); } @@ -424,27 +541,78 @@ void GenerateIndicesTest::generateTriangleStripIndices() { }), TestSuite::Compare::Container); } +template void GenerateIndicesTest::generateTriangleStripIndicesIndexed() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + /* The second digit is 0, 1, 2, 3, 4, 5, 6, 7 for easier ordering. The + output in the second digit should then be the same as in + generateTriangleStripIndices() above. */ + T indexData[]{60, 21, 72, 93, 44, 85, 36, 17}; + auto indices = Containers::arrayView(indexData); + + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(indices.prefix(std::size_t{})), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(indices.prefix(3)), + Containers::arrayView({ + 60, 21, 72 + }), TestSuite::Compare::Container); + + /* Odd */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(indices.prefix(7)), + Containers::arrayView({ + 60, 21, 72, + 72, 21, 93, /* Reversed */ + 72, 93, 44, + 44, 93, 85, /* Reversed */ + 44, 85, 36 + }), TestSuite::Compare::Container); + + /* Even */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(indices), + Containers::arrayView({ + 60, 21, 72, + 72, 21, 93, /* Reversed */ + 72, 93, 44, + 44, 93, 85, /* Reversed */ + 44, 85, 36, + 36, 85, 17 /* Reversed */ + }), TestSuite::Compare::Container); +} + void GenerateIndicesTest::generateTriangleStripIndicesWrongVertexCount() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedByte indices[2]; + std::ostringstream out; Error redirectError{&out}; MeshTools::generateTriangleStripIndicesInto(2, nullptr); + MeshTools::generateTriangleStripIndicesInto(indices, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three vertices, got 2\n"); + "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three vertices, got 2\n" + "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three indices, got 2\n"); } void GenerateIndicesTest::generateTriangleStripIndicesIntoWrongSize() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedInt indices[5]; UnsignedInt output[8]; std::ostringstream out; Error redirectError{&out}; MeshTools::generateTriangleStripIndicesInto(0, output); + MeshTools::generateTriangleStripIndicesInto(Containers::arrayView(indices).prefix(std::size_t{}), output); MeshTools::generateTriangleStripIndicesInto(5, output); + MeshTools::generateTriangleStripIndicesInto(indices, output); CORRADE_COMPARE(out.str(), "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 0 but got 8\n" + "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 0 but got 8\n" + "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 9 but got 8\n" "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 9 but got 8\n"); } @@ -482,27 +650,78 @@ void GenerateIndicesTest::generateTriangleFanIndices() { }), TestSuite::Compare::Container); } +template void GenerateIndicesTest::generateTriangleFanIndicesIndexed() { + setTestCaseTemplateName(Math::TypeTraits::name()); + + /* The second digit is 0, 1, 2, 3, 4, 5, 6, 7 for easier ordering. The + output in the second digit should then be the same as in + generateTriangleFanIndices() above. */ + T indexData[]{60, 21, 72, 93, 44, 85, 36, 17}; + auto indices = Containers::arrayView(indexData); + + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(indices.prefix(std::size_t{})), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(indices.prefix(3)), + Containers::arrayView({ + 60, 21, 72 + }), TestSuite::Compare::Container); + + /* Odd */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(indices.prefix(7)), + Containers::arrayView({ + 60, 21, 72, + 60, 72, 93, + 60, 93, 44, + 60, 44, 85, + 60, 85, 36 + }), TestSuite::Compare::Container); + + /* Even */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(indices), + Containers::arrayView({ + 60, 21, 72, + 60, 72, 93, + 60, 93, 44, + 60, 44, 85, + 60, 85, 36, + 60, 36, 17 + }), TestSuite::Compare::Container); +} + void GenerateIndicesTest::generateTriangleFanIndicesWrongVertexCount() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedInt indices[2]; + std::ostringstream out; Error redirectError{&out}; MeshTools::generateTriangleFanIndicesInto(2, nullptr); + MeshTools::generateTriangleFanIndicesInto(indices, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three vertices, got 2\n"); + "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three vertices, got 2\n" + "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three indices, got 2\n"); } void GenerateIndicesTest::generateTriangleFanIndicesIntoWrongSize() { CORRADE_SKIP_IF_NO_ASSERT(); + UnsignedInt indices[5]; UnsignedInt output[8]; std::ostringstream out; Error redirectError{&out}; MeshTools::generateTriangleFanIndicesInto(0, output); + MeshTools::generateTriangleFanIndicesInto(Containers::arrayView(indices).prefix(std::size_t{}), output); MeshTools::generateTriangleFanIndicesInto(5, output); + MeshTools::generateTriangleFanIndicesInto(indices, output); CORRADE_COMPARE(out.str(), "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 0 but got 8\n" + "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 0 but got 8\n" + "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 9 but got 8\n" "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 9 but got 8\n"); }