diff --git a/doc/changelog.dox b/doc/changelog.dox index 8dd0ffb94..7fd25d432 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -544,6 +544,13 @@ See also: @ref Trade::MeshAttribute::Weights in @ref MeshTools::compile() as well as a new @ref MeshTools::compiledPerVertexJointCount() helper utility (see also [mosra/magnum#444](https://github.com/mosra/magnum/pull/444)) +- @ref MeshTools::generateLineStripIndices(), + @relativeref{MeshTools,generateLineLoopIndices()}, + @relativeref{MeshTools,generateTriangleStripIndices()}, + @relativeref{MeshTools,generateTriangleFanIndices()} and + @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. @subsubsection changelog-latest-changes-platform Platform libraries diff --git a/src/Magnum/MeshTools/GenerateIndices.cpp b/src/Magnum/MeshTools/GenerateIndices.cpp index 359640e88..1422ca359 100644 --- a/src/Magnum/MeshTools/GenerateIndices.cpp +++ b/src/Magnum/MeshTools/GenerateIndices.cpp @@ -58,10 +58,12 @@ UnsignedInt primitiveCount(const MeshPrimitive primitive, const UnsignedInt elem } void generateLineStripIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& indices) { - CORRADE_ASSERT(vertexCount >= 2, - "MeshTools::generateLineStripIndicesInto(): expected at least two vertices, got" << vertexCount, ); - CORRADE_ASSERT(indices.size() == 2*(vertexCount - 1), - "MeshTools::generateLineStripIndicesInto(): bad output size, expected" << 2*(vertexCount - 1) << "but got" << indices.size(), ); + CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 2, + "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two vertices, got" << vertexCount, ); + + const UnsignedInt iMax = Math::max(vertexCount, 1u) - 1; + CORRADE_ASSERT(indices.size() == 2*iMax, + "MeshTools::generateLineStripIndicesInto(): bad output size, expected" << 2*iMax << "but got" << indices.size(), ); /* 1 --- 2 1 2 --- 3 4 @@ -70,21 +72,21 @@ void generateLineStripIndicesInto(const UnsignedInt vertexCount, const Container / \ / \ 0 3 0 5 */ - for(std::size_t i = 0; i != vertexCount - 1; ++i) { + for(std::size_t i = 0; i != iMax; ++i) { indices[i*2 + 0] = i; indices[i*2 + 1] = i + 1; } } Containers::Array generateLineStripIndices(const UnsignedInt vertexCount) { - Containers::Array indices{NoInit, 2*(vertexCount - 1)}; + Containers::Array indices{NoInit, 2*(Math::max(vertexCount, 1u) - 1)}; generateLineStripIndicesInto(vertexCount, indices); return indices; } void generateLineLoopIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& indices) { - CORRADE_ASSERT(vertexCount >= 2, - "MeshTools::generateLineLoopIndicesInto(): expected at least two vertices, got" << vertexCount, ); + CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 2, + "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two vertices, got" << vertexCount, ); CORRADE_ASSERT(indices.size() == 2*vertexCount, "MeshTools::generateLineLoopIndicesInto(): bad output size, expected" << 2*vertexCount << "but got" << indices.size(), ); @@ -97,12 +99,14 @@ void generateLineLoopIndicesInto(const UnsignedInt vertexCount, const Containers / \ / \ 0 ----------- 3 0 7 ----------- 6 5 */ - for(std::size_t i = 0; i != vertexCount - 1; ++i) { + for(std::size_t i = 0, iMax = Math::max(vertexCount, 1u) - 1; i != iMax; ++i) { indices[i*2 + 0] = i; indices[i*2 + 1] = i + 1; } - indices[2*vertexCount - 2] = vertexCount - 1; - indices[2*vertexCount - 1] = 0; + if(vertexCount >= 2) { + indices[2*vertexCount - 2] = vertexCount - 1; + indices[2*vertexCount - 1] = 0; + } } Containers::Array generateLineLoopIndices(const UnsignedInt vertexCount) { @@ -112,10 +116,12 @@ Containers::Array generateLineLoopIndices(const UnsignedInt vertexC } void generateTriangleStripIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& indices) { - CORRADE_ASSERT(vertexCount >= 3, - "MeshTools::generateTriangleStripIndicesInto(): expected at least three vertices, got" << vertexCount, ); - CORRADE_ASSERT(indices.size() == 3*(vertexCount - 2), - "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected" << 3*(vertexCount - 2) << "but got" << indices.size(), ); + CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 3, + "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three vertices, got" << vertexCount, ); + + const UnsignedInt iMax = Math::max(vertexCount, 2u) - 2; + CORRADE_ASSERT(indices.size() == 3*iMax, + "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected" << 3*iMax << "but got" << indices.size(), ); /* Triangles starting with odd vertices (marked with !) have the first two @@ -127,7 +133,7 @@ void generateTriangleStripIndicesInto(const UnsignedInt vertexCount, const Conta \ / \ / \ \ / / ! \ \ / / ! \ 1 ----- 3 ----- 5 1 4 ----- 5 7 10 ---- 11 */ - for(std::size_t i = 0; i != vertexCount - 2; ++i) { + for(std::size_t i = 0; i != iMax; ++i) { indices[i*3 + 0] = i % 2 ? i + 1 : i; indices[i*3 + 1] = i % 2 ? i : i + 1; indices[i*3 + 2] = i + 2; @@ -135,16 +141,18 @@ void generateTriangleStripIndicesInto(const UnsignedInt vertexCount, const Conta } Containers::Array generateTriangleStripIndices(const UnsignedInt vertexCount) { - Containers::Array indices{NoInit, 3*(vertexCount - 2)}; + Containers::Array indices{NoInit, 3*(Math::max(vertexCount, 2u) - 2u)}; generateTriangleStripIndicesInto(vertexCount, indices); return indices; } void generateTriangleFanIndicesInto(const UnsignedInt vertexCount, const Containers::StridedArrayView1D& indices) { - CORRADE_ASSERT(vertexCount >= 3, - "MeshTools::generateTriangleFanIndicesInto(): expected at least three vertices, got" << vertexCount, ); - CORRADE_ASSERT(indices.size() == 3*(vertexCount - 2), - "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected" << 3*(vertexCount - 2) << "but got" << indices.size(), ); + CORRADE_ASSERT(vertexCount == 0 || vertexCount >= 3, + "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three vertices, got" << vertexCount, ); + + const UnsignedInt iMax = Math::max(vertexCount, 2u) - 2; + CORRADE_ASSERT(indices.size() == 3*iMax, + "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected" << 3*iMax << "but got" << indices.size(), ); /* 10 8 ----- 7 5 4 ----- 3 / \ \ / / \ @@ -157,7 +165,7 @@ void generateTriangleFanIndicesInto(const UnsignedInt vertexCount, const Contain \ / \ / 1 1 */ - for(std::size_t i = 0; i != vertexCount - 2; ++i) { + for(std::size_t i = 0; i != iMax; ++i) { indices[i*3 + 0] = 0; indices[i*3 + 1] = i + 1; indices[i*3 + 2] = i + 2; @@ -165,7 +173,7 @@ void generateTriangleFanIndicesInto(const UnsignedInt vertexCount, const Contain } Containers::Array generateTriangleFanIndices(const UnsignedInt vertexCount) { - Containers::Array indices{NoInit, 3*(vertexCount - 2)}; + Containers::Array indices{NoInit, 3*(Math::max(vertexCount, 2u) - 2)}; generateTriangleFanIndicesInto(vertexCount, indices); return indices; } @@ -286,8 +294,8 @@ Trade::MeshData generateIndices(Trade::MeshData&& data) { minVertexCount = 3; } else CORRADE_ASSERT_UNREACHABLE("MeshTools::generateIndices(): invalid primitive" << data.primitive(), (Trade::MeshData{MeshPrimitive::Triangles, 0})); - CORRADE_ASSERT(vertexCount >= minVertexCount, - "MeshTools::generateIndices(): expected at least" << minVertexCount << "vertices for" << data.primitive() << Debug::nospace << ", got" << vertexCount, + CORRADE_ASSERT(vertexCount == 0 || vertexCount >= minVertexCount, + "MeshTools::generateIndices(): expected either zero or at least" << minVertexCount << "vertices for" << data.primitive() << Debug::nospace << ", got" << vertexCount, (Trade::MeshData{MeshPrimitive::Triangles, 0})); #endif @@ -317,7 +325,7 @@ Trade::MeshData generateIndices(Trade::MeshData&& data) { Containers::Array indexData; if(data.primitive() == MeshPrimitive::LineStrip) { primitive = MeshPrimitive::Lines; - indexData = Containers::Array{NoInit, 2*(vertexCount - 1)*sizeof(UnsignedInt)}; + indexData = Containers::Array{NoInit, 2*(Math::max(vertexCount, 1u) - 1)*sizeof(UnsignedInt)}; generateLineStripIndicesInto(vertexCount, Containers::arrayCast(indexData)); } else if(data.primitive() == MeshPrimitive::LineLoop) { primitive = MeshPrimitive::Lines; @@ -325,11 +333,11 @@ Trade::MeshData generateIndices(Trade::MeshData&& data) { generateLineLoopIndicesInto(vertexCount, Containers::arrayCast(indexData)); } else if(data.primitive() == MeshPrimitive::TriangleStrip) { primitive = MeshPrimitive::Triangles; - indexData = Containers::Array{NoInit, 3*(vertexCount - 2)*sizeof(UnsignedInt)}; + indexData = Containers::Array{NoInit, 3*(Math::max(vertexCount, 2u) - 2)*sizeof(UnsignedInt)}; generateTriangleStripIndicesInto(vertexCount, Containers::arrayCast(indexData)); } else if(data.primitive() == MeshPrimitive::TriangleFan) { primitive = MeshPrimitive::Triangles; - indexData = Containers::Array{NoInit, 3*(vertexCount - 2)*sizeof(UnsignedInt)}; + indexData = Containers::Array{NoInit, 3*(Math::max(vertexCount, 2u) - 2)*sizeof(UnsignedInt)}; generateTriangleFanIndicesInto(vertexCount, Containers::arrayCast(indexData)); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ diff --git a/src/Magnum/MeshTools/GenerateIndices.h b/src/Magnum/MeshTools/GenerateIndices.h index 148f3de71..dbcd2532e 100644 --- a/src/Magnum/MeshTools/GenerateIndices.h +++ b/src/Magnum/MeshTools/GenerateIndices.h @@ -53,8 +53,8 @@ MAGNUM_MESHTOOLS_EXPORT UnsignedInt primitiveCount(MeshPrimitive primitive, Unsi @m_since{2020,06} Can be used to convert a @ref MeshPrimitive::LineStrip mesh to -@ref MeshPrimitive::Lines. The @p vertexCount is expected to be at least -@cpp 2 @ce. Primitive restart is not supported. +@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. @see @ref generateLineStripIndicesInto(), @ref generateLineLoopIndices(), @ref generateTriangleStripIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() @@ -66,9 +66,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineStripIndices( @m_since{2020,06} A variant of @ref generateLineStripIndicesInto() that fills existing memory -instead of allocating a new array. The @p vertexCount is expected to be at -least @cpp 2 @ce, the @p indices array is expected to have a size of -@cpp 2*(vertexCount - 1) @ce. Primitive restart is not supported. +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 indices array is expected to have a +size of @cpp 2*(vertexCount - 1) @ce. Primitive restart is not supported. */ MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& indices); @@ -77,8 +77,8 @@ MAGNUM_MESHTOOLS_EXPORT void generateLineStripIndicesInto(UnsignedInt vertexCoun @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 at least -@cpp 2 @ce. Primitive restart is not supported. +@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. @see @ref generateLineLoopIndicesInto(), @ref generateLineStripIndices(), @ref generateTriangleStripIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() @@ -90,9 +90,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateLineLoopIndices(U @m_since{2020,06} A variant of @ref generateLineLoopIndicesInto() that fills existing memory -instead of allocating a new array. The @p vertexCount is expected to be at -least @cpp 2 @ce, the @p indices array is expected to have a size of -@cpp 2*vertexCount @ce. Primitive restart is not supported. +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 indices array is expected to have a +size of @cpp 2*vertexCount @ce. Primitive restart is not supported. */ MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& into); @@ -101,8 +101,8 @@ MAGNUM_MESHTOOLS_EXPORT void generateLineLoopIndicesInto(UnsignedInt vertexCount @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 at least -@cpp 3 @ce. Primitive restart is not supported. +@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. @see @ref generateTriangleStripIndicesInto(), @ref generateLineStripIndices(), @ref generateLineLoopIndices(), @ref generateTriangleFanIndices(), @ref generateIndices() @@ -114,9 +114,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleStripIndi @m_since{2020,06} A variant of @ref generateTriangleStripIndicesInto() that fills existing memory -instead of allocating a new array. The @p vertexCount is expected to be at -least @cpp 3 @ce, the @p indices array is expected to have a size of -@cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. +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 indices array is expected to have a +size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. */ MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& into); @@ -125,8 +125,8 @@ MAGNUM_MESHTOOLS_EXPORT void generateTriangleStripIndicesInto(UnsignedInt vertex @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 at least -@cpp 3 @ce. Primitive restart is not supported. +@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. @see @ref generateTriangleFanIndicesInto(), @ref generateLineStripIndices(), @ref generateLineLoopIndices(), @ref generateTriangleStripIndices(), @ref generateIndices() @@ -138,9 +138,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Array generateTriangleFanIndice @m_since{2020,06} A variant of @ref generateTriangleFanIndicesInto() that fills existing memory -instead of allocating a new array. The @p vertexCount is expected to be at -least @cpp 3 @ce, the @p indices array is expected to have a size of -@cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. +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 indices array is expected to have a +size of @cpp 3*(vertexCount - 2) @ce. Primitive restart is not supported. */ MAGNUM_MESHTOOLS_EXPORT void generateTriangleFanIndicesInto(UnsignedInt vertexCount, const Containers::StridedArrayView1D& into); @@ -214,9 +214,9 @@ MAGNUM_MESHTOOLS_EXPORT void generateQuadIndicesInto(const Containers::StridedAr Expects that @p mesh is not indexed, is one of @ref MeshPrimitive::LineStrip, @ref MeshPrimitive::LineLoop, @ref MeshPrimitive::TriangleStrip, @ref MeshPrimitive::TriangleFan primitives -and has at least @cpp 2 @ce vertices for a line-based primitive or @cpp 3 @ce -vertices for a triangle-based primitive. Calls one of -@ref generateLineStripIndices(), @ref generateLineLoopIndices(), +and has either @cpp 0 @ce vertices or at least @cpp 2 @ce vertices for a +line-based primitive or @cpp 3 @ce vertices for a triangle-based primitive. +Calls one of @ref generateLineStripIndices(), @ref generateLineLoopIndices(), @ref generateTriangleStripIndices() or @ref generateTriangleFanIndices() functions to generate the index buffer. If your mesh is indexed, call @ref duplicate(const Trade::MeshData& data, Containers::ArrayView) diff --git a/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp b/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp index 5bbb1f3d5..c003a4da6 100644 --- a/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp +++ b/src/Magnum/MeshTools/Test/GenerateIndicesTest.cpp @@ -67,6 +67,7 @@ struct GenerateIndicesTest: TestSuite::Tester { void generateQuadIndicesIntoWrongSize(); void generateIndicesMeshData(); + void generateIndicesMeshDataEmpty(); void generateIndicesMeshDataMove(); void generateIndicesMeshDataNoAttributes(); void generateIndicesMeshDataIndexed(); @@ -205,7 +206,8 @@ GenerateIndicesTest::GenerateIndicesTest() { &GenerateIndicesTest::generateQuadIndicesIndexOutOfBounds, &GenerateIndicesTest::generateQuadIndicesIntoWrongSize}); - addInstancedTests({&GenerateIndicesTest::generateIndicesMeshData}, + addInstancedTests({&GenerateIndicesTest::generateIndicesMeshData, + &GenerateIndicesTest::generateIndicesMeshDataEmpty}, Containers::arraySize(MeshDataData)); addTests({&GenerateIndicesTest::generateIndicesMeshDataMove, @@ -255,7 +257,12 @@ void GenerateIndicesTest::primitiveCountInvalidPrimitive() { } void GenerateIndicesTest::generateLineStripIndices() { - /* Minimal input */ + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(0), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ CORRADE_COMPARE_AS(MeshTools::generateLineStripIndices(2), Containers::arrayView({ 0, 1 @@ -288,7 +295,7 @@ void GenerateIndicesTest::generateLineStripIndicesWrongVertexCount() { Error redirectError{&out}; MeshTools::generateLineStripIndicesInto(1, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateLineStripIndicesInto(): expected at least two vertices, got 1\n"); + "MeshTools::generateLineStripIndicesInto(): expected either zero or at least two vertices, got 1\n"); } void GenerateIndicesTest::generateLineStripIndicesIntoWrongSize() { @@ -298,13 +305,20 @@ void GenerateIndicesTest::generateLineStripIndicesIntoWrongSize() { std::ostringstream out; Error redirectError{&out}; + MeshTools::generateLineStripIndicesInto(0, indices); MeshTools::generateLineStripIndicesInto(5, indices); CORRADE_COMPARE(out.str(), + "MeshTools::generateLineStripIndicesInto(): bad output size, expected 0 but got 7\n" "MeshTools::generateLineStripIndicesInto(): bad output size, expected 8 but got 7\n"); } void GenerateIndicesTest::generateLineLoopIndices() { - /* Minimal input */ + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(0), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ CORRADE_COMPARE_AS(MeshTools::generateLineLoopIndices(2), Containers::arrayView({ 0, 1, @@ -340,7 +354,7 @@ void GenerateIndicesTest::generateLineLoopIndicesWrongVertexCount() { Error redirectError{&out}; MeshTools::generateLineLoopIndicesInto(1, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateLineLoopIndicesInto(): expected at least two vertices, got 1\n"); + "MeshTools::generateLineLoopIndicesInto(): expected either zero or at least two vertices, got 1\n"); } void GenerateIndicesTest::generateLineLoopIndicesIntoWrongSize() { @@ -350,13 +364,20 @@ void GenerateIndicesTest::generateLineLoopIndicesIntoWrongSize() { std::ostringstream out; Error redirectError{&out}; + MeshTools::generateLineLoopIndicesInto(0, indices); MeshTools::generateLineLoopIndicesInto(5, indices); CORRADE_COMPARE(out.str(), + "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 0 but got 9\n" "MeshTools::generateLineLoopIndicesInto(): bad output size, expected 10 but got 9\n"); } void GenerateIndicesTest::generateTriangleStripIndices() { - /* Minimal input */ + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(0), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ CORRADE_COMPARE_AS(MeshTools::generateTriangleStripIndices(3), Containers::arrayView({ 0, 1, 2 @@ -391,7 +412,7 @@ void GenerateIndicesTest::generateTriangleStripIndicesWrongVertexCount() { Error redirectError{&out}; MeshTools::generateTriangleStripIndicesInto(2, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateTriangleStripIndicesInto(): expected at least three vertices, got 2\n"); + "MeshTools::generateTriangleStripIndicesInto(): expected either zero or at least three vertices, got 2\n"); } void GenerateIndicesTest::generateTriangleStripIndicesIntoWrongSize() { @@ -401,13 +422,20 @@ void GenerateIndicesTest::generateTriangleStripIndicesIntoWrongSize() { std::ostringstream out; Error redirectError{&out}; + MeshTools::generateTriangleStripIndicesInto(0, indices); MeshTools::generateTriangleStripIndicesInto(5, indices); CORRADE_COMPARE(out.str(), + "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 0 but got 8\n" "MeshTools::generateTriangleStripIndicesInto(): bad output size, expected 9 but got 8\n"); } void GenerateIndicesTest::generateTriangleFanIndices() { - /* Minimal input */ + /* Empty input */ + CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(0), + Containers::ArrayView{}, + TestSuite::Compare::Container); + + /* Minimal non-empty input */ CORRADE_COMPARE_AS(MeshTools::generateTriangleFanIndices(3), Containers::arrayView({ 0, 1, 2 @@ -442,7 +470,7 @@ void GenerateIndicesTest::generateTriangleFanIndicesWrongVertexCount() { Error redirectError{&out}; MeshTools::generateTriangleFanIndicesInto(2, nullptr); CORRADE_COMPARE(out.str(), - "MeshTools::generateTriangleFanIndicesInto(): expected at least three vertices, got 2\n"); + "MeshTools::generateTriangleFanIndicesInto(): expected either zero or at least three vertices, got 2\n"); } void GenerateIndicesTest::generateTriangleFanIndicesIntoWrongSize() { @@ -452,8 +480,10 @@ void GenerateIndicesTest::generateTriangleFanIndicesIntoWrongSize() { std::ostringstream out; Error redirectError{&out}; + MeshTools::generateTriangleFanIndicesInto(0, indices); MeshTools::generateTriangleFanIndicesInto(5, indices); CORRADE_COMPARE(out.str(), + "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 0 but got 8\n" "MeshTools::generateTriangleFanIndicesInto(): bad output size, expected 9 but got 8\n"); } @@ -654,6 +684,42 @@ void GenerateIndicesTest::generateIndicesMeshData() { }), TestSuite::Compare::Container); } +void GenerateIndicesTest::generateIndicesMeshDataEmpty() { + auto&& data = MeshDataData[testCaseInstanceId()]; + { + std::ostringstream out; + Debug{&out, Debug::Flag::NoNewlineAtTheEnd} << data.primitive; + setTestCaseDescription(out.str()); + } + + /* Similar to generateIndicesMeshData(), just with 0 vertices. Verifying it + doesn't crash anywhere and produces an empty mesh as well. */ + + struct Vertex { + Vector2 position; + Short data[2]; + Vector2 textureCoordinates; + }; + Containers::StridedArrayView1D vertices; + + Trade::MeshData mesh{data.primitive, {}, nullptr, { + Trade::MeshAttributeData{Trade::MeshAttribute::Position, + vertices.slice(&Vertex::position)}, + /* Array attribute to verify it's correctly propagated */ + Trade::MeshAttributeData{Trade::meshAttributeCustom(42), + VertexFormat::Short, + vertices.slice(&Vertex::data), 2}, + Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, + vertices.slice(&Vertex::textureCoordinates)} + }}; + + Trade::MeshData out = generateIndices(mesh); + CORRADE_VERIFY(out.isIndexed()); + CORRADE_COMPARE(out.indexCount(), 0); + CORRADE_COMPARE(out.attributeCount(), 3); + CORRADE_COMPARE(out.vertexCount(), 0); +} + void GenerateIndicesTest::generateIndicesMeshDataMove() { struct Vertex { Vector2 position; @@ -762,7 +828,7 @@ void GenerateIndicesTest::generateIndicesMeshDataInvalidVertexCount() { Error redirectError{&out}; generateIndices(mesh); CORRADE_COMPARE(out.str(), Utility::formatString( - "MeshTools::generateIndices(): expected at least {} vertices for {}, got {}\n", data.expectedVertexCount, primitiveName.str(), data.invalidVertexCount)); + "MeshTools::generateIndices(): expected either zero or at least {} vertices for {}, got {}\n", data.expectedVertexCount, primitiveName.str(), data.invalidVertexCount)); } }}}}