diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index 319a1faa6..1217cb87f 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -72,7 +72,7 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& inde "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].data.size(); + } else _vertexCount = _attributes[0]._data.size(); CORRADE_ASSERT(!_indices.empty() || !_indexData, "Trade::MeshData: indexData passed for a non-indexed mesh", ); @@ -88,11 +88,11 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array&& inde constructors */ for(std::size_t i = 0; i != _attributes.size(); ++i) { const MeshAttributeData& attribute = _attributes[i]; - const Containers::StridedArrayView1D data = Containers::arrayCast(attribute.data); + const Containers::StridedArrayView1D data = Containers::arrayCast(attribute._data); CORRADE_ASSERT(data.size() == _vertexCount, "Trade::MeshData: attribute" << i << "has" << data.size() << "vertices but" << _vertexCount << "expected", ); - CORRADE_ASSERT(data.empty() || (&data.front() >= _vertexData.begin() && &data.back() + vertexFormatSize(attribute.format) <= _vertexData.end()), - "Trade::MeshData: attribute" << i << "[" << Debug::nospace << static_cast(&data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast(&data.back() + vertexFormatSize(attribute.format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast(_vertexData.end()) << Debug::nospace << "]", ); + CORRADE_ASSERT(data.empty() || (&data.front() >= _vertexData.begin() && &data.back() + vertexFormatSize(attribute._format) <= _vertexData.end()), + "Trade::MeshData: attribute" << i << "[" << Debug::nospace << static_cast(&data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast(&data.back() + vertexFormatSize(attribute._format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast(_vertexData.end()) << Debug::nospace << "]", ); } #endif } @@ -181,37 +181,37 @@ MeshIndexType MeshData::indexType() const { MeshAttribute MeshData::attributeName(UnsignedInt id) const { CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attributeName(): index" << id << "out of range for" << _attributes.size() << "attributes", {}); - return _attributes[id].name; + return _attributes[id]._name; } VertexFormat MeshData::attributeFormat(UnsignedInt id) const { CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attributeFormat(): index" << id << "out of range for" << _attributes.size() << "attributes", {}); - return _attributes[id].format; + return _attributes[id]._format; } std::size_t MeshData::attributeOffset(UnsignedInt id) const { CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attributeOffset(): index" << id << "out of range for" << _attributes.size() << "attributes", {}); - return static_cast(_attributes[id].data.data()) - _vertexData.data(); + return static_cast(_attributes[id]._data.data()) - _vertexData.data(); } UnsignedInt MeshData::attributeStride(UnsignedInt id) const { CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attributeStride(): index" << id << "out of range for" << _attributes.size() << "attributes", {}); - return _attributes[id].data.stride(); + return _attributes[id]._data.stride(); } UnsignedInt MeshData::attributeCount(const MeshAttribute name) const { UnsignedInt count = 0; for(const MeshAttributeData& attribute: _attributes) - if(attribute.name == name) ++count; + if(attribute._name == name) ++count; return count; } UnsignedInt MeshData::attributeFor(const MeshAttribute name, UnsignedInt id) const { for(std::size_t i = 0; i != _attributes.size(); ++i) { - if(_attributes[i].name != name) continue; + if(_attributes[i]._name != name) continue; if(id-- == 0) return i; } @@ -244,8 +244,8 @@ Containers::StridedArrayView2D MeshData::attribute(UnsignedInt id) c CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::attribute(): index" << id << "out of range for" << _attributes.size() << "attributes", nullptr); /* Build a 2D view using information about attribute type size */ - return Containers::arrayCast<2, const char>(_attributes[id].data, - vertexFormatSize(_attributes[id].format)); + return Containers::arrayCast<2, const char>(_attributes[id]._data, + vertexFormatSize(_attributes[id]._format)); } Containers::StridedArrayView2D MeshData::mutableAttribute(UnsignedInt id) { @@ -254,8 +254,8 @@ Containers::StridedArrayView2D MeshData::mutableAttribute(UnsignedInt id) CORRADE_ASSERT(id < _attributes.size(), "Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << _attributes.size() << "attributes", nullptr); /* Build a 2D view using information about attribute type size */ - auto out = Containers::arrayCast<2, const char>(_attributes[id].data, - vertexFormatSize(_attributes[id].format)); + auto out = Containers::arrayCast<2, const char>(_attributes[id]._data, + vertexFormatSize(_attributes[id]._format)); /** @todo some arrayConstCast? UGH */ return Containers::StridedArrayView2D{ /* The view size is there only for a size assert, we're pretty sure the @@ -317,9 +317,9 @@ void MeshData::positions2DInto(const Containers::StridedArrayView1D des const MeshAttributeData& attribute = _attributes[attributeId]; /* Copy 2D positions as-is, for 3D positions ignore Z */ - if(attribute.format == VertexFormat::Vector2 || - attribute.format == VertexFormat::Vector3) - Utility::copy(Containers::arrayCast(attribute.data), destination); + if(attribute._format == VertexFormat::Vector2 || + attribute._format == VertexFormat::Vector3) + Utility::copy(Containers::arrayCast(attribute._data), destination); else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -337,16 +337,16 @@ void MeshData::positions3DInto(const Containers::StridedArrayView1D des /* For 2D positions copy the XY part to the first two components and then fill the Z with a single value */ - if(attribute.format == VertexFormat::Vector2) { - Utility::copy(Containers::arrayCast(attribute.data), + if(attribute._format == VertexFormat::Vector2) { + Utility::copy(Containers::arrayCast(attribute._data), Containers::arrayCast(destination)); constexpr Float z[1]{0.0f}; Utility::copy( Containers::stridedArrayView(z).broadcasted<0>(_vertexCount), Containers::arrayCast<2, Float>(destination).transposed<0, 1>()[2]); /* Copy 3D positions as-is */ - } else if(attribute.format == VertexFormat::Vector3) { - Utility::copy(Containers::arrayCast(attribute.data), destination); + } else if(attribute._format == VertexFormat::Vector3) { + Utility::copy(Containers::arrayCast(attribute._data), destination); } else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -362,8 +362,8 @@ void MeshData::normalsInto(const Containers::StridedArrayView1D destina CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); const MeshAttributeData& attribute = _attributes[attributeId]; - if(attribute.format == VertexFormat::Vector3) - Utility::copy(Containers::arrayCast(attribute.data), destination); + if(attribute._format == VertexFormat::Vector3) + Utility::copy(Containers::arrayCast(attribute._data), destination); else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -379,8 +379,8 @@ void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D(attribute.data), destination); + if(attribute._format == VertexFormat::Vector2) + Utility::copy(Containers::arrayCast(attribute._data), destination); else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -398,16 +398,16 @@ void MeshData::colorsInto(const Containers::StridedArrayView1D destinati /* For three-component colors copy the RGB part to the first three components and then fill the alpha with a single value */ - if(attribute.format == VertexFormat::Vector3) { - Utility::copy(Containers::arrayCast(attribute.data), + if(attribute._format == VertexFormat::Vector3) { + Utility::copy(Containers::arrayCast(attribute._data), Containers::arrayCast(destination)); constexpr Float alpha[1]{1.0f}; Utility::copy( Containers::stridedArrayView(alpha).broadcasted<0>(_vertexCount), Containers::arrayCast<2, Float>(destination).transposed<0, 1>()[3]); /* Copy four-component colors as-is */ - } else if(attribute.format == VertexFormat::Vector4) { - Utility::copy(Containers::arrayCast(attribute.data), + } else if(attribute._format == VertexFormat::Vector4) { + Utility::copy(Containers::arrayCast(attribute._data), Containers::arrayCast(destination)); } else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index ba83cd7eb..dfa820923 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -209,8 +209,8 @@ class MAGNUM_TRADE_EXPORT MeshIndexData { @brief Mesh attribute data @m_since_latest -Convenience type for populating @ref MeshData. Has no accessors, as the data -are then accessible through @ref MeshData APIs. +Convenience type for populating @ref MeshData, see its documentation for an +introduction. */ class MAGNUM_TRADE_EXPORT MeshAttributeData { public: @@ -221,7 +221,7 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { * initialization of the attribute array for @ref MeshData, expected to * be replaced with concrete values later. */ - constexpr explicit MeshAttributeData() noexcept: name{}, format{}, data{} {} + constexpr explicit MeshAttributeData() noexcept: _name{}, _format{}, _data{} {} /** * @brief Type-erased constructor @@ -261,15 +261,23 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData { /** @overload */ template constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::ArrayView& data) noexcept: MeshAttributeData{name, Containers::stridedArrayView(data)} {} + /** @brief Attribute name */ + constexpr MeshAttribute name() const { return _name; } + + /** @brief Attribute format */ + constexpr VertexFormat format() const { return _format; } + + /** @brief Type-erased attribute data */ + constexpr Containers::StridedArrayView1D data() const { return _data; } + private: constexpr explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D& data, std::nullptr_t) noexcept; - /* Not prefixed with _ because we use them like public in MeshData */ friend MeshData; - MeshAttribute name; + MeshAttribute _name; /* Here's some room for flags */ - VertexFormat format; - Containers::StridedArrayView1D data; + VertexFormat _format; + Containers::StridedArrayView1D _data; }; /** @relatesalso MeshAttributeData @@ -1092,7 +1100,7 @@ constexpr MeshIndexData::MeshIndexData(const MeshIndexType type, const Container _type{type}, _data{(CORRADE_CONSTEXPR_ASSERT(!data.empty(), "Trade::MeshIndexData: index array can't be empty, create a non-indexed mesh instead"), data)} {} constexpr MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D& data, std::nullptr_t) noexcept: - name{name}, format{format}, data{(CORRADE_CONSTEXPR_ASSERT( + _name{name}, _format{format}, _data{(CORRADE_CONSTEXPR_ASSERT( (name == MeshAttribute::Position && (format == VertexFormat::Vector2 || format == VertexFormat::Vector3)) || @@ -1132,8 +1140,8 @@ template Containers::StridedArrayView1D MeshData::attribute(Un #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ if(!data.stride()[1]) return {}; #endif - CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[id].format, - "Trade::MeshData::attribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr); + CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[id]._format, + "Trade::MeshData::attribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr); return Containers::arrayCast<1, const T>(data); } @@ -1142,8 +1150,8 @@ template Containers::StridedArrayView1D MeshData::mutableAttribute(U #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ if(!data.stride()[1]) return {}; #endif - CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[id].format, - "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr); + CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[id]._format, + "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr); return Containers::arrayCast<1, T>(data); } @@ -1155,8 +1163,8 @@ template Containers::StridedArrayView1D MeshData::attribute(Me #ifndef CORRADE_NO_ASSERT const UnsignedInt attributeId = attributeFor(name, id); #endif - CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[attributeId].format, - "Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId].name << "of format" << _attributes[attributeId].format, nullptr); + CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[attributeId]._format, + "Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr); return Containers::arrayCast<1, const T>(data); } @@ -1168,8 +1176,8 @@ template Containers::StridedArrayView1D MeshData::mutableAttribute(M #ifndef CORRADE_NO_ASSERT const UnsignedInt attributeId = attributeFor(name, id); #endif - CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[attributeId].format, - "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId].name << "of type" << _attributes[attributeId].format, nullptr); + CORRADE_ASSERT(Implementation::vertexFormatFor() == _attributes[attributeId]._format, + "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId]._name << "of type" << _attributes[attributeId]._format, nullptr); return Containers::arrayCast<1, T>(data); } diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index 5d20e46f5..dffb068e5 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -329,60 +329,51 @@ constexpr Vector2 Positions[] { }; void MeshDataTest::constructAttribute() { - Containers::Array positionData{3*sizeof(Vector2)}; - auto positionView = Containers::arrayCast(positionData); - - MeshAttributeData positions{MeshAttribute::Position, positionView}; - MeshData data{MeshPrimitive::Points, std::move(positionData), {positions}}; - CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position); - CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Vector2); - CORRADE_COMPARE(static_cast(data.attribute(0).data()), - positionView.data()); + const Vector2 positionData[3]; + MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(positionData)}; + CORRADE_COMPARE(positions.name(), MeshAttribute::Position); + CORRADE_COMPARE(positions.format(), VertexFormat::Vector2); + CORRADE_VERIFY(positions.data().data() == positionData); constexpr MeshAttributeData cpositions{MeshAttribute::Position, Containers::arrayView(Positions)}; - MeshData cdata{MeshPrimitive::Points, {}, Positions, {cpositions}}; - CORRADE_COMPARE(cdata.attributeName(0), MeshAttribute::Position); - CORRADE_COMPARE(cdata.attributeFormat(0), VertexFormat::Vector2); - CORRADE_COMPARE(static_cast(cdata.attribute(0).data()), - Positions); + constexpr MeshAttribute name = cpositions.name(); + constexpr VertexFormat format = cpositions.format(); + constexpr Containers::StridedArrayView1D data = cpositions.data(); + CORRADE_COMPARE(name, MeshAttribute::Position); + CORRADE_COMPARE(format, VertexFormat::Vector2); + CORRADE_COMPARE(data.data(), Positions); } void MeshDataTest::constructAttributeCustom() { - Containers::Array idData{3*sizeof(Short)}; - auto idView = Containers::arrayCast(idData); - - MeshAttributeData ids{meshAttributeCustom(13), idView}; - MeshData data{MeshPrimitive::Points, std::move(idData), {ids}}; - CORRADE_COMPARE(data.attributeName(0), meshAttributeCustom(13)); - CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Short); - CORRADE_COMPARE(static_cast(data.attribute(0).data()), - idView.data()); + const Short idData[3]{}; + MeshAttributeData ids{meshAttributeCustom(13), Containers::arrayView(idData)}; + CORRADE_COMPARE(ids.name(), meshAttributeCustom(13)); + CORRADE_COMPARE(ids.format(), VertexFormat::Short); + CORRADE_VERIFY(ids.data().data() == idData); } void MeshDataTest::constructAttributeWrongFormat() { - Containers::Array positionData{3*sizeof(Vector2)}; + Vector2 positionData[3]; std::ostringstream out; Error redirectError{&out}; - MeshAttributeData{MeshAttribute::Color, Containers::arrayCast(positionData)}; + MeshAttributeData{MeshAttribute::Color, Containers::arrayView(positionData)}; CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: VertexFormat::Vector2 is not a valid format for Trade::MeshAttribute::Color\n"); } void MeshDataTest::constructAttribute2D() { - Containers::Array positionData{4*sizeof(Vector2)}; + char positionData[4*sizeof(Vector2)]{}; auto positionView = Containers::StridedArrayView2D{positionData, {4, sizeof(Vector2)}}.every(2); MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector2, positionView}; - MeshData data{MeshPrimitive::Points, std::move(positionData), {positions}}; - CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position); - CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Vector2); - CORRADE_COMPARE(static_cast(data.attribute(0).data()), - positionView.data()); + CORRADE_COMPARE(positions.name(), MeshAttribute::Position); + CORRADE_COMPARE(positions.format(), VertexFormat::Vector2); + CORRADE_COMPARE(positions.data().data(), positionView.data()); } void MeshDataTest::constructAttribute2DWrongSize() { - Containers::Array positionData{4*sizeof(Vector2)}; + char positionData[4*sizeof(Vector2)]{}; std::ostringstream out; Error redirectError{&out}; @@ -393,7 +384,7 @@ void MeshDataTest::constructAttribute2DWrongSize() { } void MeshDataTest::constructAttribute2DNonContiguous() { - Containers::Array positionData{4*sizeof(Vector2)}; + char positionData[4*sizeof(Vector2)]{}; std::ostringstream out; Error redirectError{&out}; @@ -404,19 +395,15 @@ void MeshDataTest::constructAttribute2DNonContiguous() { } void MeshDataTest::constructAttributeTypeErased() { - Containers::Array positionData{3*sizeof(Vector3)}; - auto positionView = Containers::arrayCast(positionData); - - MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector3, Containers::arrayCast(Containers::stridedArrayView(positionView))}; - MeshData data{MeshPrimitive::Points, std::move(positionData), {positions}}; - CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position); - CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Vector3); - CORRADE_COMPARE(static_cast(data.attribute(0).data()), - positionView.data()); + const Vector3 positionData[3]{}; + MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector3, Containers::arrayCast(Containers::stridedArrayView(positionData))}; + CORRADE_COMPARE(positions.name(), MeshAttribute::Position); + CORRADE_COMPARE(positions.format(), VertexFormat::Vector3); + CORRADE_VERIFY(positions.data().data() == positionData); } void MeshDataTest::constructAttributeTypeErasedWrongStride() { - Containers::Array positionData{3*sizeof(Vector3)}; + char positionData[3*sizeof(Vector3)]{}; std::ostringstream out; Error redirectError{&out}; @@ -426,10 +413,9 @@ void MeshDataTest::constructAttributeTypeErasedWrongStride() { void MeshDataTest::constructAttributeNullptr() { MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector2, nullptr}; - MeshData data{MeshPrimitive::LineLoop, nullptr, {positions}}; - CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position); - CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Vector2); - CORRADE_VERIFY(!data.attribute(0).data()); + CORRADE_COMPARE(positions.name(), MeshAttribute::Position); + CORRADE_COMPARE(positions.format(), VertexFormat::Vector2); + CORRADE_VERIFY(!positions.data().data()); } void MeshDataTest::constructAttributeNonOwningArray() {