Browse Source

Trade: handle implementation-specific vertex formats in MeshData.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
a29e9dc009
  1. 33
      src/Magnum/Trade/MeshData.cpp
  2. 123
      src/Magnum/Trade/MeshData.h
  3. 134
      src/Magnum/Trade/Test/MeshDataTest.cpp

33
src/Magnum/Trade/MeshData.cpp

@ -56,7 +56,7 @@ MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexForma
because I feel that makes more sense than duplicating the full assert
logic */
/** @todo support zero / negative stride? would be hard to transfer to GL */
CORRADE_ASSERT(data.empty() || std::ptrdiff_t(vertexFormatSize(format)) <= data.stride(),
CORRADE_ASSERT(data.empty() || isVertexFormatImplementationSpecific(format) || std::ptrdiff_t(vertexFormatSize(format)) <= data.stride(),
"Trade::MeshAttributeData: expected stride to be positive and enough to fit" << format << Debug::nospace << ", got" << data.stride(), );
}
@ -64,7 +64,7 @@ MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexForma
/* 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],
CORRADE_ASSERT(data.empty()[0] || isVertexFormatImplementationSpecific(format) || 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", );
@ -99,7 +99,12 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
"Trade::MeshData: attribute" << i << "doesn't specify anything", );
CORRADE_ASSERT(attribute._vertexCount == _vertexCount,
"Trade::MeshData: attribute" << i << "has" << attribute._vertexCount << "vertices but" << _vertexCount << "expected", );
const UnsignedInt typeSize = vertexFormatSize(attribute._format);
/* 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. */
const UnsignedInt typeSize =
isVertexFormatImplementationSpecific(attribute._format) ? 0 :
vertexFormatSize(attribute._format);
if(attribute._isOffsetOnly) {
const std::size_t size = attribute._data.offset + (_vertexCount - 1)*attribute._stride + typeSize;
CORRADE_ASSERT(!_vertexCount || size <= _vertexData.size(),
@ -317,10 +322,12 @@ Containers::StridedArrayView1D<const void> MeshData::attributeDataViewInternal(c
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);
const MeshAttributeData& attribute = _attributes[id];
/* Build a 2D view using information about attribute type size */
return Containers::arrayCast<2, const char>(
attributeDataViewInternal(_attributes[id]),
vertexFormatSize(_attributes[id]._format));
attributeDataViewInternal(attribute),
isVertexFormatImplementationSpecific(attribute._format) ?
attribute._stride : vertexFormatSize(attribute._format));
}
Containers::StridedArrayView2D<char> MeshData::mutableAttribute(UnsignedInt id) {
@ -328,10 +335,12 @@ Containers::StridedArrayView2D<char> MeshData::mutableAttribute(UnsignedInt id)
"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);
const MeshAttributeData& attribute = _attributes[id];
/* Build a 2D view using information about attribute type size */
auto out = Containers::arrayCast<2, const char>(
attributeDataViewInternal(_attributes[id]),
vertexFormatSize(_attributes[id]._format));
attributeDataViewInternal(attribute),
isVertexFormatImplementationSpecific(attribute._format) ?
attribute._stride : vertexFormatSize(attribute._format));
/** @todo some arrayConstCast? UGH */
return Containers::StridedArrayView2D<char>{
/* The view size is there only for a size assert, we're pretty sure the
@ -391,6 +400,8 @@ void MeshData::positions2DInto(const Containers::StridedArrayView1D<Vector2> des
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::positions2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position) << "position attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::positions2DInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const auto destination2f = Containers::arrayCast<2, Float>(destination);
@ -439,6 +450,8 @@ void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3> des
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::positions3DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position) << "position attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions3DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::positions3DInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const Containers::StridedArrayView2D<Float> destination2f = Containers::arrayCast<2, Float>(Containers::arrayCast<Vector2>(destination));
const Containers::StridedArrayView2D<Float> destination3f = Containers::arrayCast<2, Float>(destination);
@ -518,6 +531,8 @@ void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3> destina
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::normalsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Normal) << "normal attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::normalsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const auto destination3f = Containers::arrayCast<2, Float>(destination);
@ -543,6 +558,8 @@ void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vec
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::textureCoordinates2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::TextureCoordinates) << "texture coordinate attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::textureCoordinatesInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const auto destination2f = Containers::arrayCast<2, Float>(destination);
@ -580,6 +597,8 @@ void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4> destinati
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::colorsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Color) << "color attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::colorsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::colorsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const Containers::StridedArrayView2D<Float> destination3f = Containers::arrayCast<2, Float>(Containers::arrayCast<Vector3>(destination));
const Containers::StridedArrayView2D<Float> destination4f = Containers::arrayCast<2, Float>(destination);

123
src/Magnum/Trade/MeshData.h

@ -1001,9 +1001,12 @@ class MAGNUM_TRADE_EXPORT MeshData {
*
* 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()
* equal to format size for known @ref VertexFormat values and to
* attribute stride for implementation-specific values) 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(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::StridedArrayView2D<const char> attribute(UnsignedInt id) const;
@ -1021,14 +1024,18 @@ class MAGNUM_TRADE_EXPORT MeshData {
*
* The @p id is expected to be smaller than @ref attributeCount() const
* and @p T is expected to correspond to
* @ref attributeFormat(UnsignedInt) const. You can also use the
* non-templated @ref positions2DAsArray(), @ref positions3DAsArray(),
* @ref normalsAsArray(), @ref textureCoordinates2DAsArray() and
* @ref colorsAsArray() accessors to get common attributes converted to
* usual types, but note that these operations involve extra allocation
* and data conversion.
* @ref attributeFormat(UnsignedInt) const. Expects that the vertex
* format is *not* implementation-specific, in that case you can only
* access the attribute via the typeless @ref attribute(UnsignedInt) const
* above. You can also use the non-templated @ref positions2DAsArray(),
* @ref positions3DAsArray(), @ref normalsAsArray(),
* @ref textureCoordinates2DAsArray() and @ref colorsAsArray()
* accessors to get common attributes converted to usual types, but
* note that these operations involve extra allocation and data
* conversion.
* @see @ref attribute(MeshAttribute, UnsignedInt) const,
* @ref mutableAttribute(MeshAttribute, UnsignedInt)
* @ref mutableAttribute(MeshAttribute, UnsignedInt),
* @ref isVertexFormatImplementationSpecific()
*/
template<class T> Containers::StridedArrayView1D<const T> attribute(UnsignedInt id) const;
@ -1046,12 +1053,15 @@ class MAGNUM_TRADE_EXPORT MeshData {
*
* 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.
* represents the actual data type (its size is equal to format size
* for known @ref VertexFormat values and to attribute stride for
* implementation-specific values) 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()
* @ref Corrade::Containers::StridedArrayView::isContiguous(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::StridedArrayView2D<const char> attribute(MeshAttribute name, UnsignedInt id = 0) const;
@ -1070,14 +1080,18 @@ class MAGNUM_TRADE_EXPORT MeshData {
* The @p id is expected to be smaller than
* @ref attributeCount(MeshAttribute) const and @p T is expected to
* correspond to @ref attributeFormat(MeshAttribute, UnsignedInt) const.
* You can also use the non-templated @ref positions2DAsArray(),
* Expects that the vertex format is *not* implementation-specific, in
* that case you can only access the attribute via the typeless
* @ref attribute(MeshAttribute, UnsignedInt) const above. You can also
* use the non-templated @ref positions2DAsArray(),
* @ref positions3DAsArray(), @ref normalsAsArray(),
* @ref textureCoordinates2DAsArray() and @ref colorsAsArray()
* accessors to get common attributes converted to usual types, but
* note that these operations involve extra data conversion and an
* allocation.
* @see @ref attribute(UnsignedInt) const,
* @ref mutableAttribute(MeshAttribute, UnsignedInt)
* @ref mutableAttribute(MeshAttribute, UnsignedInt),
* @ref isVertexFormatImplementationSpecific()
*/
template<class T> Containers::StridedArrayView1D<const T> attribute(MeshAttribute name, UnsignedInt id = 0) const;
@ -1117,8 +1131,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* with @ref MeshAttribute::Position as the first argument. Converts
* the position array from an arbitrary underlying type and returns it
* in a newly-allocated array. If the underlying type is
* three-component, the last component is dropped.
* @see @ref positions2DInto()
* three-component, the last component is dropped. Expects that the
* vertex format is *not* implementation-specific, in that case you can
* only access the attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref positions2DInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<Vector2> positions2DAsArray(UnsignedInt id = 0) const;
@ -1139,8 +1156,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* with @ref MeshAttribute::Position as the first argument. Converts
* the position array from an arbitrary underlying type and returns it
* in a newly-allocated array. If the underlying type is two-component,
* the Z component is set to @cpp 0.0f @ce.
* @see @ref positions3DInto()
* the Z component is set to @cpp 0.0f @ce. Expects that the vertex
* format is *not* implementation-specific, in that case you can only
* access the attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref positions3DInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<Vector3> positions3DAsArray(UnsignedInt id = 0) const;
@ -1160,8 +1180,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const
* with @ref MeshAttribute::Normal as the first argument. Converts the
* normal array from an arbitrary underlying type and returns it in a
* newly-allocated array.
* @see @ref normalsInto()
* newly-allocated array. Expects that the vertex format is *not*
* implementation-specific, in that case you can only access the
* attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref normalsInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<Vector3> normalsAsArray(UnsignedInt id = 0) const;
@ -1181,8 +1204,12 @@ class MAGNUM_TRADE_EXPORT MeshData {
* Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const
* with @ref MeshAttribute::TextureCoordinates as the first argument.
* Converts the texture coordinate array from an arbitrary underlying
* type and returns it in a newly-allocated array.
* @see @ref textureCoordinates2DInto()
* type and returns it in a newly-allocated array. Expects that the
* vertex format is *not* implementation-specific, in that case you can
* only access the attribute via the typeless
* @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref textureCoordinates2DInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<Vector2> textureCoordinates2DAsArray(UnsignedInt id = 0) const;
@ -1203,8 +1230,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* with @ref MeshAttribute::Color as the first argument. Converts the
* color array from an arbitrary underlying type and returns it in a
* newly-allocated array. If the underlying type is three-component,
* the alpha component is set to @cpp 1.0f @ce.
* @see @ref colorsInto()
* the alpha component is set to @cpp 1.0f @ce. Expects that the vertex
* format is *not* implementation-specific, in that case you can only
* access the attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref colorsInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<Color4> colorsAsArray(UnsignedInt id = 0) const;
@ -1407,6 +1437,10 @@ namespace Implementation {
/* Double types intentionally not supported for any builtin attributes
right now -- only for custom types */
return
/* Implementation-specific formats can be used for any attribute
(tho the access capabilities will be reduced) */
isVertexFormatImplementationSpecific(format) ||
/* Named attributes are restricted so we can decode them */
(name == MeshAttribute::Position &&
(format == VertexFormat::Vector2 ||
format == VertexFormat::Vector2h ||
@ -1453,7 +1487,8 @@ namespace Implementation {
format == VertexFormat::Vector2usNormalized ||
format == VertexFormat::Vector2s ||
format == VertexFormat::Vector2sNormalized)) ||
isMeshAttributeCustom(name); /* can be any format */
/* Custom attributes can be anything */
isMeshAttributeCustom(name);
}
}
#endif
@ -1505,8 +1540,13 @@ 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::isVertexFormatCompatible<T>(_attributes[id]._format),
"Trade::MeshData::attribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr);
#ifndef CORRADE_NO_ASSERT
const MeshAttributeData& attribute = _attributes[id];
#endif
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), {});
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(attribute._format),
"Trade::MeshData::attribute(): improper type requested for" << attribute._name << "of format" << attribute._format, nullptr);
return Containers::arrayCast<1, const T>(data);
}
@ -1515,8 +1555,13 @@ 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::isVertexFormatCompatible<T>(_attributes[id]._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr);
#ifndef CORRADE_NO_ASSERT
const MeshAttributeData& attribute = _attributes[id];
#endif
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), {});
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(attribute._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << attribute._name << "of format" << attribute._format, nullptr);
return Containers::arrayCast<1, T>(data);
}
@ -1526,10 +1571,12 @@ template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(Me
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id);
const MeshAttributeData& attribute = _attributes[attributeFor(name, id)];
#endif
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[attributeId]._format),
"Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), {});
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(attribute._format),
"Trade::MeshData::attribute(): improper type requested for" << attribute._name << "of format" << attribute._format, nullptr);
return Containers::arrayCast<1, const T>(data);
}
@ -1539,10 +1586,12 @@ template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(M
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id);
const MeshAttributeData& attribute = _attributes[attributeFor(name, id)];
#endif
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[attributeId]._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), {});
CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(attribute._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << attribute._name << "of format" << attribute._format, nullptr);
return Containers::arrayCast<1, T>(data);
}

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

