Browse Source

Trade: typeless access to MeshData attributes.

Similarly to ImageData::pixels() which return a strided array view of
one dimension more.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
e3ee1e561e
  1. 48
      src/Magnum/Trade/MeshData.cpp
  2. 103
      src/Magnum/Trade/MeshData.h
  3. 109
      src/Magnum/Trade/Test/MeshDataTest.cpp

48
src/Magnum/Trade/MeshData.cpp

@ -49,6 +49,16 @@ MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexForma
"Trade::MeshAttributeData: view stride" << data.stride() << "is not large enough to contain" << format, ); "Trade::MeshAttributeData: view stride" << data.stride() << "is not large enough to contain" << format, );
} }
MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView2D<const char>& data) noexcept: MeshAttributeData{name, format, Containers::StridedArrayView1D<const void>{{data.data(), ~std::size_t{}}, data.size()[0], data.stride()[0]}, nullptr} {
/* Yes, this calls into a constexpr function defined in the header --
because I feel that makes more sense than duplicating the full assert
logic */
CORRADE_ASSERT(data.empty()[0] || vertexFormatSize(format) == data.size()[1],
"Trade::MeshAttributeData: second view dimension size" << data.size()[1] << "doesn't match" << format, );
CORRADE_ASSERT(data.isContiguous<1>(),
"Trade::MeshAttributeData: second view dimension is not contiguous", );
}
Containers::Array<MeshAttributeData> meshAttributeDataNonOwningArray(const Containers::ArrayView<const MeshAttributeData> view) { Containers::Array<MeshAttributeData> meshAttributeDataNonOwningArray(const Containers::ArrayView<const MeshAttributeData> view) {
/* Ugly, eh? */ /* Ugly, eh? */
return Containers::Array<Trade::MeshAttributeData>{const_cast<Trade::MeshAttributeData*>(view.data()), view.size(), reinterpret_cast<void(*)(Trade::MeshAttributeData*, std::size_t)>(Trade::Implementation::nonOwnedArrayDeleter)}; return Containers::Array<Trade::MeshAttributeData>{const_cast<Trade::MeshAttributeData*>(view.data()), view.size(), reinterpret_cast<void(*)(Trade::MeshAttributeData*, std::size_t)>(Trade::Implementation::nonOwnedArrayDeleter)};
@ -230,6 +240,44 @@ UnsignedInt MeshData::attributeStride(MeshAttribute name, UnsignedInt id) const
return attributeStride(attributeId); return attributeStride(attributeId);
} }
Containers::StridedArrayView2D<const char> MeshData::attribute(UnsignedInt id) const {
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));
}
Containers::StridedArrayView2D<char> MeshData::mutableAttribute(UnsignedInt id) {
CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable,
"Trade::MeshData::mutableAttribute(): vertex data not mutable", {});
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));
/** @todo some arrayConstCast? UGH */
return Containers::StridedArrayView2D<char>{
/* The view size is there only for a size assert, we're pretty sure the
view is valid */
{static_cast<char*>(const_cast<void*>(out.data())), ~std::size_t{}},
out.size(), out.stride()};
}
Containers::StridedArrayView2D<const char> MeshData::attribute(MeshAttribute name, UnsignedInt id) const {
const UnsignedInt attributeId = attributeFor(name, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {});
return attribute(attributeId);
}
Containers::StridedArrayView2D<char> MeshData::mutableAttribute(MeshAttribute name, UnsignedInt id) {
CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable,
"Trade::MeshData::mutableAttribute(): vertex data not mutable", {});
const UnsignedInt attributeId = attributeFor(name, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {});
return mutableAttribute(attributeId);
}
namespace { namespace {
template<class T> void convertIndices(const Containers::ArrayView<const char> data, const Containers::ArrayView<UnsignedInt> destination) { template<class T> void convertIndices(const Containers::ArrayView<const char> data, const Containers::ArrayView<UnsignedInt> destination) {

103
src/Magnum/Trade/MeshData.h

@ -229,6 +229,20 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
*/ */
explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const void>& data) noexcept; explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const void>& data) noexcept;
/**
* @brief Constructor
* @param name Attribute name
* @param format Vertex format
* @param data Attribute data
*
* Expects that the second dimension of @p data is contiguous and its
* size matches @p type; and that @p type corresponds to @p name.
*/
explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView2D<const char>& data) noexcept;
/** @overload */
explicit MeshAttributeData(MeshAttribute name, VertexFormat format, std::nullptr_t) noexcept: MeshAttributeData{name, format, nullptr, nullptr} {}
/** /**
* @brief Constructor * @brief Constructor
* @param name Attribute name * @param name Attribute name
@ -762,6 +776,26 @@ class MAGNUM_TRADE_EXPORT MeshData {
/** /**
* @brief Data for given attribute array * @brief Data for given attribute array
* *
* The @p id is expected to be smaller than @ref attributeCount() const.
* The second dimension represents the actual data type (its size is
* equal to type size) and is guaranteed to be contiguous. Use the
* templated overload below to get the attribute in a concrete type.
* @see @ref Corrade::Containers::StridedArrayView::isContiguous()
*/
Containers::StridedArrayView2D<const char> attribute(UnsignedInt id) const;
/**
* @brief Mutable data for given attribute array
*
* Like @ref attribute(UnsignedInt) const, but returns a mutable view.
* Expects that the mesh is mutable.
* @see @ref vertexDataFlags()
*/
Containers::StridedArrayView2D<char> mutableAttribute(UnsignedInt id);
/**
* @brief Data for given attribute array in a concrete type
*
* The @p id is expected to be smaller than @ref attributeCount() const * The @p id is expected to be smaller than @ref attributeCount() const
* and @p T is expected to correspond to * and @p T is expected to correspond to
* @ref attributeFormat(UnsignedInt) const. You can also use the * @ref attributeFormat(UnsignedInt) const. You can also use the
@ -776,7 +810,7 @@ class MAGNUM_TRADE_EXPORT MeshData {
template<class T> Containers::StridedArrayView1D<const T> attribute(UnsignedInt id) const; template<class T> Containers::StridedArrayView1D<const T> attribute(UnsignedInt id) const;
/** /**
* @brief Mutable data for given attribute array * @brief Mutable data for given attribute array in a concrete type
* *
* Like @ref attribute(UnsignedInt) const, but returns a mutable view. * Like @ref attribute(UnsignedInt) const, but returns a mutable view.
* Expects that the mesh is mutable. * Expects that the mesh is mutable.
@ -788,6 +822,29 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @brief Data for given named attribute array * @brief Data for given named attribute array
* *
* The @p id is expected to be smaller than * The @p id is expected to be smaller than
* @ref attributeCount(MeshAttribute) const. The second dimension
* represents the actual data type (its size is equal to type size) and
* is guaranteed to be contiguous. Use the templated overload below to
* get the attribute in a concrete type.
* @see @ref attribute(UnsignedInt) const,
* @ref mutableAttribute(MeshAttribute, UnsignedInt),
* @ref Corrade::Containers::StridedArrayView::isContiguous()
*/
Containers::StridedArrayView2D<const char> attribute(MeshAttribute name, UnsignedInt id = 0) const;
/**
* @brief Mutable data for given named attribute array
*
* Like @ref attribute(MeshAttribute, UnsignedInt) const, but returns a
* mutable view. Expects that the mesh is mutable.
* @see @ref vertexDataFlags()
*/
Containers::StridedArrayView2D<char> mutableAttribute(MeshAttribute name, UnsignedInt id = 0);
/**
* @brief Data for given named attribute array in a concrete type
*
* The @p id is expected to be smaller than
* @ref attributeCount(MeshAttribute) const and @p T is expected to * @ref attributeCount(MeshAttribute) const and @p T is expected to
* correspond to @ref attributeFormat(MeshAttribute, UnsignedInt) const. * correspond to @ref attributeFormat(MeshAttribute, UnsignedInt) const.
* You can also use the non-templated @ref positions2DAsArray(), * You can also use the non-templated @ref positions2DAsArray(),
@ -802,7 +859,7 @@ class MAGNUM_TRADE_EXPORT MeshData {
template<class T> Containers::StridedArrayView1D<const T> attribute(MeshAttribute name, UnsignedInt id = 0) const; template<class T> Containers::StridedArrayView1D<const T> attribute(MeshAttribute name, UnsignedInt id = 0) const;
/** /**
* @brief Mutable data for given named attribute array * @brief Mutable data for given named attribute array in a concrete type
* *
* Like @ref attribute(MeshAttribute, UnsignedInt) const, but returns a * Like @ref attribute(MeshAttribute, UnsignedInt) const, but returns a
* mutable view. Expects that the mesh is mutable. * mutable view. Expects that the mesh is mutable.
@ -1066,35 +1123,49 @@ template<class T> Containers::ArrayView<T> MeshData::mutableIndices() {
} }
template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(UnsignedInt id) const { template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(), Containers::StridedArrayView2D<const char> data = attribute(id);
"Trade::MeshData::attribute(): index" << id << "out of range for" << _attributes.size() << "attributes", nullptr); #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {};
#endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format, CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format,
"Trade::MeshData::attribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr); "Trade::MeshData::attribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr);
return Containers::arrayCast<const T>(_attributes[id].data); return Containers::arrayCast<1, const T>(data);
} }
template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(UnsignedInt id) { template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(UnsignedInt id) {
CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable, Containers::StridedArrayView2D<char> data = mutableAttribute(id);
"Trade::MeshData::mutableAttribute(): vertex data not mutable", {}); #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
CORRADE_ASSERT(id < _attributes.size(), if(!data.stride()[1]) return {};
"Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << _attributes.size() << "attributes", nullptr); #endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format, CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id].format,
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr); "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id].name << "of format" << _attributes[id].format, nullptr);
return Containers::arrayCast<T>(reinterpret_cast<Containers::StridedArrayView1D<char>&>(_attributes[id].data)); return Containers::arrayCast<1, T>(data);
} }
template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(MeshAttribute name, UnsignedInt id) const { template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(MeshAttribute name, UnsignedInt id) const {
Containers::StridedArrayView2D<const char> data = attribute(name, id);
#ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id); const UnsignedInt attributeId = attributeFor(name, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #endif
return attribute<T>(attributeId); 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);
} }
template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(MeshAttribute name, UnsignedInt id) { template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(MeshAttribute name, UnsignedInt id) {
CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable, Containers::StridedArrayView2D<char> data = mutableAttribute(name, id);
"Trade::MeshData::mutableAttribute(): vertex data not mutable", {}); #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id); const UnsignedInt attributeId = attributeFor(name, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #endif
return mutableAttribute<T>(attributeId); 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);
} }
}} }}

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

@ -49,8 +49,12 @@ struct MeshDataTest: TestSuite::Tester {
void constructAttribute(); void constructAttribute();
void constructAttributeCustom(); void constructAttributeCustom();
void constructAttributeWrongFormat(); void constructAttributeWrongFormat();
void constructAttribute2D();
void constructAttribute2DWrongSize();
void constructAttribute2DNonContiguous();
void constructAttributeTypeErased(); void constructAttributeTypeErased();
void constructAttributeTypeErasedWrongStride(); void constructAttributeTypeErasedWrongStride();
void constructAttributeNullptr();
void constructAttributeNonOwningArray(); void constructAttributeNonOwningArray();
void construct(); void construct();
@ -140,8 +144,12 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::constructAttribute, &MeshDataTest::constructAttribute,
&MeshDataTest::constructAttributeCustom, &MeshDataTest::constructAttributeCustom,
&MeshDataTest::constructAttributeWrongFormat, &MeshDataTest::constructAttributeWrongFormat,
&MeshDataTest::constructAttribute2D,
&MeshDataTest::constructAttribute2DWrongSize,
&MeshDataTest::constructAttribute2DNonContiguous,
&MeshDataTest::constructAttributeTypeErased, &MeshDataTest::constructAttributeTypeErased,
&MeshDataTest::constructAttributeTypeErasedWrongStride, &MeshDataTest::constructAttributeTypeErasedWrongStride,
&MeshDataTest::constructAttributeNullptr,
&MeshDataTest::constructAttributeNonOwningArray, &MeshDataTest::constructAttributeNonOwningArray,
&MeshDataTest::construct, &MeshDataTest::construct,
@ -376,6 +384,41 @@ void MeshDataTest::constructAttributeWrongFormat() {
CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: VertexFormat::Vector2 is not a valid format for Trade::MeshAttribute::Color\n"); 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)};
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());
}
void MeshDataTest::constructAttribute2DWrongSize() {
Containers::Array<char> positionData{4*sizeof(Vector2)};
std::ostringstream out;
Error redirectError{&out};
MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3,
Containers::StridedArrayView2D<char>{positionData,
{4, sizeof(Vector2)}}.every(2)};
CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: second view dimension size 8 doesn't match VertexFormat::Vector3\n");
}
void MeshDataTest::constructAttribute2DNonContiguous() {
Containers::Array<char> positionData{4*sizeof(Vector2)};
std::ostringstream out;
Error redirectError{&out};
MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector2,
Containers::StridedArrayView2D<char>{positionData,
{2, sizeof(Vector2)*2}}.every({1, 2})};
CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: second view dimension is not contiguous\n");
}
void MeshDataTest::constructAttributeTypeErased() { void MeshDataTest::constructAttributeTypeErased() {
Containers::Array<char> positionData{3*sizeof(Vector3)}; Containers::Array<char> positionData{3*sizeof(Vector3)};
auto positionView = Containers::arrayCast<Vector3>(positionData); auto positionView = Containers::arrayCast<Vector3>(positionData);
@ -397,6 +440,14 @@ void MeshDataTest::constructAttributeTypeErasedWrongStride() {
CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: view stride 1 is not large enough to contain VertexFormat::Vector3\n"); CORRADE_COMPARE(out.str(), "Trade::MeshAttributeData: view stride 1 is not large enough to contain VertexFormat::Vector3\n");
} }
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());
}
void MeshDataTest::constructAttributeNonOwningArray() { void MeshDataTest::constructAttributeNonOwningArray() {
const MeshAttributeData data[3]; const MeshAttributeData data[3];
Containers::Array<MeshAttributeData> array = meshAttributeDataNonOwningArray(data); Containers::Array<MeshAttributeData> array = meshAttributeDataNonOwningArray(data);
@ -491,6 +542,30 @@ void MeshDataTest::construct() {
CORRADE_COMPARE(data.attributeStride(1), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(1), sizeof(Vertex));
CORRADE_COMPARE(data.attributeStride(2), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(2), sizeof(Vertex));
CORRADE_COMPARE(data.attributeStride(3), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(3), sizeof(Vertex));
/* 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);
/* Typed access by ID */
CORRADE_COMPARE(data.attribute<Vector3>(0)[1], (Vector3{0.4f, 0.5f, 0.6f})); CORRADE_COMPARE(data.attribute<Vector3>(0)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.attribute<Vector2>(1)[0], (Vector2{0.000f, 0.125f})); CORRADE_COMPARE(data.attribute<Vector2>(1)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.attribute<Vector3>(2)[2], Vector3::zAxis()); CORRADE_COMPARE(data.attribute<Vector3>(2)[2], Vector3::zAxis());
@ -534,6 +609,30 @@ void MeshDataTest::construct() {
CORRADE_COMPARE(data.attributeStride(MeshAttribute::TextureCoordinates, 0), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(MeshAttribute::TextureCoordinates, 0), sizeof(Vertex));
CORRADE_COMPARE(data.attributeStride(MeshAttribute::TextureCoordinates, 1), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(MeshAttribute::TextureCoordinates, 1), sizeof(Vertex));
CORRADE_COMPARE(data.attributeStride(meshAttributeCustom(13)), sizeof(Vertex)); CORRADE_COMPARE(data.attributeStride(meshAttributeCustom(13)), sizeof(Vertex));
/* 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);
/* Typed access by name */
CORRADE_COMPARE(data.attribute<Vector3>(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f})); CORRADE_COMPARE(data.attribute<Vector3>(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.attribute<Vector3>(MeshAttribute::Normal)[2], Vector3::zAxis()); CORRADE_COMPARE(data.attribute<Vector3>(MeshAttribute::Normal)[2], Vector3::zAxis());
CORRADE_COMPARE(data.attribute<Vector2>(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f})); CORRADE_COMPARE(data.attribute<Vector2>(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f}));
@ -1275,13 +1374,17 @@ void MeshDataTest::mutableAccessNotAllowed() {
data.mutableIndexData(); data.mutableIndexData();
data.mutableVertexData(); data.mutableVertexData();
data.mutableIndices<UnsignedShort>(); data.mutableIndices<UnsignedShort>();
data.mutableAttribute(0);
data.mutableAttribute<Vector2>(0); data.mutableAttribute<Vector2>(0);
data.mutableAttribute(MeshAttribute::Position);
data.mutableAttribute<Vector2>(MeshAttribute::Position); data.mutableAttribute<Vector2>(MeshAttribute::Position);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::MeshData::mutableIndexData(): index data not mutable\n" "Trade::MeshData::mutableIndexData(): index data not mutable\n"
"Trade::MeshData::mutableVertexData(): vertex data not mutable\n" "Trade::MeshData::mutableVertexData(): vertex data not mutable\n"
"Trade::MeshData::mutableIndices(): index data not mutable\n" "Trade::MeshData::mutableIndices(): index data not mutable\n"
"Trade::MeshData::mutableAttribute(): vertex data not mutable\n" "Trade::MeshData::mutableAttribute(): vertex data not mutable\n"
"Trade::MeshData::mutableAttribute(): vertex data not mutable\n"
"Trade::MeshData::mutableAttribute(): vertex data not mutable\n"
"Trade::MeshData::mutableAttribute(): vertex data not mutable\n"); "Trade::MeshData::mutableAttribute(): vertex data not mutable\n");
} }
@ -1327,6 +1430,7 @@ void MeshDataTest::attributeNotFound() {
data.attributeFormat(2); data.attributeFormat(2);
data.attributeOffset(2); data.attributeOffset(2);
data.attributeStride(2); data.attributeStride(2);
data.attribute(2);
data.attribute<Vector2>(2); data.attribute<Vector2>(2);
data.attributeFormat(MeshAttribute::Position); data.attributeFormat(MeshAttribute::Position);
data.attributeFormat(MeshAttribute::Color, 2); data.attributeFormat(MeshAttribute::Color, 2);
@ -1334,6 +1438,8 @@ void MeshDataTest::attributeNotFound() {
data.attributeOffset(MeshAttribute::Color, 2); data.attributeOffset(MeshAttribute::Color, 2);
data.attributeStride(MeshAttribute::Position); data.attributeStride(MeshAttribute::Position);
data.attributeStride(MeshAttribute::Color, 2); data.attributeStride(MeshAttribute::Color, 2);
data.attribute(MeshAttribute::Position);
data.attribute(MeshAttribute::Color, 2);
data.attribute<Vector2>(MeshAttribute::Position); data.attribute<Vector2>(MeshAttribute::Position);
data.attribute<Vector2>(MeshAttribute::Color, 2); data.attribute<Vector2>(MeshAttribute::Color, 2);
data.positions2DAsArray(); data.positions2DAsArray();
@ -1347,6 +1453,7 @@ void MeshDataTest::attributeNotFound() {
"Trade::MeshData::attributeOffset(): index 2 out of range for 2 attributes\n" "Trade::MeshData::attributeOffset(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attributeStride(): index 2 out of range for 2 attributes\n" "Trade::MeshData::attributeStride(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attribute(): index 2 out of range for 2 attributes\n" "Trade::MeshData::attribute(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attribute(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attributeFormat(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n" "Trade::MeshData::attributeFormat(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n"
"Trade::MeshData::attributeFormat(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n" "Trade::MeshData::attributeFormat(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n"
"Trade::MeshData::attributeOffset(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n" "Trade::MeshData::attributeOffset(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n"
@ -1355,6 +1462,8 @@ void MeshDataTest::attributeNotFound() {
"Trade::MeshData::attributeStride(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n" "Trade::MeshData::attributeStride(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n"
"Trade::MeshData::attribute(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n" "Trade::MeshData::attribute(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n"
"Trade::MeshData::attribute(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n" "Trade::MeshData::attribute(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n"
"Trade::MeshData::attribute(): index 0 out of range for 0 Trade::MeshAttribute::Position attributes\n"
"Trade::MeshData::attribute(): index 2 out of range for 2 Trade::MeshAttribute::Color attributes\n"
"Trade::MeshData::positions2DInto(): index 0 out of range for 0 position attributes\n" "Trade::MeshData::positions2DInto(): index 0 out of range for 0 position attributes\n"
"Trade::MeshData::positions3DInto(): index 0 out of range for 0 position attributes\n" "Trade::MeshData::positions3DInto(): index 0 out of range for 0 position attributes\n"
"Trade::MeshData::normalsInto(): index 0 out of range for 0 normal attributes\n" "Trade::MeshData::normalsInto(): index 0 out of range for 0 normal attributes\n"

Loading…
Cancel
Save