diff --git a/src/Magnum/MeshTools/CompressIndices.cpp b/src/Magnum/MeshTools/CompressIndices.cpp index c5579588b..12ba8774c 100644 --- a/src/Magnum/MeshTools/CompressIndices.cpp +++ b/src/Magnum/MeshTools/CompressIndices.cpp @@ -165,8 +165,6 @@ Trade::MeshData compressIndices(Trade::MeshData&& data, MeshIndexType atLeast) { } Trade::MeshData compressIndices(const Trade::MeshData& data, MeshIndexType atLeast) { - CORRADE_ASSERT(data.isIndexed(), "MeshTools::compressIndices(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0})); - return compressIndices(Trade::MeshData{data.primitive(), {}, data.indexData(), Trade::MeshIndexData{data.indices()}, {}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()), diff --git a/src/Magnum/MeshTools/Concatenate.cpp b/src/Magnum/MeshTools/Concatenate.cpp index ea08e5ed9..3ad883dc7 100644 --- a/src/Magnum/MeshTools/Concatenate.cpp +++ b/src/Magnum/MeshTools/Concatenate.cpp @@ -226,15 +226,9 @@ Trade::MeshData concatenate(Trade::MeshData&& first, std::initializer_list> next) { - Containers::ArrayView indexData; - Trade::MeshIndexData indices; - if(first.isIndexed()) { - indexData = first.indexData(); - indices = Trade::MeshIndexData{first.indices()}; - } - return concatenate(Trade::MeshData{first.primitive(), - {}, indexData, indices, + /* If data is not indexed, the reference will be also non-indexed */ + {}, first.indexData(), Trade::MeshIndexData{first.indices()}, {}, first.vertexData(), Trade::meshAttributeDataNonOwningArray(first.attributeData()), first.vertexCount(), }, next); diff --git a/src/Magnum/MeshTools/GenerateIndices.cpp b/src/Magnum/MeshTools/GenerateIndices.cpp index 1c6ebdcce..23786cbb1 100644 --- a/src/Magnum/MeshTools/GenerateIndices.cpp +++ b/src/Magnum/MeshTools/GenerateIndices.cpp @@ -222,11 +222,11 @@ Trade::MeshData generateIndices(Trade::MeshData&& data) { } Trade::MeshData generateIndices(const Trade::MeshData& data) { - CORRADE_ASSERT(!data.isIndexed(), - "MeshTools::generateIndices(): mesh data already indexed", - (Trade::MeshData{MeshPrimitive::Triangles, 0})); - return generateIndices(Trade::MeshData{data.primitive(), + /* Passing the indices through. If the mesh isn't indexed, this makes + the reference non-indexed also, if the mesh is indexed, it causes an + assert inside the delegated generateIndices(). */ + {}, data.indexData(), Trade::MeshIndexData{data.indices()}, {}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()), data.vertexCount()}); } diff --git a/src/Magnum/MeshTools/Interleave.cpp b/src/Magnum/MeshTools/Interleave.cpp index 5c9ec82e5..f8965fe99 100644 --- a/src/Magnum/MeshTools/Interleave.cpp +++ b/src/Magnum/MeshTools/Interleave.cpp @@ -301,15 +301,9 @@ Trade::MeshData interleave(Trade::MeshData&& data, const std::initializer_list extra) { - Containers::ArrayView indexData; - Trade::MeshIndexData indices; - if(data.isIndexed()) { - indexData = data.indexData(); - indices = Trade::MeshIndexData{data.indices()}; - } - return interleave(Trade::MeshData{data.primitive(), - {}, indexData, indices, + /* If data is not indexed, the reference will be also non-indexed */ + {}, data.indexData(), Trade::MeshIndexData{data.indices()}, {}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()), data.vertexCount() }, extra); diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index a4a949bc2..01701d014 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -42,6 +42,12 @@ MeshIndexData::MeshIndexData(const MeshIndexType type, const Containers::ArrayVi } MeshIndexData::MeshIndexData(const Containers::StridedArrayView2D& data) noexcept { + /* Second dimension being zero indicates a non-indexed mesh */ + if(data.size()[1] == 0) { + _type = MeshIndexType{}; + return; + } + if(data.size()[1] == 4) _type = MeshIndexType::UnsignedInt; else if(data.size()[1] == 2) _type = MeshIndexType::UnsignedShort; else if(data.size()[1] == 1) _type = MeshIndexType::UnsignedByte; @@ -230,8 +236,9 @@ std::size_t MeshData::indexOffset() const { } Containers::StridedArrayView2D MeshData::indices() const { - CORRADE_ASSERT(isIndexed(), - "Trade::MeshData::indices(): the mesh is not indexed", {}); + /* For a non-indexed mesh returning zero size in both dimensions, indexed + mesh with zero indices sill has the second dimension non-zero */ + if(!isIndexed()) return {}; const std::size_t indexTypeSize = meshIndexTypeSize(_indexType); /* Build a 2D view using information about attribute type size */ return {{_indices, _indexCount*indexTypeSize}, {_indexCount, indexTypeSize}}; @@ -240,8 +247,9 @@ Containers::StridedArrayView2D MeshData::indices() const { Containers::StridedArrayView2D MeshData::mutableIndices() { CORRADE_ASSERT(_indexDataFlags & DataFlag::Mutable, "Trade::MeshData::mutableIndices(): index data not mutable", {}); - CORRADE_ASSERT(isIndexed(), - "Trade::MeshData::mutableIndices(): the mesh is not indexed", {}); + /* For a non-indexed mesh returning zero size in both dimensions, indexed + mesh with zero indices sill has the second dimension non-zero */ + if(!isIndexed()) return {}; const std::size_t indexTypeSize = meshIndexTypeSize(_indexType); /* Build a 2D view using information about index type size */ Containers::StridedArrayView2D out{{_indices, _indexCount*indexTypeSize}, {_indexCount, indexTypeSize}}; diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index d3946bf28..bf8257690 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -265,7 +265,8 @@ class MAGNUM_TRADE_EXPORT MeshIndexData { * * Expects that @p data is contiguous and size of the second dimension * is either 1, 2 or 4, corresponding to one of the @ref MeshIndexType - * values. + * values. As a special case, if second dimension size is 0, the + * constructor is equivalent to @ref MeshIndexData(std::nullptr_t). */ explicit MeshIndexData(const Containers::StridedArrayView2D& data) noexcept; @@ -1093,8 +1094,11 @@ class MAGNUM_TRADE_EXPORT MeshData { /** * @brief Mesh indices * - * The view is guaranteed to be contiguous and its second dimension - * represents the actual data type (its size is equal to type size). + * For an indexed mesh, the view is guaranteed to be contiguous and its + * second dimension represents the actual data type (its size is equal + * to type size, even in case there's zero indices). For a non-indexed + * mesh, the returned view has a zero size in both dimensions. + * * Use the templated overload below to get the indices in a concrete * type. * @see @ref Corrade::Containers::StridedArrayView::isContiguous() @@ -2107,6 +2111,8 @@ template constexpr MeshAttributeData::MeshAttributeData(MeshAttribute n template constexpr MeshAttributeData::MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView2D& data) noexcept: MeshAttributeData{name, Implementation::vertexFormatFor::type>(), UnsignedShort(data.size()[1]), Containers::StridedArrayView1D{{data.data(), ~std::size_t{}}, data.size()[0], data.stride()[0]}, (CORRADE_CONSTEXPR_ASSERT(data.stride()[1] == sizeof(T), "Trade::MeshAttributeData: second view dimension is not contiguous"), nullptr)} {} template Containers::ArrayView MeshData::indices() const { + CORRADE_ASSERT(isIndexed(), + "Trade::MeshData::indices(): the mesh is not indexed", {}); Containers::StridedArrayView2D data = indices(); #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ if(!data.stride()[1]) return {}; @@ -2117,6 +2123,8 @@ template Containers::ArrayView MeshData::indices() const { } template Containers::ArrayView MeshData::mutableIndices() { + CORRADE_ASSERT(isIndexed(), + "Trade::MeshData::mutableIndices(): the mesh is not indexed", {}); Containers::StridedArrayView2D data = mutableIndices(); #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ if(!data.stride()[1]) return {}; diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index 301d305f4..07a89b6e0 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -46,6 +46,7 @@ struct MeshDataTest: TestSuite::Tester { void constructIndexTypeErased(); void constructIndexTypeErasedWrongSize(); void constructIndex2D(); + void constructIndex2DNotIndexed(); void constructIndex2DWrongSize(); void constructIndex2DNonContiguous(); void constructIndexNullptr(); @@ -204,6 +205,7 @@ MeshDataTest::MeshDataTest() { &MeshDataTest::constructIndexTypeErased, &MeshDataTest::constructIndexTypeErasedWrongSize, &MeshDataTest::constructIndex2D, + &MeshDataTest::constructIndex2DNotIndexed, &MeshDataTest::constructIndex2DWrongSize, &MeshDataTest::constructIndex2DNonContiguous, &MeshDataTest::constructIndexNullptr, @@ -516,6 +518,12 @@ void MeshDataTest::constructIndex2D() { } } +void MeshDataTest::constructIndex2DNotIndexed() { + MeshIndexData indices{Containers::StridedArrayView2D{}}; + CORRADE_COMPARE(indices.type(), MeshIndexType{}); + CORRADE_COMPARE(indices.data().data(), nullptr); +} + void MeshDataTest::constructIndex2DWrongSize() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -1192,6 +1200,8 @@ void MeshDataTest::constructZeroIndices() { CORRADE_VERIFY(data.isIndexed()); CORRADE_COMPARE(data.indexType(), MeshIndexType::UnsignedInt); CORRADE_COMPARE(data.indexCount(), 0); + CORRADE_COMPARE(data.indices().size(), (Containers::StridedArrayView2D::Size{0, 4})); + CORRADE_COMPARE(data.mutableIndices().size(), (Containers::StridedArrayView2D::Size{0, 4})); CORRADE_COMPARE(data.vertexCount(), 3); } @@ -1249,10 +1259,18 @@ void MeshDataTest::constructIndexless() { default */ CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_COMPARE(data.primitive(), MeshPrimitive::LineLoop); - CORRADE_COMPARE(data.indexData(), nullptr); CORRADE_COMPARE(data.importerState(), &importerState); + /* Access to indexData() and typeless access to (mutable)indices() is + allowed, to allow creation of MeshData instances referencing other + MeshData without having to branch on isIndexed(). */ CORRADE_VERIFY(!data.isIndexed()); + CORRADE_COMPARE(data.indexData(), nullptr); + CORRADE_COMPARE(data.indices().data(), nullptr); + CORRADE_COMPARE(data.indices().size(), (Containers::StridedArrayView2D::Size{0, 0})); + CORRADE_COMPARE(data.mutableIndices().data(), nullptr); + CORRADE_COMPARE(data.mutableIndices().size(), (Containers::StridedArrayView2D::Size{0, 0})); + CORRADE_COMPARE(data.vertexCount(), 3); CORRADE_COMPARE(data.attributeCount(), 1); CORRADE_COMPARE(data.attributeFormat(MeshAttribute::Position), VertexFormat::Vector2); @@ -2777,8 +2795,8 @@ void MeshDataTest::indicesNotIndexed() { data.indexCount(); data.indexType(); data.indexOffset(); - data.indices(); data.indices(); + data.mutableIndices(); data.indicesAsArray(); UnsignedInt a[1]; data.indicesInto(a); @@ -2787,7 +2805,7 @@ void MeshDataTest::indicesNotIndexed() { "Trade::MeshData::indexType(): the mesh is not indexed\n" "Trade::MeshData::indexOffset(): the mesh is not indexed\n" "Trade::MeshData::indices(): the mesh is not indexed\n" - "Trade::MeshData::indices(): the mesh is not indexed\n" + "Trade::MeshData::mutableIndices(): the mesh is not indexed\n" "Trade::MeshData::indicesAsArray(): the mesh is not indexed\n" "Trade::MeshData::indicesInto(): the mesh is not indexed\n"); }