From 27f6cc309d4636adb0f65e559de8e5cc109483cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 7 Mar 2020 14:28:12 +0100 Subject: [PATCH] Trade: allow specifying explicit vertex count on MeshData construction. Until now, except for an attribute-less index-less mesh, the vertex count was only implicitly taken from passed attributes, but it was severely limiting: - There was no way to set vertex count for an attribute-less indexed mesh, which didn't make sense - All code that made non-owning MeshData instances referencing another MeshData had to explicitly handle the attribute-less corner case to avoid vertex count getting lost - Offset-only attributes couldn't be used to specify static layout of meshes with dynamic vertex count, causing unnecessary extra allocations especially in the Primitives library. --- src/Magnum/MeshTools/Combine.cpp | 4 +- src/Magnum/MeshTools/Interleave.cpp | 18 +- src/Magnum/MeshTools/Test/CombineTest.cpp | 22 +- src/Magnum/MeshTools/Test/DuplicateTest.cpp | 4 +- src/Magnum/Trade/MeshData.cpp | 65 +++-- src/Magnum/Trade/MeshData.h | 91 +++++-- .../Trade/Test/AbstractImporterTest.cpp | 6 +- src/Magnum/Trade/Test/MeshData2DTest.cpp | 4 +- src/Magnum/Trade/Test/MeshData3DTest.cpp | 4 +- src/Magnum/Trade/Test/MeshDataTest.cpp | 244 +++++++++++------- 10 files changed, 280 insertions(+), 182 deletions(-) diff --git a/src/Magnum/MeshTools/Combine.cpp b/src/Magnum/MeshTools/Combine.cpp index d099a90e3..8ec259769 100644 --- a/src/Magnum/MeshTools/Combine.cpp +++ b/src/Magnum/MeshTools/Combine.cpp @@ -91,7 +91,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::ArrayView indexData{indexCount*sizeof(UnsignedInt)}; const auto indexDataI = Containers::arrayCast(indexData); - const std::size_t vertexCount = removeDuplicatesInPlaceInto( + const UnsignedInt vertexCount = removeDuplicatesInPlaceInto( Containers::StridedArrayView2D{combinedIndices, {indexCount, indexStride}}, indexDataI); @@ -133,7 +133,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::ArrayView> data) { diff --git a/src/Magnum/MeshTools/Interleave.cpp b/src/Magnum/MeshTools/Interleave.cpp index d73e827e8..ad629adb5 100644 --- a/src/Magnum/MeshTools/Interleave.cpp +++ b/src/Magnum/MeshTools/Interleave.cpp @@ -154,14 +154,10 @@ Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vert } Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const Containers::ArrayView extra) { - /* If there's no attributes in the original mesh, we need to pass vertex - count explicitly (MeshData asserts on that to avoid it getting lost.) */ - if(!data.attributeCount()) - return interleavedLayout(Trade::MeshData{data.primitive(), data.vertexCount()}, vertexCount, extra); - return interleavedLayout( Trade::MeshData{data.primitive(), {}, data.vertexData(), - Trade::meshAttributeDataNonOwningArray(data.attributeData())}, + Trade::meshAttributeDataNonOwningArray(data.attributeData()), + data.vertexCount()}, vertexCount, extra); } @@ -257,19 +253,13 @@ Trade::MeshData interleave(const Trade::MeshData& data, const Containers::ArrayV if(data.isIndexed()) { indexData = data.indexData(); indices = Trade::MeshIndexData{data.indices()}; - - /* If there's neither an index array nor any attributes in the original - mesh, we need to pass vertex count explicitly (MeshData asserts on that - to avoid it getting lost.) */ - } else if(!data.attributeCount()) { - return interleave(Trade::MeshData{data.primitive(), data.vertexCount()}, extra); } return interleave(Trade::MeshData{data.primitive(), {}, indexData, indices, - {}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()) + {}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()), + data.vertexCount() }, extra); - } Trade::MeshData interleave(const Trade::MeshData& data, const std::initializer_list extra) { diff --git a/src/Magnum/MeshTools/Test/CombineTest.cpp b/src/Magnum/MeshTools/Test/CombineTest.cpp index db91dbd09..4be6f8967 100644 --- a/src/Magnum/MeshTools/Test/CombineTest.cpp +++ b/src/Magnum/MeshTools/Test/CombineTest.cpp @@ -107,11 +107,11 @@ void CombineTest::combineIndexedAttributesIndicesOnly() { const UnsignedShort indicesB[]{3, 4, 3}; const UnsignedByte indicesC[]{7, 6, 7}; Trade::MeshData a{MeshPrimitive::LineLoop, {}, indicesA, - Trade::MeshIndexData{indicesA}}; + Trade::MeshIndexData{indicesA}, 3}; Trade::MeshData b{MeshPrimitive::LineLoop, {}, indicesB, - Trade::MeshIndexData{indicesB}}; + Trade::MeshIndexData{indicesB}, 5}; Trade::MeshData c{MeshPrimitive::LineLoop, {}, indicesC, - Trade::MeshIndexData{indicesC}}; + Trade::MeshIndexData{indicesC}, 8}; Trade::MeshData result = MeshTools::combineIndexedAttributes({a, b, c}); CORRADE_COMPARE(result.primitive(), MeshPrimitive::LineLoop); @@ -121,7 +121,7 @@ void CombineTest::combineIndexedAttributesIndicesOnly() { Containers::arrayView({0, 1, 0}), TestSuite::Compare::Container); CORRADE_COMPARE(result.attributeCount(), 0); - CORRADE_COMPARE(result.vertexCount(), 0); + CORRADE_COMPARE(result.vertexCount(), 2); } void CombineTest::combineIndexedAttributesNoMeshes() { @@ -134,9 +134,9 @@ void CombineTest::combineIndexedAttributesNoMeshes() { void CombineTest::combineIndexedAttributesNotIndexed() { const UnsignedShort indices[5]{}; Trade::MeshData a{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; Trade::MeshData b{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; Trade::MeshData c{MeshPrimitive::Lines, 5}; std::ostringstream out; @@ -148,9 +148,9 @@ void CombineTest::combineIndexedAttributesNotIndexed() { void CombineTest::combineIndexedAttributesDifferentPrimitive() { const UnsignedShort indices[5]{}; Trade::MeshData a{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; Trade::MeshData b{MeshPrimitive::Points, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; std::ostringstream out; Error redirectError{&out}; @@ -161,12 +161,12 @@ void CombineTest::combineIndexedAttributesDifferentPrimitive() { void CombineTest::combineIndexedAttributesDifferentIndexCount() { const UnsignedShort indices[5]{}; Trade::MeshData a{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; Trade::MeshData b{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 1}; Trade::MeshData c{MeshPrimitive::Lines, {}, indices, - Trade::MeshIndexData{Containers::arrayView(indices).prefix(4)}}; + Trade::MeshIndexData{Containers::arrayView(indices).prefix(4)}, 1}; std::ostringstream out; Error redirectError{&out}; diff --git a/src/Magnum/MeshTools/Test/DuplicateTest.cpp b/src/Magnum/MeshTools/Test/DuplicateTest.cpp index 058373e05..8f638a942 100644 --- a/src/Magnum/MeshTools/Test/DuplicateTest.cpp +++ b/src/Magnum/MeshTools/Test/DuplicateTest.cpp @@ -372,7 +372,7 @@ void DuplicateTest::duplicateMeshDataExtraWrongCount() { void DuplicateTest::duplicateMeshDataExtraOffsetOnly() { UnsignedByte indices[]{0, 1, 2, 2, 1, 0}; Trade::MeshData data{MeshPrimitive::TriangleFan, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 3}; std::ostringstream out; Error redirectError{&out}; @@ -386,7 +386,7 @@ void DuplicateTest::duplicateMeshDataExtraOffsetOnly() { void DuplicateTest::duplicateMeshDataNoAttributes() { UnsignedByte indices[]{0, 1, 2, 2, 1, 0}; Trade::MeshData data{MeshPrimitive::Lines, - {}, indices, Trade::MeshIndexData{indices}}; + {}, indices, Trade::MeshIndexData{indices}, 3}; Trade::MeshData duplicated = MeshTools::duplicate(data, {}); CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::Lines); diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index adaa1db16..948526f52 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -79,15 +79,29 @@ Containers::Array meshAttributeDataNonOwningArray(const Conta return Containers::Array{const_cast(view.data()), view.size(), reinterpret_cast(Trade::Implementation::nonOwnedArrayDeleter)}; } -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: _indexType{indices._type}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState}, _indexData{std::move(indexData)}, _vertexData{std::move(vertexData)}, _attributes{std::move(attributes)}, _indices{Containers::arrayCast(indices._data)} { - /* Save vertex count. It's a strided array view, so the size is not - depending on type. */ +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: _indexType{indices._type}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState}, _indexData{std::move(indexData)}, _vertexData{std::move(vertexData)}, _attributes{std::move(attributes)}, _indices{Containers::arrayCast(indices._data)} { + /* Save vertex count. If it's passed explicitly, use that (but still check + that all attributes have the same vertex count for safety), otherwise + expect at least one attribute */ + #ifndef CORRADE_NO_ASSERT + UnsignedInt expectedAttributeVertexCount; + #endif if(_attributes.empty()) { - CORRADE_ASSERT(indices._type != MeshIndexType{}, - "Trade::MeshData: indices are expected to be valid if there are no attributes and vertex count isn't passed explicitly", ); - /** @todo some better value? attributeless indexed with defined vertex count? */ - _vertexCount = 0; - } else _vertexCount = _attributes[0]._vertexCount; + CORRADE_ASSERT(vertexCount != ImplicitVertexCount, + "Trade::MeshData: vertex count can't be implicit if there are no attributes", ); + _vertexCount = vertexCount; + /* No attributes, so we won't be checking anything */ + } else if(vertexCount != ImplicitVertexCount) { + _vertexCount = vertexCount; + #ifndef CORRADE_NO_ASSERT + expectedAttributeVertexCount = _attributes[0]._vertexCount; + #endif + } else { + _vertexCount = _attributes[0]._vertexCount; + #ifndef CORRADE_NO_ASSERT + expectedAttributeVertexCount = _vertexCount; + #endif + } CORRADE_ASSERT(!_indices.empty() || _indexData.empty(), "Trade::MeshData: indexData passed for a non-indexed mesh", ); @@ -101,8 +115,8 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& inde const MeshAttributeData& attribute = _attributes[i]; CORRADE_ASSERT(attribute._format != VertexFormat{}, "Trade::MeshData: attribute" << i << "doesn't specify anything", ); - CORRADE_ASSERT(attribute._vertexCount == _vertexCount, - "Trade::MeshData: attribute" << i << "has" << attribute._vertexCount << "vertices but" << _vertexCount << "expected", ); + CORRADE_ASSERT(attribute._vertexCount == expectedAttributeVertexCount, + "Trade::MeshData: attribute" << i << "has" << attribute._vertexCount << "vertices but" << expectedAttributeVertexCount << "expected", ); /* Check that the view fits into the provided vertex data array. For implementation-specific formats we don't know the size so use 0 to check at least partially. */ @@ -123,9 +137,9 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& inde #endif } -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, const void* const importerState): MeshData{primitive, std::move(indexData), indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(indexData), indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} { +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} { CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned), "Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, ); CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned), @@ -134,45 +148,45 @@ MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags _vertexDataFlags = vertexDataFlags; } -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, const std::initializer_list attributes, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, const std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, std::move(vertexData), std::move(attributes), importerState} { +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, std::move(vertexData), std::move(attributes), vertexCount, importerState} { CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned), "Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, ); _indexDataFlags = indexDataFlags; } -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, const std::initializer_list attributes, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, const std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} { +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} { CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned), "Trade::MeshData: can't construct with non-owned vertex data but" << vertexDataFlags, ); _vertexDataFlags = vertexDataFlags; } -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, const std::initializer_list attributes, const void* const importerState): MeshData{primitive, std::move(indexData), indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView vertexData, const std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(indexData), indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, std::move(vertexData), std::move(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, std::move(vertexData), std::move(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& vertexData, const std::initializer_list attributes, const void* const importerState): MeshData{primitive, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& vertexData, const std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} { +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} { CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned), "Trade::MeshData: can't construct with non-owned vertex data but" << vertexDataFlags, ); _vertexDataFlags = vertexDataFlags; } -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, const void* const importerState): MeshData{primitive, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, {}, {}, importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, {}, {}, vertexCount, importerState} {} -MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, importerState} { +MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView indexData, const MeshIndexData& indices, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array{const_cast(static_cast(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, vertexCount, importerState} { CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned), "Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, ); _indexDataFlags = indexDataFlags; } -MeshData::MeshData(const MeshPrimitive primitive, const UnsignedInt vertexCount, const void* const importerState) noexcept: _vertexCount{vertexCount}, _indexType{}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState} {} +MeshData::MeshData(const MeshPrimitive primitive, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, {}, {}, vertexCount, importerState} {} MeshData::~MeshData() = default; @@ -238,8 +252,7 @@ MeshAttributeData MeshData::attributeData(UnsignedInt id) const { CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attributeData(): index" << id << "out of range for" << _attributes.size() << "attributes", MeshAttributeData{}); const MeshAttributeData& attribute = _attributes[id]; - return attribute._isOffsetOnly ? MeshAttributeData{attribute._name, - attribute._format, attributeDataViewInternal(attribute)} : attribute; + return MeshAttributeData{attribute._name, attribute._format, attributeDataViewInternal(attribute)}; } MeshAttribute MeshData::attributeName(UnsignedInt id) const { diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index bfff0fe04..1c4d60d07 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -418,6 +418,10 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { * attribute construction time. Expects that @p arraySize is zero for * builtin attributes. Note that instances created this way can't be * used in most @ref MeshTools algorithms. + * + * Additionally, for even more flexibility, the @p vertexCount can be + * overriden at @ref MeshData construction time, however all attributes + * are still required to have the same vertex count to catch accidents. * @see @ref isOffsetOnly(), @ref arraySize(), * @ref data(Containers::ArrayView) const */ @@ -654,6 +658,14 @@ implementation-specific @ref VertexFormat values. */ class MAGNUM_TRADE_EXPORT MeshData { public: + enum: UnsignedInt { + /** + * Implicit vertex count. When passed to a constructor, indicates + * that vertex count should be taken from attribute data views. + */ + ImplicitVertexCount = ~UnsignedInt{} + }; + /** * @brief Construct an indexed mesh data * @param primitive Primitive @@ -661,6 +673,10 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param indices Index data description * @param vertexData Vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * * The @p indices are expected to point to a sub-range of @p indexData. @@ -674,14 +690,14 @@ class MAGNUM_TRADE_EXPORT MeshData { * The @ref indexDataFlags() / @ref vertexDataFlags() are implicitly * set to a combination of @ref DataFlag::Owned and * @ref DataFlag::Mutable. For non-owned data use the - * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, const MeshIndexData&, DataFlags, Containers::ArrayView, Containers::Array&&, const void*) + * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, const MeshIndexData&, DataFlags, Containers::ArrayView, Containers::Array&&, UnsignedInt, const void*) * constructor or its variants instead. */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct indexed mesh data with non-owned index and vertex data @@ -692,19 +708,23 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param vertexDataFlags Vertex data flags * @param vertexData View on vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * - * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, const void*) + * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * creates an instance that doesn't own the passed vertex and index * data. The @p indexDataFlags / @p vertexDataFlags parameters can * contain @ref DataFlag::Mutable to indicate the external data can be * modified, and is expected to *not* have @ref DataFlag::Owned set. */ - explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct indexed mesh data with non-owned index data @@ -714,9 +734,13 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param indices Index data description * @param vertexData Vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * - * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, const void*) + * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * creates an instance that doesn't own the passed index data. The * @p indexDataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* @@ -724,11 +748,11 @@ class MAGNUM_TRADE_EXPORT MeshData { * implicitly set to a combination of @ref DataFlag::Owned and * @ref DataFlag::Mutable. */ - explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, Containers::Array&& vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct indexed mesh data with non-owned vertex data @@ -738,9 +762,13 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param vertexDataFlags Vertex data flags * @param vertexData View on vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * - * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, const void*) + * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * creates an instance that doesn't own the passed vertex data. The * @p vertexDataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* @@ -748,20 +776,24 @@ class MAGNUM_TRADE_EXPORT MeshData { * implicitly set to a combination of @ref DataFlag::Owned and * @ref DataFlag::Mutable. */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct a non-indexed mesh data * @param primitive Primitive * @param vertexData Vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * - * Same as calling @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, const void*) + * Same as calling @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * with default-constructed @p indexData and @p indices arguments. * * The @ref vertexDataFlags() are implicitly set to a combination of @@ -769,14 +801,14 @@ class MAGNUM_TRADE_EXPORT MeshData { * the @ref indexDataFlags() are implicitly set to a combination of * @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there * isn't any data to own or to mutate. For non-owned data use the - * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, Containers::Array&&, const void*) + * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, Containers::Array&&, UnsignedInt, const void*) * constructor instead. */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, Containers::Array&& vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, Containers::Array&& vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct a non-owned non-indexed mesh data @@ -784,9 +816,13 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param vertexDataFlags Vertex data flags * @param vertexData View on vertex data * @param attributes Description of all vertex attribute data + * @param vertexCount Vertex count. If set to + * @ref ImplicitVertexCount, vertex count is taken from data views + * passed to @p attributes (in which case there has to be at least + * one). * @param importerState Importer-specific state * - * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, Containers::Array&&, const void*) + * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * creates an instance that doesn't own the passed data. The * @p vertexDataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* @@ -795,20 +831,22 @@ class MAGNUM_TRADE_EXPORT MeshData { * @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there * isn't any data to own or to mutate. */ - explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView vertexData, Containers::Array&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept; /** @overload */ /* Not noexcept because allocation happens inside */ - explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, const void* importerState = nullptr); + explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView vertexData, std::initializer_list attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr); /** * @brief Construct an attribute-less indexed mesh data * @param primitive Primitive * @param indexData Index data * @param indices Index data description + * @param vertexCount Vertex count. Passing @ref ImplicitVertexCount + * is not allowed in this overload. * @param importerState Importer-specific state * - * Same as calling @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, const void*) + * Same as calling @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, Containers::Array&&, Containers::Array&&, UnsignedInt, const void*) * with default-constructed @p vertexData and @p attributes arguments. * The @p indices are expected to be valid (but can be empty). If you * want to create an attribute-less non-indexed mesh, use @@ -820,10 +858,10 @@ class MAGNUM_TRADE_EXPORT MeshData { * the @ref vertexDataFlags() are implicitly set to a combination of * @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there * isn't any data to own or to mutate. For non-owned data use the - * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, const MeshIndexData&, const void*) + * @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView, const MeshIndexData&, UnsignedInt, const void*) * constructor instead. */ - explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, Containers::Array&& indexData, const MeshIndexData& indices, UnsignedInt vertexCount, const void* importerState = nullptr) noexcept; /** * @brief Construct a non-owned attribute-less indexed mesh data @@ -831,9 +869,11 @@ class MAGNUM_TRADE_EXPORT MeshData { * @param indexDataFlags Index data flags * @param indexData View on index data * @param indices Index data description + * @param vertexCount Vertex count. Passing + * @ref ImplicitVertexCount is not allowed in this overload. * @param importerState Importer-specific state * - * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, const void*) + * Compared to @ref MeshData(MeshPrimitive, Containers::Array&&, const MeshIndexData&, UnsignedInt, const void*) * creates an instance that doesn't own the passed data. The * @p indexDataFlags parameter can contain @ref DataFlag::Mutable to * indicate the external data can be modified, and is expected to *not* @@ -842,12 +882,13 @@ class MAGNUM_TRADE_EXPORT MeshData { * @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there * isn't any data to own or to mutate. */ - explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, const void* importerState = nullptr) noexcept; + explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView indexData, const MeshIndexData& indices, UnsignedInt vertexCount, const void* importerState = nullptr) noexcept; /** * @brief Construct an index-less attribute-less mesh data * @param primitive Primitive - * @param vertexCount Desired count of vertices to draw + * @param vertexCount Vertex count. Passing @ref ImplicitVertexCount + * is not allowed in this overload. * @param importerState Importer-specific state * * Useful in case the drawing is fully driven by a shader. For diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 7c948f2bf..0ca558f93 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -2264,7 +2264,7 @@ void AbstractImporterTest::mesh() { Containers::Optional doMesh(UnsignedInt id, UnsignedInt level) override { /* Verify that initializer list is converted to an array with the default deleter and not something disallowed */ - if(id == 7 && level == 2) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state}; + if(id == 7 && level == 2) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, MeshData::ImplicitVertexCount, &state}; else return {}; } } importer; @@ -2304,7 +2304,7 @@ void AbstractImporterTest::meshDeprecatedFallback() { else return {}; } Containers::Optional doMesh(UnsignedInt id, UnsignedInt level) override { - if(id == 7 && level == 0) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state}; + if(id == 7 && level == 0) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, MeshData::ImplicitVertexCount, &state}; else return {}; } } importer; @@ -2610,7 +2610,7 @@ void AbstractImporterTest::meshCustomIndexDataDeleter() { UnsignedInt doMeshCount() const override { return 1; } Int doMeshForName(const std::string&) override { return 0; } Containers::Optional doMesh(UnsignedInt, UnsignedInt) override { - return MeshData{MeshPrimitive::Triangles, Containers::Array{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}}; + return MeshData{MeshPrimitive::Triangles, Containers::Array{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}, 1}; } char data[1]; diff --git a/src/Magnum/Trade/Test/MeshData2DTest.cpp b/src/Magnum/Trade/Test/MeshData2DTest.cpp index 5cf12e91d..fed1d1686 100644 --- a/src/Magnum/Trade/Test/MeshData2DTest.cpp +++ b/src/Magnum/Trade/Test/MeshData2DTest.cpp @@ -98,7 +98,7 @@ struct { Containers::StridedArrayView1D{Vertices, &Vertices[0].textureCoords3, 2, sizeof(Vertex)}}, MeshAttributeData{MeshAttribute::Color, Containers::StridedArrayView1D{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}}, - }, &State}}, + }, MeshData::ImplicitVertexCount, &State}}, /* GCC 4.8 needs the explicit MeshData3D conversion otherwise it tries to use a deleted copy constructor */ MeshData2D{MeshData{MeshPrimitive::Lines, {}, Vertices, { @@ -108,7 +108,7 @@ struct { Containers::StridedArrayView1D{Vertices, &Vertices[0].textureCoords1, 2, sizeof(Vertex)}}, MeshAttributeData{MeshAttribute::Color, Containers::StridedArrayView1D{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}}, - }, &State}} + }, MeshData::ImplicitVertexCount, &State}} } }; diff --git a/src/Magnum/Trade/Test/MeshData3DTest.cpp b/src/Magnum/Trade/Test/MeshData3DTest.cpp index 0965f94c3..250130ca6 100644 --- a/src/Magnum/Trade/Test/MeshData3DTest.cpp +++ b/src/Magnum/Trade/Test/MeshData3DTest.cpp @@ -106,7 +106,7 @@ struct { Containers::StridedArrayView1D{Vertices, &Vertices[0].textureCoords3, 2, sizeof(Vertex)}}, MeshAttributeData{MeshAttribute::Color, Containers::StridedArrayView1D{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}}, - }, &State}}, + }, MeshData::ImplicitVertexCount, &State}}, /* GCC 4.8 needs the explicit MeshData3D conversion otherwise it tries to use a deleted copy constructor */ MeshData3D{MeshData{MeshPrimitive::Lines, {}, Vertices, { @@ -118,7 +118,7 @@ struct { Containers::StridedArrayView1D{Vertices, &Vertices[0].textureCoords1, 2, sizeof(Vertex)}}, MeshAttributeData{MeshAttribute::Color, Containers::StridedArrayView1D{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}}, - }, &State}} + }, MeshData::ImplicitVertexCount, &State}} } }; diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index d77578123..628e20da3 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -75,6 +75,7 @@ struct MeshDataTest: TestSuite::Tester { void constructArrayAttributeNotAllowed(); void construct(); + void constructZeroIndices(); void constructZeroAttributes(); void constructZeroVertices(); @@ -91,7 +92,7 @@ struct MeshDataTest: TestSuite::Tester { void constructAttributelessNotOwned(); void constructIndexDataButNotIndexed(); - void constructAttributelessInvalidIndices(); + void constructAttributelessImplicitVertexCount(); void constructIndicesNotContained(); void constructAttributeNotContained(); void constructInconsitentVertexCount(); @@ -153,6 +154,16 @@ struct MeshDataTest: TestSuite::Tester { void releaseVertexData(); }; +struct { + const char* name; + UnsignedInt vertexCount, expectedVertexCount; +} ConstructData[] { + {"implicit vertex count", MeshData::ImplicitVertexCount, 3}, + {"explicit vertex count", 3, 3}, + {"explicit large vertex count", 17, 17}, + {"explicit zero vertex count", 0, 0} +}; + struct { const char* name; DataFlags indexDataFlags, vertexDataFlags; @@ -207,10 +218,12 @@ MeshDataTest::MeshDataTest() { &MeshDataTest::constructArrayAttribute2DNonContiguous, &MeshDataTest::constructArrayAttributeTypeErased, &MeshDataTest::constructArrayAttributeOffsetOnly, - &MeshDataTest::constructArrayAttributeNotAllowed, + &MeshDataTest::constructArrayAttributeNotAllowed}); - &MeshDataTest::construct, - &MeshDataTest::constructZeroIndices, + addInstancedTests({&MeshDataTest::construct}, + Containers::arraySize(ConstructData)); + + addTests({&MeshDataTest::constructZeroIndices, &MeshDataTest::constructZeroAttributes, &MeshDataTest::constructZeroVertices, &MeshDataTest::constructIndexless, @@ -228,7 +241,7 @@ MeshDataTest::MeshDataTest() { Containers::arraySize(SingleNotOwnedData)); addTests({&MeshDataTest::constructIndexDataButNotIndexed, - &MeshDataTest::constructAttributelessInvalidIndices, + &MeshDataTest::constructAttributelessImplicitVertexCount, &MeshDataTest::constructIndicesNotContained, &MeshDataTest::constructAttributeNotContained, &MeshDataTest::constructInconsitentVertexCount, @@ -823,6 +836,9 @@ void MeshDataTest::constructArrayAttributeNotAllowed() { } void MeshDataTest::construct() { + auto&& instanceData = ConstructData[testCaseInstanceId()]; + setTestCaseDescription(instanceData.name); + struct Vertex { Vector3 position; Vector3 normal; @@ -839,8 +855,10 @@ void MeshDataTest::construct() { indexView[4] = 2; indexView[5] = 1; - Containers::Array vertexData{3*sizeof(Vertex)}; - auto vertexView = Containers::arrayCast(vertexData); + /* Enough vertex data to fit also the case with large explicit vertex count + (but fill just the first 3, as those are only tested) */ + Containers::Array vertexData{17*sizeof(Vertex)}; + auto vertexView = Containers::arrayCast(vertexData).prefix(3); vertexView[0].position = {0.1f, 0.2f, 0.3f}; vertexView[1].position = {0.4f, 0.5f, 0.6f}; vertexView[2].position = {0.7f, 0.8f, 0.9f}; @@ -854,6 +872,9 @@ void MeshDataTest::construct() { vertexView[1].id = -374; vertexView[2].id = 22; + if(instanceData.vertexCount < 3) + vertexView = vertexView.prefix(instanceData.vertexCount); + int importerState; MeshIndexData indices{indexView}; MeshAttributeData positions{MeshAttribute::Position, @@ -869,7 +890,7 @@ void MeshDataTest::construct() { MeshData data{MeshPrimitive::Triangles, std::move(indexData), indices, /* Texture coordinates deliberately twice (though aliased) */ - std::move(vertexData), {positions, textureCoordinates, normals, textureCoordinates, ids}, &importerState}; + std::move(vertexData), {positions, textureCoordinates, normals, textureCoordinates, ids}, instanceData.vertexCount, &importerState}; /* Basics */ CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable); @@ -899,7 +920,7 @@ void MeshDataTest::construct() { CORRADE_COMPARE(data.indices()[5], 1); /* Attribute access by ID */ - CORRADE_COMPARE(data.vertexCount(), 3); + CORRADE_COMPARE(data.vertexCount(), instanceData.expectedVertexCount); CORRADE_COMPARE(data.attributeCount(), 5); CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position); CORRADE_COMPARE(data.attributeName(1), MeshAttribute::TextureCoordinates); @@ -927,43 +948,53 @@ void MeshDataTest::construct() { CORRADE_COMPARE(data.attributeArraySize(4), 0); /* Typeless access by ID with a cast later */ - CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( - data.attribute(0))[1]), (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( - data.attribute(1))[0]), (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( - data.attribute(2))[2]), Vector3::zAxis()); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( - data.attribute(3))[1]), (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Short>( - data.attribute(4))[0]), 15); - CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( - data.mutableAttribute(0))[1]), (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( - data.mutableAttribute(1))[0]), (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( - data.mutableAttribute(2))[2]), Vector3::zAxis()); - CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( - data.mutableAttribute(3))[1]), (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE((Containers::arrayCast<1, Short>( - data.mutableAttribute(4))[0]), 15); + CORRADE_COMPARE(data.attribute(0).size()[0], instanceData.expectedVertexCount); + CORRADE_COMPARE(data.mutableAttribute(0).size()[0], instanceData.expectedVertexCount); + if(instanceData.vertexCount) { + CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( + data.attribute(0))[1]), (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( + data.attribute(1))[0]), (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( + data.attribute(2))[2]), Vector3::zAxis()); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( + data.attribute(3))[1]), (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Short>( + data.attribute(4))[0]), 15); + CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( + data.mutableAttribute(0))[1]), (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( + data.mutableAttribute(1))[0]), (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( + data.mutableAttribute(2))[2]), Vector3::zAxis()); + CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( + data.mutableAttribute(3))[1]), (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE((Containers::arrayCast<1, Short>( + data.mutableAttribute(4))[0]), 15); + } /* Typed access by ID */ - CORRADE_COMPARE(data.attribute(0)[1], (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE(data.attribute(1)[0], (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE(data.attribute(2)[2], Vector3::zAxis()); - CORRADE_COMPARE(data.attribute(3)[1], (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE(data.attribute(4)[1], -374); - CORRADE_COMPARE(data.mutableAttribute(0)[1], (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE(data.mutableAttribute(1)[0], (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE(data.mutableAttribute(2)[2], Vector3::zAxis()); - CORRADE_COMPARE(data.mutableAttribute(3)[1], (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE(data.mutableAttribute(4)[1], -374); + CORRADE_COMPARE(data.attribute(0).size(), instanceData.expectedVertexCount); + CORRADE_COMPARE(data.mutableAttribute(0).size(), instanceData.expectedVertexCount); + if(instanceData.vertexCount) { + CORRADE_COMPARE(data.attribute(0)[1], (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE(data.attribute(1)[0], (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE(data.attribute(2)[2], Vector3::zAxis()); + CORRADE_COMPARE(data.attribute(3)[1], (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE(data.attribute(4)[1], -374); + CORRADE_COMPARE(data.mutableAttribute(0)[1], (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE(data.mutableAttribute(1)[0], (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE(data.mutableAttribute(2)[2], Vector3::zAxis()); + CORRADE_COMPARE(data.mutableAttribute(3)[1], (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE(data.mutableAttribute(4)[1], -374); + } /* Raw attribute data access by ID */ CORRADE_COMPARE(data.attributeData(3).name(), MeshAttribute::TextureCoordinates); CORRADE_COMPARE(data.attributeData(3).format(), VertexFormat::Vector2); - CORRADE_COMPARE(Containers::arrayCast(data.attributeData(3).data())[1], (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE(data.attributeData(3).data().size(), instanceData.expectedVertexCount); + if(instanceData.vertexCount) + CORRADE_COMPARE(Containers::arrayCast(data.attributeData(3).data())[1], (Vector2{0.250f, 0.375f})); /* Attribute access by name */ CORRADE_VERIFY(data.hasAttribute(MeshAttribute::Position)); @@ -1009,38 +1040,46 @@ void MeshDataTest::construct() { CORRADE_COMPARE(data.attributeArraySize(meshAttributeCustom(13)), 0); /* Typeless access by name with a cast later */ - CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( - data.attribute(MeshAttribute::Position))[1]), (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( - data.attribute(MeshAttribute::Normal))[2]), Vector3::zAxis()); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( - data.attribute(MeshAttribute::TextureCoordinates, 0))[0]), (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( - data.attribute(MeshAttribute::TextureCoordinates, 1))[1]), (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE((Containers::arrayCast<1, const Short>( - data.attribute(meshAttributeCustom(13)))[1]), -374); - CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( - data.mutableAttribute(MeshAttribute::Position))[1]), (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( - data.mutableAttribute(MeshAttribute::Normal))[2]), Vector3::zAxis()); - CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( - data.mutableAttribute(MeshAttribute::TextureCoordinates, 0))[0]), (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( - data.mutableAttribute(MeshAttribute::TextureCoordinates, 1))[1]), (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE((Containers::arrayCast<1, Short>( - data.mutableAttribute(meshAttributeCustom(13)))[1]), -374); + CORRADE_COMPARE(data.attribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount); + if(instanceData.vertexCount) { + CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( + data.attribute(MeshAttribute::Position))[1]), (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( + data.attribute(MeshAttribute::Normal))[2]), Vector3::zAxis()); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( + data.attribute(MeshAttribute::TextureCoordinates, 0))[0]), (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector2>( + data.attribute(MeshAttribute::TextureCoordinates, 1))[1]), (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE((Containers::arrayCast<1, const Short>( + data.attribute(meshAttributeCustom(13)))[1]), -374); + CORRADE_COMPARE((Containers::arrayCast<1, const Vector3>( + data.mutableAttribute(MeshAttribute::Position))[1]), (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE((Containers::arrayCast<1, Vector3>( + data.mutableAttribute(MeshAttribute::Normal))[2]), Vector3::zAxis()); + CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( + data.mutableAttribute(MeshAttribute::TextureCoordinates, 0))[0]), (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE((Containers::arrayCast<1, Vector2>( + data.mutableAttribute(MeshAttribute::TextureCoordinates, 1))[1]), (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE((Containers::arrayCast<1, Short>( + data.mutableAttribute(meshAttributeCustom(13)))[1]), -374); + } /* Typed access by name */ - CORRADE_COMPARE(data.attribute(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE(data.attribute(MeshAttribute::Normal)[2], Vector3::zAxis()); - CORRADE_COMPARE(data.attribute(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE(data.attribute(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE(data.attribute(meshAttributeCustom(13))[2], 22); - CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f})); - CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Normal)[2], Vector3::zAxis()); - CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f})); - CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f})); - CORRADE_COMPARE(data.attribute(meshAttributeCustom(13))[2], 22); + CORRADE_COMPARE(data.attribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount); + if(instanceData.vertexCount) { + CORRADE_COMPARE(data.attribute(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE(data.attribute(MeshAttribute::Normal)[2], Vector3::zAxis()); + CORRADE_COMPARE(data.attribute(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE(data.attribute(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE(data.attribute(meshAttributeCustom(13))[2], 22); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f})); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Normal)[2], Vector3::zAxis()); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f})); + CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f})); + CORRADE_COMPARE(data.attribute(meshAttributeCustom(13))[2], 22); + } } void MeshDataTest::constructZeroIndices() { @@ -1073,14 +1112,14 @@ void MeshDataTest::constructZeroAttributes() { auto indexView = Containers::arrayCast(indexData); MeshData data{MeshPrimitive::Triangles, std::move(indexData), MeshIndexData{indexView}, - std::move(vertexData), {}}; + std::move(vertexData), {}, 15}; CORRADE_COMPARE(data.indexCount(), 3); CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_COMPARE(data.attributeCount(), 0); CORRADE_VERIFY(!data.attributeData()); CORRADE_COMPARE(data.vertexData().size(), 3); - CORRADE_COMPARE(data.vertexCount(), 0); + CORRADE_COMPARE(data.vertexCount(), 15); } void MeshDataTest::constructZeroVertices() { @@ -1112,7 +1151,7 @@ void MeshDataTest::constructIndexless() { int importerState; MeshAttributeData positions{MeshAttribute::Position, vertexView}; - MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions}, &importerState}; + MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable); /* These are empty so it doesn't matter, but this is a nice non-restrictive default */ @@ -1153,7 +1192,7 @@ void MeshDataTest::constructAttributeless() { int importerState; MeshIndexData indices{indexView}; - MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), indices, &importerState}; + MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), indices, 3, &importerState}; /* These are empty so it doesn't matter, but this is a nice non-restrictive default */ CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable); @@ -1170,7 +1209,7 @@ void MeshDataTest::constructAttributeless() { CORRADE_COMPARE(data.indices()[2], 2); CORRADE_COMPARE(data.indices()[5], 1); - CORRADE_COMPARE(data.vertexCount(), 0); /** @todo what to return here? */ + CORRADE_COMPARE(data.vertexCount(), 3); CORRADE_COMPARE(data.attributeCount(), 0); } @@ -1184,7 +1223,7 @@ void MeshDataTest::constructNotOwned() { int importerState; MeshIndexData indices{indexData}; MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)}; - MeshData data{MeshPrimitive::Triangles, instanceData.indexDataFlags, Containers::arrayView(indexData), indices, instanceData.vertexDataFlags, Containers::arrayView(vertexData), {positions}, &importerState}; + MeshData data{MeshPrimitive::Triangles, instanceData.indexDataFlags, Containers::arrayView(indexData), indices, instanceData.vertexDataFlags, Containers::arrayView(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), instanceData.indexDataFlags); CORRADE_COMPARE(data.vertexDataFlags(), instanceData.vertexDataFlags); @@ -1234,7 +1273,7 @@ void MeshDataTest::constructIndicesNotOwned() { int importerState; MeshIndexData indices{indexData}; MeshAttributeData positions{MeshAttribute::Position, vertexView}; - MeshData data{MeshPrimitive::Triangles, instanceData.dataFlags, Containers::arrayView(indexData), indices, std::move(vertexData), {positions}, &importerState}; + MeshData data{MeshPrimitive::Triangles, instanceData.dataFlags, Containers::arrayView(indexData), indices, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), instanceData.dataFlags); CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable); @@ -1282,7 +1321,7 @@ void MeshDataTest::constructVerticesNotOwned() { int importerState; MeshIndexData indices{indexView}; MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)}; - MeshData data{MeshPrimitive::Triangles, std::move(indexData), indices, instanceData.dataFlags, Containers::arrayView(vertexData), {positions}, &importerState}; + MeshData data{MeshPrimitive::Triangles, std::move(indexData), indices, instanceData.dataFlags, Containers::arrayView(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_COMPARE(data.vertexDataFlags(), instanceData.dataFlags); @@ -1324,7 +1363,7 @@ void MeshDataTest::constructIndexlessNotOwned() { int importerState; MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)}; - MeshData data{MeshPrimitive::LineLoop, instanceData.dataFlags, vertexData, {positions}, &importerState}; + MeshData data{MeshPrimitive::LineLoop, instanceData.dataFlags, vertexData, {positions}, MeshData::ImplicitVertexCount, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_COMPARE(data.vertexDataFlags(), instanceData.dataFlags); @@ -1351,7 +1390,7 @@ void MeshDataTest::constructAttributelessNotOwned() { int importerState; MeshIndexData indices{indexData}; - MeshData data{MeshPrimitive::TriangleStrip, instanceData.dataFlags, indexData, indices, &importerState}; + MeshData data{MeshPrimitive::TriangleStrip, instanceData.dataFlags, indexData, indices, 5, &importerState}; CORRADE_COMPARE(data.indexDataFlags(), instanceData.dataFlags); CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable); CORRADE_COMPARE(data.primitive(), MeshPrimitive::TriangleStrip); @@ -1373,7 +1412,7 @@ void MeshDataTest::constructAttributelessNotOwned() { CORRADE_COMPARE(data.mutableIndices()[2], 0); } - CORRADE_COMPARE(data.vertexCount(), 0); /** @todo what to return here? */ + CORRADE_COMPARE(data.vertexCount(), 5); CORRADE_COMPARE(data.attributeCount(), 0); } @@ -1419,11 +1458,11 @@ void MeshDataTest::constructIndexDataButNotIndexed() { CORRADE_COMPARE(out.str(), "Trade::MeshData: indexData passed for a non-indexed mesh\n"); } -void MeshDataTest::constructAttributelessInvalidIndices() { +void MeshDataTest::constructAttributelessImplicitVertexCount() { std::ostringstream out; Error redirectError{&out}; - MeshData{MeshPrimitive::Points, nullptr, MeshIndexData{}}; - CORRADE_COMPARE(out.str(), "Trade::MeshData: indices are expected to be valid if there are no attributes and vertex count isn't passed explicitly\n"); + MeshData{MeshPrimitive::Points, nullptr, {}}; + CORRADE_COMPARE(out.str(), "Trade::MeshData: vertex count can't be implicit if there are no attributes\n"); } void MeshDataTest::constructIndicesNotContained() { @@ -1433,8 +1472,8 @@ void MeshDataTest::constructIndicesNotContained() { std::ostringstream out; Error redirectError{&out}; - MeshData{MeshPrimitive::Triangles, std::move(indexData), indices}; - MeshData{MeshPrimitive::Triangles, nullptr, indices}; + MeshData{MeshPrimitive::Triangles, std::move(indexData), indices, 1}; + MeshData{MeshPrimitive::Triangles, nullptr, indices, 1}; CORRADE_COMPARE(out.str(), "Trade::MeshData: indices [0xdead:0xdeb3] are not contained in passed indexData array [0xbadda9:0xbaddaf]\n" "Trade::MeshData: indices [0xdead:0xdeb3] are not contained in passed indexData array [0x0:0x0]\n"); @@ -1449,25 +1488,40 @@ void MeshDataTest::constructAttributeNotContained() { /* See implementationSpecificVertexFormatNotContained() below for implementation-specific formats */ + /* Here the original positions array is shrunk from 3 items to 2 and the + vertex data too, which should work without asserting -- comparing just + the original view would not pass, which is wrong */ + MeshData{MeshPrimitive::Triangles, {}, vertexData.prefix(16), {positions}, 2}; + std::ostringstream out; Error redirectError{&out}; + /* Here the original positions array is extended from 3 items to 4, which + makes it not fit anymore, and thus an assert should hit -- comparing + just the original view would pass, which is wrong */ + MeshData{MeshPrimitive::Triangles, {}, vertexData, {positions}, 4}; MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}}; MeshData{MeshPrimitive::Triangles, nullptr, {positions}}; MeshData{MeshPrimitive::Triangles, Containers::Array{24}, {positions3}}; CORRADE_COMPARE(out.str(), + "Trade::MeshData: attribute 0 [0xbadda9:0xbaddc9] is not contained in passed vertexData array [0xbadda9:0xbaddc1]\n" "Trade::MeshData: attribute 1 [0xdead:0xdec5] is not contained in passed vertexData array [0xbadda9:0xbaddc1]\n" "Trade::MeshData: attribute 0 [0xbadda9:0xbaddc1] is not contained in passed vertexData array [0x0:0x0]\n" "Trade::MeshData: offset attribute 0 spans 25 bytes but passed vertexData array has only 24\n"); } void MeshDataTest::constructInconsitentVertexCount() { - Containers::Array vertexData{24}; - MeshAttributeData positions{MeshAttribute::Position, Containers::arrayCast(vertexData)}; + Containers::Array vertexData{136}; + MeshAttributeData positions{MeshAttribute::Position, Containers::arrayCast(vertexData).prefix(3)}; MeshAttributeData positions2{MeshAttribute::Position, Containers::arrayCast(vertexData).prefix(2)}; std::ostringstream out; Error redirectError{&out}; - MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}}; + /* The explicit vertex count should be ignored for the assertion message, + we only check that all passed attribute arrays have the same vertex + count. However, the actual "containment" of the attribute views is + checked with the explicit vertex count -- see the + constructAttributeNotContained() test above. */ + MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}, 17}; CORRADE_COMPARE(out.str(), "Trade::MeshData: attribute 1 has 2 vertices but 3 expected\n"); } @@ -1552,7 +1606,7 @@ void MeshDataTest::constructAttributelessNotOwnedFlagOwned() { std::ostringstream out; Error redirectError{&out}; - MeshData data{MeshPrimitive::Triangles, DataFlag::Owned, indexData, indices}; + MeshData data{MeshPrimitive::Triangles, DataFlag::Owned, indexData, indices, 2}; CORRADE_COMPARE(out.str(), "Trade::MeshData: can't construct with non-owned index data but Trade::DataFlag::Owned\n"); } @@ -1590,7 +1644,7 @@ void MeshDataTest::constructMove() { int importerState; MeshIndexData indices{indexView}; MeshAttributeData positions{MeshAttribute::Position, vertexView}; - MeshData a{MeshPrimitive::Triangles, std::move(indexData), indices, std::move(vertexData), {positions}, &importerState}; + MeshData a{MeshPrimitive::Triangles, std::move(indexData), indices, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState}; MeshData b{std::move(a)}; @@ -1680,7 +1734,7 @@ template void MeshDataTest::indicesAsArray() { indexView[1] = 131; indexView[2] = 240; - MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}}; + MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}, 241}; CORRADE_COMPARE_AS(data.indicesAsArray(), Containers::arrayView({75, 131, 240}), TestSuite::Compare::Container); @@ -1688,7 +1742,7 @@ template void MeshDataTest::indicesAsArray() { void MeshDataTest::indicesIntoArrayInvalidSize() { Containers::Array indexData{3*sizeof(UnsignedInt)}; - MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{Containers::arrayCast(indexData)}}; + MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{Containers::arrayCast(indexData)}, 1}; std::ostringstream out; Error redirectError{&out}; @@ -2338,7 +2392,7 @@ void MeshDataTest::indicesWrongType() { Containers::Array indexData{sizeof(UnsignedShort)}; auto indexView = Containers::arrayCast(indexData); indexView[0] = 57616; - MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}}; + MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}, 57617}; std::ostringstream out; Error redirectError{&out}; @@ -2422,7 +2476,7 @@ void MeshDataTest::releaseIndexData() { Containers::Array indexData{23}; auto indexView = Containers::arrayCast(indexData.slice(6, 12)); - MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), MeshIndexData{indexView}}; + MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), MeshIndexData{indexView}, 10}; CORRADE_VERIFY(data.isIndexed()); CORRADE_COMPARE(data.indexCount(), 3); CORRADE_COMPARE(data.indexOffset(), 6);