@ -60,6 +60,7 @@ struct MeshDataTest: TestSuite::Tester {
void constructAttributePadding();
void constructAttributeNonOwningArray();
void constructAttributeOffsetOnly();
void constructAttributeImplementationSpecificFormat();
void constructAttributeWrongFormat();
void constructAttributeWrongStride();
void constructAttributeWrongDataAccess();
@ -123,6 +124,10 @@ struct MeshDataTest: TestSuite::Tester {
template<class T> void colorsAsArrayPackedUnsignedNormalized();
void colorsIntoArrayInvalidSize();
void implementationSpecificVertexFormat();
void implementationSpecificVertexFormatWrongAccess();
void implementationSpecificVertexFormatNotContained();
void mutableAccessNotAllowed();
void indicesNotIndexed();
@ -178,6 +183,7 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::constructAttributePadding,
&MeshDataTest::constructAttributeNonOwningArray,
&MeshDataTest::constructAttributeOffsetOnly,
&MeshDataTest::constructAttributeImplementationSpecificFormat,
&MeshDataTest::constructAttributeWrongFormat,
&MeshDataTest::constructAttributeWrongStride,
&MeshDataTest::constructAttributeWrongDataAccess,
@ -288,6 +294,10 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4us>,
&MeshDataTest::colorsIntoArrayInvalidSize,
&MeshDataTest::implementationSpecificVertexFormat,
&MeshDataTest::implementationSpecificVertexFormatWrongAccess,
&MeshDataTest::implementationSpecificVertexFormatNotContained,
&MeshDataTest::mutableAccessNotAllowed,
&MeshDataTest::indicesNotIndexed,
@ -574,6 +584,18 @@ void MeshDataTest::constructAttributeOffsetOnly() {
TestSuite::Compare::Container);
}
void MeshDataTest::constructAttributeImplementationSpecificFormat() {
Vector2 positions[]{{1.0f, 0.3f}, {0.5f, 0.7f}};
/* This should not fire any asserts */
MeshAttributeData a{MeshAttribute::TextureCoordinates, vertexFormatWrap(0x3a), positions};
CORRADE_COMPARE(a.name(), MeshAttribute::TextureCoordinates);
CORRADE_COMPARE(a.format(), vertexFormatWrap(0x3a));
CORRADE_COMPARE_AS(Containers::arrayCast<const Vector2>(a.data()),
Containers::arrayView<Vector2>({{1.0f, 0.3f}, {0.5f, 0.7f}}),
TestSuite::Compare::Container);
}
void MeshDataTest::constructAttributeWrongFormat() {
Vector2 positionData[3];
@ -1234,6 +1256,8 @@ void MeshDataTest::constructAttributeNotContained() {
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData)};
MeshAttributeData positions2{MeshAttribute::Position, Containers::arrayView(vertexData2)};
MeshAttributeData positions3{MeshAttribute::Position, VertexFormat::Vector2, 1, 3, 8};
/* See implementationSpecificVertexFormatNotContained() below for
implementation-specific formats */
std::ostringstream out;
Error redirectError{&out};
@ -1862,6 +1886,116 @@ void MeshDataTest::colorsIntoArrayInvalidSize() {
"Trade::MeshData::colorsInto(): expected a view with 3 elements but got 2\n");
}
void MeshDataTest::implementationSpecificVertexFormat() {
struct Vertex {
Long:64;
long double thing;
} vertexData[] {
{456.0l},
{456.0l}
};
/* Constructing should work w/o asserts */
Containers::StridedArrayView1D<long double> attribute{vertexData,
&vertexData[0].thing, 2, sizeof(Vertex)};
MeshData data{MeshPrimitive::TriangleFan, DataFlag::Mutable, vertexData, {
MeshAttributeData{MeshAttribute::Position,
vertexFormatWrap(0xdead1), attribute},
MeshAttributeData{MeshAttribute::Normal,
vertexFormatWrap(0xdead2), attribute},
MeshAttributeData{MeshAttribute::TextureCoordinates,
vertexFormatWrap(0xdead3), attribute},
MeshAttributeData{MeshAttribute::Color,
vertexFormatWrap(0xdead4), attribute}}};
/* Getting typeless attribute should work also */
UnsignedInt format = 0xdead1;
for(MeshAttribute name: {MeshAttribute::Position,
MeshAttribute::Normal,
MeshAttribute::TextureCoordinates,
MeshAttribute::Color}) {
CORRADE_ITERATION(name);
CORRADE_COMPARE(data.attributeFormat(name), vertexFormatWrap(format++));
/* The actual type size is unknown, so this will use the full stride */
CORRADE_COMPARE(data.attribute(name).size()[1], sizeof(Vertex));
CORRADE_COMPARE_AS((Containers::arrayCast<1, const long double>(
data.attribute(name).prefix({2, sizeof(long double)}))),
attribute, TestSuite::Compare::Container);
CORRADE_COMPARE_AS((Containers::arrayCast<1, const long double>(
data.mutableAttribute(name).prefix({2, sizeof(long double)}))),
attribute, TestSuite::Compare::Container);
}
}
void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
struct Vertex {
Long:64;
long double thing;
} vertexData[] {
{456.0l},
{456.0l}
};
Containers::StridedArrayView1D<long double> attribute{vertexData,
&vertexData[0].thing, 2, sizeof(Vertex)};
MeshData data{MeshPrimitive::TriangleFan, DataFlag::Mutable, vertexData, {
MeshAttributeData{MeshAttribute::Position,
vertexFormatWrap(0xdead1), attribute},
MeshAttributeData{MeshAttribute::Normal,
vertexFormatWrap(0xdead2), attribute},
MeshAttributeData{MeshAttribute::TextureCoordinates,
vertexFormatWrap(0xdead3), attribute},
MeshAttributeData{MeshAttribute::Color,
vertexFormatWrap(0xdead4), attribute}}};
std::ostringstream out;
Error redirectError{&out};
data.attribute<Float>(MeshAttribute::Position);
data.attribute<Float>(MeshAttribute::Normal);
data.attribute<Float>(MeshAttribute::TextureCoordinates);
data.attribute<Float>(MeshAttribute::Color);
data.mutableAttribute<Float>(MeshAttribute::Position);
data.mutableAttribute<Float>(MeshAttribute::Normal);
data.mutableAttribute<Float>(MeshAttribute::TextureCoordinates);
data.mutableAttribute<Float>(MeshAttribute::Color);
data.positions2DAsArray();
data.positions3DAsArray();
data.normalsAsArray();
data.textureCoordinates2DAsArray();
data.colorsAsArray();
CORRADE_COMPARE(out.str(),
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead1\n"
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead2\n"
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead3\n"
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead4\n"
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format 0xdead1\n"
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format 0xdead2\n"
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format 0xdead3\n"
"Trade::MeshData::mutableAttribute(): can't cast data from an implementation-specific vertex format 0xdead4\n"
"Trade::MeshData::positions2DInto(): can't extract data out of an implementation-specific vertex format 0xdead1\n"
"Trade::MeshData::positions3DInto(): can't extract data out of an implementation-specific vertex format 0xdead1\n"
"Trade::MeshData::normalsInto(): can't extract data out of an implementation-specific vertex format 0xdead2\n"
"Trade::MeshData::textureCoordinatesInto(): can't extract data out of an implementation-specific vertex format 0xdead3\n"
"Trade::MeshData::colorsInto(): can't extract data out of an implementation-specific vertex format 0xdead4\n");
}
void MeshDataTest::implementationSpecificVertexFormatNotContained() {
Containers::Array<char> vertexData{reinterpret_cast<char*>(0xbadda9), 3, [](char*, std::size_t){}};
Containers::ArrayView<char> vertexData2{reinterpret_cast<char*>(0xdead), 3};
MeshAttributeData positions{MeshAttribute::Position, vertexFormatWrap(0x3a), vertexData};
MeshAttributeData positions2{MeshAttribute::Position, vertexFormatWrap(0x3a), vertexData2};
std::ostringstream out;
Error redirectError{&out};
MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}};
CORRADE_COMPARE(out.str(),
/* Assumes size of the type is 0, so the diagnostic is different from
constructAttributeNotContained() */
"Trade::MeshData: attribute 1 [0xdead:0xdeaf] is not contained in passed vertexData array [0xbadda9:0xbaddac]\n");
}
void MeshDataTest::mutableAccessNotAllowed() {
const UnsignedShort indexData[]{0, 1, 0};
const Vector2 vertexData[]{{0.1f, 0.2f}, {0.4f, 0.5f}};

Loading…
Cancel
Save