diff --git a/src/Magnum/MeshTools/Interleave.cpp b/src/Magnum/MeshTools/Interleave.cpp index 8f89b6095..0518008d4 100644 --- a/src/Magnum/MeshTools/Interleave.cpp +++ b/src/Magnum/MeshTools/Interleave.cpp @@ -80,9 +80,9 @@ Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt std::size_t extraAttributeCount = 0; for(std::size_t i = 0; i != extra.size(); ++i) { if(extra[i].format() == VertexFormat{}) { - CORRADE_ASSERT(extra[i].data().stride() > 0 || stride >= std::size_t(-extra[i].data().stride()), - "MeshTools::interleavedLayout(): negative padding" << extra[i].data().stride() << "in extra attribute" << i << "too large for stride" << stride, (Trade::MeshData{MeshPrimitive::Points, 0})); - stride += extra[i].data().stride(); + CORRADE_ASSERT(extra[i].stride() > 0 || stride >= std::size_t(-extra[i].stride()), + "MeshTools::interleavedLayout(): negative padding" << extra[i].stride() << "in extra attribute" << i << "too large for stride" << stride, (Trade::MeshData{MeshPrimitive::Points, 0})); + stride += extra[i].stride(); } else { stride += vertexFormatSize(extra[i].format()); ++extraAttributeCount; @@ -118,7 +118,7 @@ Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt for(UnsignedInt i = 0; i != extra.size(); ++i) { /* Padding, only adjust the offset for next attribute */ if(extra[i].format() == VertexFormat{}) { - offset += extra[i].data().stride(); + offset += extra[i].stride(); continue; } diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 004e30d58..bfff0fe04 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -430,6 +430,7 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { * between interleaved attributes. Negative values can be used to alias * multiple different attributes onto each other. Not meant to be * passed to @ref MeshData. + * @see @ref stride() */ constexpr explicit MeshAttributeData(Int padding): _data{nullptr}, _vertexCount{0}, _format{}, _stride{ (CORRADE_CONSTEXPR_ASSERT(padding >= -32768 && padding <= 32767, @@ -452,6 +453,25 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { /** @brief Attribute format */ constexpr VertexFormat format() const { return _format; } + /** + * @brief Attribute offset + * + * If the attribute is offset-only, returns the offset directly, + * otherwise uses the @p vertexData parameter to calculate the offset. + * @see @ref isOffsetOnly() + */ + std::size_t offset(Containers::ArrayView vertexData) const { + return _isOffsetOnly ? _data.offset : reinterpret_cast(_data.pointer) - reinterpret_cast(vertexData.data()); + } + + /** + * @brief Attribute stride + * + * Can be negative for pad values, never negative for real attributes. + * @see @ref MeshAttributeData(Int) + */ + constexpr Short stride() const { return _stride; } + /** @brief Attribute array size */ constexpr UnsignedShort arraySize() const { return _arraySize; } @@ -474,8 +494,8 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { /** * @brief Type-erased attribute data for an offset-only attribute * - * If the attribute is not offset-only, the @ref vertexData parameter - * is ignored. + * If the attribute is not offset-only, the @p vertexData parameter is + * ignored. * @see @ref isOffsetOnly(), @ref data() const */ Containers::StridedArrayView1D data(Containers::ArrayView vertexData) const { diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index 70448ce10..d77578123 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -492,6 +492,8 @@ void MeshDataTest::constructAttribute() { CORRADE_COMPARE(positions.arraySize(), 0); CORRADE_COMPARE(positions.name(), MeshAttribute::Position); CORRADE_COMPARE(positions.format(), VertexFormat::Vector2); + CORRADE_COMPARE(positions.offset(positionData), 0); + CORRADE_COMPARE(positions.stride(), sizeof(Vector2)); CORRADE_VERIFY(positions.data().data() == positionData); /* This is allowed too for simplicity, it just ignores the parameter */ CORRADE_VERIFY(positions.data(positionData).data() == positionData); @@ -501,11 +503,13 @@ void MeshDataTest::constructAttribute() { constexpr UnsignedShort arraySize = cpositions.arraySize(); constexpr MeshAttribute name = cpositions.name(); constexpr VertexFormat format = cpositions.format(); + constexpr Short stride = cpositions.stride(); constexpr Containers::StridedArrayView1D data = cpositions.data(); CORRADE_VERIFY(!isOffsetOnly); CORRADE_COMPARE(arraySize, 0); CORRADE_COMPARE(name, MeshAttribute::Position); CORRADE_COMPARE(format, VertexFormat::Vector2); + CORRADE_COMPARE(stride, sizeof(Vector2)); CORRADE_COMPARE(data.data(), Positions); } @@ -603,6 +607,8 @@ void MeshDataTest::constructAttributeOffsetOnly() { CORRADE_COMPARE(a.arraySize(), 0); CORRADE_COMPARE(a.name(), MeshAttribute::TextureCoordinates); CORRADE_COMPARE(a.format(), VertexFormat::Vector2); + CORRADE_COMPARE(a.offset(vertexData), sizeof(Vector2)); + CORRADE_COMPARE(a.stride(), 2*sizeof(Vector2)); CORRADE_COMPARE_AS(Containers::arrayCast(a.data(vertexData)), Containers::arrayView({{1.0f, 0.3f}, {0.5f, 0.7f}}), TestSuite::Compare::Container); @@ -612,6 +618,8 @@ void MeshDataTest::constructAttributeOffsetOnly() { CORRADE_COMPARE(ca.arraySize(), 0); CORRADE_COMPARE(ca.name(), MeshAttribute::TextureCoordinates); CORRADE_COMPARE(ca.format(), VertexFormat::Vector2); + CORRADE_COMPARE(ca.offset(vertexData), sizeof(Vector2)); + CORRADE_COMPARE(ca.stride(), 2*sizeof(Vector2)); CORRADE_COMPARE_AS(Containers::arrayCast(a.data(vertexData)), Containers::arrayView({{1.0f, 0.3f}, {0.5f, 0.7f}}), TestSuite::Compare::Container);