Browse Source

Trade: expose getters in MeshAttributeData.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
5f35b06d8f
  1. 58
      src/Magnum/Trade/MeshData.cpp
  2. 40
      src/Magnum/Trade/MeshData.h
  3. 80
      src/Magnum/Trade/Test/MeshDataTest.cpp

58
src/Magnum/Trade/MeshData.cpp

@ -72,7 +72,7 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& 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<char>&& inde
constructors */
for(std::size_t i = 0; i != _attributes.size(); ++i) {
const MeshAttributeData& attribute = _attributes[i];
const Containers::StridedArrayView1D<const char> data = Containers::arrayCast<const char>(attribute.data);
const Containers::StridedArrayView1D<const char> data = Containers::arrayCast<const char>(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<const void*>(&data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(&data.back() + vertexFormatSize(attribute.format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_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<const void*>(&data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(&data.back() + vertexFormatSize(attribute._format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_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<const char*>(_attributes[id].data.data()) - _vertexData.data();
return static_cast<const char*>(_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<const char> 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<char> MeshData::mutableAttribute(UnsignedInt id) {
@ -254,8 +254,8 @@ Containers::StridedArrayView2D<char> 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<char>{
/* 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<Vector2> 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<const Vector2>(attribute.data), destination);
if(attribute._format == VertexFormat::Vector2 ||
attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
@ -337,16 +337,16 @@ void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3> 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<const Vector2>(attribute.data),
if(attribute._format == VertexFormat::Vector2) {
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data),
Containers::arrayCast<Vector2>(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<const Vector3>(attribute.data), destination);
} else if(attribute._format == VertexFormat::Vector3) {
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination);
} else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
@ -362,8 +362,8 @@ void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3> 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<const Vector3>(attribute.data), destination);
if(attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
@ -379,8 +379,8 @@ void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vec
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
if(attribute.format == VertexFormat::Vector2)
Utility::copy(Containers::arrayCast<const Vector2>(attribute.data), destination);
if(attribute._format == VertexFormat::Vector2)
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
@ -398,16 +398,16 @@ void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4> 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<const Vector3>(attribute.data),
if(attribute._format == VertexFormat::Vector3) {
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data),
Containers::arrayCast<Vector3>(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<const Vector4>(attribute.data),
} else if(attribute._format == VertexFormat::Vector4) {
Utility::copy(Containers::arrayCast<const Vector4>(attribute._data),
Containers::arrayCast<Vector4>(destination));
} else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}

40
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<class T> constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::ArrayView<T>& 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<const void> data() const { return _data; }
private:
constexpr explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const void>& 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<const void> data;
VertexFormat _format;
Containers::StridedArrayView1D<const void> _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<const void>& 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<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(Un
#ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {};
#endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format,
"Trade::MeshData::attribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr);
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _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<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(U
#ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {};
#endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format,
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr);
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _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<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(Me
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id);
#endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[attributeId].format,
"Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId].name << "of format" << _attributes[attributeId].format, nullptr);
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _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<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(M
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id);
#endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[attributeId].format,
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId].name << "of type" << _attributes[attributeId].format, nullptr);
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _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);
}

80
src/Magnum/Trade/Test/MeshDataTest.cpp

@ -329,60 +329,51 @@ constexpr Vector2 Positions[] {
};
void MeshDataTest::constructAttribute() {
Containers::Array<char> positionData{3*sizeof(Vector2)};
auto positionView = Containers::arrayCast<Vector2>(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<const void*>(data.attribute<Vector2>(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<const void*>(cdata.attribute<Vector2>(0).data()),
Positions);
constexpr MeshAttribute name = cpositions.name();
constexpr VertexFormat format = cpositions.format();
constexpr Containers::StridedArrayView1D<const void> data = cpositions.data();
CORRADE_COMPARE(name, MeshAttribute::Position);
CORRADE_COMPARE(format, VertexFormat::Vector2);
CORRADE_COMPARE(data.data(), Positions);
}
void MeshDataTest::constructAttributeCustom() {
Containers::Array<char> idData{3*sizeof(Short)};
auto idView = Containers::arrayCast<Short>(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<const void*>(data.attribute<Short>(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<char> positionData{3*sizeof(Vector2)};
Vector2 positionData[3];
std::ostringstream out;
Error redirectError{&out};
MeshAttributeData{MeshAttribute::Color, Containers::arrayCast<Vector2>(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<char> positionData{4*sizeof(Vector2)};
char positionData[4*sizeof(Vector2)]{};
auto positionView = Containers::StridedArrayView2D<char>{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<const void*>(data.attribute<Vector2>(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<char> 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<char> 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<char> positionData{3*sizeof(Vector3)};
auto positionView = Containers::arrayCast<Vector3>(positionData);
MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector3, Containers::arrayCast<const char>(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<const void*>(data.attribute<Vector3>(0).data()),
positionView.data());
const Vector3 positionData[3]{};
MeshAttributeData positions{MeshAttribute::Position, VertexFormat::Vector3, Containers::arrayCast<const char>(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<char> 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<Vector2>(0).data());
CORRADE_COMPARE(positions.name(), MeshAttribute::Position);
CORRADE_COMPARE(positions.format(), VertexFormat::Vector2);
CORRADE_VERIFY(!positions.data().data());
}
void MeshDataTest::constructAttributeNonOwningArray() {

Loading…
Cancel
Save