Browse Source

Trade: allow specifying explicit vertex count on MeshData construction.

Until now, except for an attribute-less index-less mesh, the vertex
count was only implicitly taken from passed attributes, but it was
severely limiting:

 - There was no way to set vertex count for an attribute-less
   indexed mesh, which didn't make sense
 - All code that made non-owning MeshData instances referencing another
   MeshData had to explicitly handle the attribute-less corner case to
   avoid vertex count getting lost
 - Offset-only attributes couldn't be used to specify static layout of
   meshes with dynamic vertex count, causing unnecessary extra
   allocations especially in the Primitives library.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
27f6cc309d
  1. 4
      src/Magnum/MeshTools/Combine.cpp
  2. 18
      src/Magnum/MeshTools/Interleave.cpp
  3. 22
      src/Magnum/MeshTools/Test/CombineTest.cpp
  4. 4
      src/Magnum/MeshTools/Test/DuplicateTest.cpp
  5. 65
      src/Magnum/Trade/MeshData.cpp
  6. 91
      src/Magnum/Trade/MeshData.h
  7. 6
      src/Magnum/Trade/Test/AbstractImporterTest.cpp
  8. 4
      src/Magnum/Trade/Test/MeshData2DTest.cpp
  9. 4
      src/Magnum/Trade/Test/MeshData3DTest.cpp
  10. 244
      src/Magnum/Trade/Test/MeshDataTest.cpp

4
src/Magnum/MeshTools/Combine.cpp

@ -91,7 +91,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::ArrayView<const Conta
/* Make the combined index array unique */
Containers::Array<char> indexData{indexCount*sizeof(UnsignedInt)};
const auto indexDataI = Containers::arrayCast<UnsignedInt>(indexData);
const std::size_t vertexCount = removeDuplicatesInPlaceInto(
const UnsignedInt vertexCount = removeDuplicatesInPlaceInto(
Containers::StridedArrayView2D<char>{combinedIndices, {indexCount, indexStride}},
indexDataI);
@ -133,7 +133,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::ArrayView<const Conta
return Trade::MeshData{primitive,
std::move(indexData), Trade::MeshIndexData{indexDataI},
std::move(vertexData), std::move(attributeData)};
std::move(vertexData), std::move(attributeData), vertexCount};
}
Trade::MeshData combineIndexedAttributes(std::initializer_list<Containers::Reference<const Trade::MeshData>> data) {

18
src/Magnum/MeshTools/Interleave.cpp

@ -154,14 +154,10 @@ Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vert
}
Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {
/* If there's no attributes in the original mesh, we need to pass vertex
count explicitly (MeshData asserts on that to avoid it getting lost.) */
if(!data.attributeCount())
return interleavedLayout(Trade::MeshData{data.primitive(), data.vertexCount()}, vertexCount, extra);
return interleavedLayout(
Trade::MeshData{data.primitive(), {}, data.vertexData(),
Trade::meshAttributeDataNonOwningArray(data.attributeData())},
Trade::meshAttributeDataNonOwningArray(data.attributeData()),
data.vertexCount()},
vertexCount, extra);
}
@ -257,19 +253,13 @@ Trade::MeshData interleave(const Trade::MeshData& data, const Containers::ArrayV
if(data.isIndexed()) {
indexData = data.indexData();
indices = Trade::MeshIndexData{data.indices()};
/* If there's neither an index array nor any attributes in the original
mesh, we need to pass vertex count explicitly (MeshData asserts on that
to avoid it getting lost.) */
} else if(!data.attributeCount()) {
return interleave(Trade::MeshData{data.primitive(), data.vertexCount()}, extra);
}
return interleave(Trade::MeshData{data.primitive(),
{}, indexData, indices,
{}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData())
{}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()),
data.vertexCount()
}, extra);
}
Trade::MeshData interleave(const Trade::MeshData& data, const std::initializer_list<Trade::MeshAttributeData> extra) {

22
src/Magnum/MeshTools/Test/CombineTest.cpp

@ -107,11 +107,11 @@ void CombineTest::combineIndexedAttributesIndicesOnly() {
const UnsignedShort indicesB[]{3, 4, 3};
const UnsignedByte indicesC[]{7, 6, 7};
Trade::MeshData a{MeshPrimitive::LineLoop, {}, indicesA,
Trade::MeshIndexData{indicesA}};
Trade::MeshIndexData{indicesA}, 3};
Trade::MeshData b{MeshPrimitive::LineLoop, {}, indicesB,
Trade::MeshIndexData{indicesB}};
Trade::MeshIndexData{indicesB}, 5};
Trade::MeshData c{MeshPrimitive::LineLoop, {}, indicesC,
Trade::MeshIndexData{indicesC}};
Trade::MeshIndexData{indicesC}, 8};
Trade::MeshData result = MeshTools::combineIndexedAttributes({a, b, c});
CORRADE_COMPARE(result.primitive(), MeshPrimitive::LineLoop);
@ -121,7 +121,7 @@ void CombineTest::combineIndexedAttributesIndicesOnly() {
Containers::arrayView<UnsignedInt>({0, 1, 0}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeCount(), 0);
CORRADE_COMPARE(result.vertexCount(), 0);
CORRADE_COMPARE(result.vertexCount(), 2);
}
void CombineTest::combineIndexedAttributesNoMeshes() {
@ -134,9 +134,9 @@ void CombineTest::combineIndexedAttributesNoMeshes() {
void CombineTest::combineIndexedAttributesNotIndexed() {
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData c{MeshPrimitive::Lines, 5};
std::ostringstream out;
@ -148,9 +148,9 @@ void CombineTest::combineIndexedAttributesNotIndexed() {
void CombineTest::combineIndexedAttributesDifferentPrimitive() {
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Points,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
std::ostringstream out;
Error redirectError{&out};
@ -161,12 +161,12 @@ void CombineTest::combineIndexedAttributesDifferentPrimitive() {
void CombineTest::combineIndexedAttributesDifferentIndexCount() {
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData c{MeshPrimitive::Lines,
{}, indices,
Trade::MeshIndexData{Containers::arrayView(indices).prefix(4)}};
Trade::MeshIndexData{Containers::arrayView(indices).prefix(4)}, 1};
std::ostringstream out;
Error redirectError{&out};

4
src/Magnum/MeshTools/Test/DuplicateTest.cpp

@ -372,7 +372,7 @@ void DuplicateTest::duplicateMeshDataExtraWrongCount() {
void DuplicateTest::duplicateMeshDataExtraOffsetOnly() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Trade::MeshData data{MeshPrimitive::TriangleFan,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 3};
std::ostringstream out;
Error redirectError{&out};
@ -386,7 +386,7 @@ void DuplicateTest::duplicateMeshDataExtraOffsetOnly() {
void DuplicateTest::duplicateMeshDataNoAttributes() {
UnsignedByte indices[]{0, 1, 2, 2, 1, 0};
Trade::MeshData data{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}};
{}, indices, Trade::MeshIndexData{indices}, 3};
Trade::MeshData duplicated = MeshTools::duplicate(data, {});
CORRADE_COMPARE(duplicated.primitive(), MeshPrimitive::Lines);

65
src/Magnum/Trade/MeshData.cpp

@ -79,15 +79,29 @@ Containers::Array<MeshAttributeData> meshAttributeDataNonOwningArray(const Conta
return Containers::Array<Trade::MeshAttributeData>{const_cast<Trade::MeshAttributeData*>(view.data()), view.size(), reinterpret_cast<void(*)(Trade::MeshAttributeData*, std::size_t)>(Trade::Implementation::nonOwnedArrayDeleter)};
}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: _indexType{indices._type}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState}, _indexData{std::move(indexData)}, _vertexData{std::move(vertexData)}, _attributes{std::move(attributes)}, _indices{Containers::arrayCast<const char>(indices._data)} {
/* Save vertex count. It's a strided array view, so the size is not
depending on type. */
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: _indexType{indices._type}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState}, _indexData{std::move(indexData)}, _vertexData{std::move(vertexData)}, _attributes{std::move(attributes)}, _indices{Containers::arrayCast<const char>(indices._data)} {
/* Save vertex count. If it's passed explicitly, use that (but still check
that all attributes have the same vertex count for safety), otherwise
expect at least one attribute */
#ifndef CORRADE_NO_ASSERT
UnsignedInt expectedAttributeVertexCount;
#endif
if(_attributes.empty()) {
CORRADE_ASSERT(indices._type != MeshIndexType{},
"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]._vertexCount;
CORRADE_ASSERT(vertexCount != ImplicitVertexCount,
"Trade::MeshData: vertex count can't be implicit if there are no attributes", );
_vertexCount = vertexCount;
/* No attributes, so we won't be checking anything */
} else if(vertexCount != ImplicitVertexCount) {
_vertexCount = vertexCount;
#ifndef CORRADE_NO_ASSERT
expectedAttributeVertexCount = _attributes[0]._vertexCount;
#endif
} else {
_vertexCount = _attributes[0]._vertexCount;
#ifndef CORRADE_NO_ASSERT
expectedAttributeVertexCount = _vertexCount;
#endif
}
CORRADE_ASSERT(!_indices.empty() || _indexData.empty(),
"Trade::MeshData: indexData passed for a non-indexed mesh", );
@ -101,8 +115,8 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
const MeshAttributeData& attribute = _attributes[i];
CORRADE_ASSERT(attribute._format != VertexFormat{},
"Trade::MeshData: attribute" << i << "doesn't specify anything", );
CORRADE_ASSERT(attribute._vertexCount == _vertexCount,
"Trade::MeshData: attribute" << i << "has" << attribute._vertexCount << "vertices but" << _vertexCount << "expected", );
CORRADE_ASSERT(attribute._vertexCount == expectedAttributeVertexCount,
"Trade::MeshData: attribute" << i << "has" << attribute._vertexCount << "vertices but" << expectedAttributeVertexCount << "expected", );
/* 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. */
@ -123,9 +137,9 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
#endif
}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, std::move(indexData), indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(indexData), indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} {
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} {
CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned),
"Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, );
CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned),
@ -134,45 +148,45 @@ MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags
_vertexDataFlags = vertexDataFlags;
}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, const std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, const std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, std::move(vertexData), std::move(attributes), importerState} {
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, std::move(vertexData), std::move(attributes), vertexCount, importerState} {
CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned),
"Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, );
_indexDataFlags = indexDataFlags;
}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, const std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, const std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, indexDataFlags, indexData, indices, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} {
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} {
CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned),
"Trade::MeshData: can't construct with non-owned vertex data but" << vertexDataFlags, );
_vertexDataFlags = vertexDataFlags;
}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, const std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, std::move(indexData), indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const DataFlags vertexDataFlags, const Containers::ArrayView<const void> vertexData, const std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(indexData), indices, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, std::move(vertexData), std::move(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, std::move(vertexData), std::move(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& vertexData, const std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& vertexData, const std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, std::move(vertexData), Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), importerState} {
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(vertexData.data())), vertexData.size(), Implementation::nonOwnedArrayDeleter}, std::move(attributes), vertexCount, importerState} {
CORRADE_ASSERT(!(vertexDataFlags & DataFlag::Owned),
"Trade::MeshData: can't construct with non-owned vertex data but" << vertexDataFlags, );
_vertexDataFlags = vertexDataFlags;
}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, const void* const importerState): MeshData{primitive, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, const UnsignedInt vertexCount, const void* const importerState): MeshData{primitive, vertexDataFlags, vertexData, Implementation::initializerListToArrayWithDefaultDeleter(attributes), vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, {}, {}, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, std::move(indexData), indices, {}, {}, vertexCount, importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, importerState} {
MeshData::MeshData(const MeshPrimitive primitive, const DataFlags indexDataFlags, const Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, Containers::Array<char>{const_cast<char*>(static_cast<const char*>(indexData.data())), indexData.size(), Implementation::nonOwnedArrayDeleter}, indices, vertexCount, importerState} {
CORRADE_ASSERT(!(indexDataFlags & DataFlag::Owned),
"Trade::MeshData: can't construct with non-owned index data but" << indexDataFlags, );
_indexDataFlags = indexDataFlags;
}
MeshData::MeshData(const MeshPrimitive primitive, const UnsignedInt vertexCount, const void* const importerState) noexcept: _vertexCount{vertexCount}, _indexType{}, _primitive{primitive}, _indexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _vertexDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState} {}
MeshData::MeshData(const MeshPrimitive primitive, const UnsignedInt vertexCount, const void* const importerState) noexcept: MeshData{primitive, {}, MeshIndexData{}, {}, {}, vertexCount, importerState} {}
MeshData::~MeshData() = default;
@ -238,8 +252,7 @@ MeshAttributeData MeshData::attributeData(UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(),
"Trade::MeshData::attributeData(): index" << id << "out of range for" << _attributes.size() << "attributes", MeshAttributeData{});
const MeshAttributeData& attribute = _attributes[id];
return attribute._isOffsetOnly ? MeshAttributeData{attribute._name,
attribute._format, attributeDataViewInternal(attribute)} : attribute;
return MeshAttributeData{attribute._name, attribute._format, attributeDataViewInternal(attribute)};
}
MeshAttribute MeshData::attributeName(UnsignedInt id) const {

91
src/Magnum/Trade/MeshData.h

@ -418,6 +418,10 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
* attribute construction time. Expects that @p arraySize is zero for
* builtin attributes. Note that instances created this way can't be
* used in most @ref MeshTools algorithms.
*
* Additionally, for even more flexibility, the @p vertexCount can be
* overriden at @ref MeshData construction time, however all attributes
* are still required to have the same vertex count to catch accidents.
* @see @ref isOffsetOnly(), @ref arraySize(),
* @ref data(Containers::ArrayView<const void>) const
*/
@ -654,6 +658,14 @@ implementation-specific @ref VertexFormat values.
*/
class MAGNUM_TRADE_EXPORT MeshData {
public:
enum: UnsignedInt {
/**
* Implicit vertex count. When passed to a constructor, indicates
* that vertex count should be taken from attribute data views.
*/
ImplicitVertexCount = ~UnsignedInt{}
};
/**
* @brief Construct an indexed mesh data
* @param primitive Primitive
@ -661,6 +673,10 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param indices Index data description
* @param vertexData Vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* The @p indices are expected to point to a sub-range of @p indexData.
@ -674,14 +690,14 @@ class MAGNUM_TRADE_EXPORT MeshData {
* The @ref indexDataFlags() / @ref vertexDataFlags() are implicitly
* set to a combination of @ref DataFlag::Owned and
* @ref DataFlag::Mutable. For non-owned data use the
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, const MeshIndexData&, DataFlags, Containers::ArrayView<const void>, Containers::Array<MeshAttributeData>&&, const void*)
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, const MeshIndexData&, DataFlags, Containers::ArrayView<const void>, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* constructor or its variants instead.
*/
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct indexed mesh data with non-owned index and vertex data
@ -692,19 +708,23 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param vertexDataFlags Vertex data flags
* @param vertexData View on vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* creates an instance that doesn't own the passed vertex and index
* data. The @p indexDataFlags / @p vertexDataFlags parameters can
* contain @ref DataFlag::Mutable to indicate the external data can be
* modified, and is expected to *not* have @ref DataFlag::Owned set.
*/
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct indexed mesh data with non-owned index data
@ -714,9 +734,13 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param indices Index data description
* @param vertexData Vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* creates an instance that doesn't own the passed index data. The
* @p indexDataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
@ -724,11 +748,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* implicitly set to a combination of @ref DataFlag::Owned and
* @ref DataFlag::Mutable.
*/
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct indexed mesh data with non-owned vertex data
@ -738,9 +762,13 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param vertexDataFlags Vertex data flags
* @param vertexData View on vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* creates an instance that doesn't own the passed vertex data. The
* @p vertexDataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
@ -748,20 +776,24 @@ class MAGNUM_TRADE_EXPORT MeshData {
* implicitly set to a combination of @ref DataFlag::Owned and
* @ref DataFlag::Mutable.
*/
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct a non-indexed mesh data
* @param primitive Primitive
* @param vertexData Vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* Same as calling @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Same as calling @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* with default-constructed @p indexData and @p indices arguments.
*
* The @ref vertexDataFlags() are implicitly set to a combination of
@ -769,14 +801,14 @@ class MAGNUM_TRADE_EXPORT MeshData {
* the @ref indexDataFlags() are implicitly set to a combination of
* @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there
* isn't any data to own or to mutate. For non-owned data use the
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, Containers::Array<MeshAttributeData>&&, const void*)
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* constructor instead.
*/
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct a non-owned non-indexed mesh data
@ -784,9 +816,13 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param vertexDataFlags Vertex data flags
* @param vertexData View on vertex data
* @param attributes Description of all vertex attribute data
* @param vertexCount Vertex count. If set to
* @ref ImplicitVertexCount, vertex count is taken from data views
* passed to @p attributes (in which case there has to be at least
* one).
* @param importerState Importer-specific state
*
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* creates an instance that doesn't own the passed data. The
* @p vertexDataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
@ -795,20 +831,22 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there
* isn't any data to own or to mutate.
*/
explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, Containers::Array<MeshAttributeData>&& attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr) noexcept;
/** @overload */
/* Not noexcept because allocation happens inside */
explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, const void* importerState = nullptr);
explicit MeshData(MeshPrimitive primitive, DataFlags vertexDataFlags, Containers::ArrayView<const void> vertexData, std::initializer_list<MeshAttributeData> attributes, UnsignedInt vertexCount = ImplicitVertexCount, const void* importerState = nullptr);
/**
* @brief Construct an attribute-less indexed mesh data
* @param primitive Primitive
* @param indexData Index data
* @param indices Index data description
* @param vertexCount Vertex count. Passing @ref ImplicitVertexCount
* is not allowed in this overload.
* @param importerState Importer-specific state
*
* Same as calling @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, const void*)
* Same as calling @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, Containers::Array<char>&&, Containers::Array<MeshAttributeData>&&, UnsignedInt, const void*)
* with default-constructed @p vertexData and @p attributes arguments.
* The @p indices are expected to be valid (but can be empty). If you
* want to create an attribute-less non-indexed mesh, use
@ -820,10 +858,10 @@ class MAGNUM_TRADE_EXPORT MeshData {
* the @ref vertexDataFlags() are implicitly set to a combination of
* @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there
* isn't any data to own or to mutate. For non-owned data use the
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, const MeshIndexData&, const void*)
* @ref MeshData(MeshPrimitive, DataFlags, Containers::ArrayView<const void>, const MeshIndexData&, UnsignedInt, const void*)
* constructor instead.
*/
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, Containers::Array<char>&& indexData, const MeshIndexData& indices, UnsignedInt vertexCount, const void* importerState = nullptr) noexcept;
/**
* @brief Construct a non-owned attribute-less indexed mesh data
@ -831,9 +869,11 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @param indexDataFlags Index data flags
* @param indexData View on index data
* @param indices Index data description
* @param vertexCount Vertex count. Passing
* @ref ImplicitVertexCount is not allowed in this overload.
* @param importerState Importer-specific state
*
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, const void*)
* Compared to @ref MeshData(MeshPrimitive, Containers::Array<char>&&, const MeshIndexData&, UnsignedInt, const void*)
* creates an instance that doesn't own the passed data. The
* @p indexDataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
@ -842,12 +882,13 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @ref DataFlag::Owned and @ref DataFlag::Mutable, even though there
* isn't any data to own or to mutate.
*/
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, const void* importerState = nullptr) noexcept;
explicit MeshData(MeshPrimitive primitive, DataFlags indexDataFlags, Containers::ArrayView<const void> indexData, const MeshIndexData& indices, UnsignedInt vertexCount, const void* importerState = nullptr) noexcept;
/**
* @brief Construct an index-less attribute-less mesh data
* @param primitive Primitive
* @param vertexCount Desired count of vertices to draw
* @param vertexCount Vertex count. Passing @ref ImplicitVertexCount
* is not allowed in this overload.
* @param importerState Importer-specific state
*
* Useful in case the drawing is fully driven by a shader. For

6
src/Magnum/Trade/Test/AbstractImporterTest.cpp

@ -2264,7 +2264,7 @@ void AbstractImporterTest::mesh() {
Containers::Optional<MeshData> doMesh(UnsignedInt id, UnsignedInt level) override {
/* Verify that initializer list is converted to an array with
the default deleter and not something disallowed */
if(id == 7 && level == 2) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state};
if(id == 7 && level == 2) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, MeshData::ImplicitVertexCount, &state};
else return {};
}
} importer;
@ -2304,7 +2304,7 @@ void AbstractImporterTest::meshDeprecatedFallback() {
else return {};
}
Containers::Optional<MeshData> doMesh(UnsignedInt id, UnsignedInt level) override {
if(id == 7 && level == 0) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state};
if(id == 7 && level == 0) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, MeshData::ImplicitVertexCount, &state};
else return {};
}
} importer;
@ -2610,7 +2610,7 @@ void AbstractImporterTest::meshCustomIndexDataDeleter() {
UnsignedInt doMeshCount() const override { return 1; }
Int doMeshForName(const std::string&) override { return 0; }
Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}};
return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}, 1};
}
char data[1];

4
src/Magnum/Trade/Test/MeshData2DTest.cpp

@ -98,7 +98,7 @@ struct {
Containers::StridedArrayView1D<const Vector2>{Vertices, &Vertices[0].textureCoords3, 2, sizeof(Vertex)}},
MeshAttributeData{MeshAttribute::Color,
Containers::StridedArrayView1D<const Color4>{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}},
}, &State}},
}, MeshData::ImplicitVertexCount, &State}},
/* GCC 4.8 needs the explicit MeshData3D conversion otherwise it tries
to use a deleted copy constructor */
MeshData2D{MeshData{MeshPrimitive::Lines, {}, Vertices, {
@ -108,7 +108,7 @@ struct {
Containers::StridedArrayView1D<const Vector2>{Vertices, &Vertices[0].textureCoords1, 2, sizeof(Vertex)}},
MeshAttributeData{MeshAttribute::Color,
Containers::StridedArrayView1D<const Color4>{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}},
}, &State}}
}, MeshData::ImplicitVertexCount, &State}}
}
};

4
src/Magnum/Trade/Test/MeshData3DTest.cpp

@ -106,7 +106,7 @@ struct {
Containers::StridedArrayView1D<const Vector2>{Vertices, &Vertices[0].textureCoords3, 2, sizeof(Vertex)}},
MeshAttributeData{MeshAttribute::Color,
Containers::StridedArrayView1D<const Color4>{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}},
}, &State}},
}, MeshData::ImplicitVertexCount, &State}},
/* GCC 4.8 needs the explicit MeshData3D conversion otherwise it tries
to use a deleted copy constructor */
MeshData3D{MeshData{MeshPrimitive::Lines, {}, Vertices, {
@ -118,7 +118,7 @@ struct {
Containers::StridedArrayView1D<const Vector2>{Vertices, &Vertices[0].textureCoords1, 2, sizeof(Vertex)}},
MeshAttributeData{MeshAttribute::Color,
Containers::StridedArrayView1D<const Color4>{Vertices, &Vertices[0].color, 2, sizeof(Vertex)}},
}, &State}}
}, MeshData::ImplicitVertexCount, &State}}
}
};

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

@ -75,6 +75,7 @@ struct MeshDataTest: TestSuite::Tester {
void constructArrayAttributeNotAllowed();
void construct();
void constructZeroIndices();
void constructZeroAttributes();
void constructZeroVertices();
@ -91,7 +92,7 @@ struct MeshDataTest: TestSuite::Tester {
void constructAttributelessNotOwned();
void constructIndexDataButNotIndexed();
void constructAttributelessInvalidIndices();
void constructAttributelessImplicitVertexCount();
void constructIndicesNotContained();
void constructAttributeNotContained();
void constructInconsitentVertexCount();
@ -153,6 +154,16 @@ struct MeshDataTest: TestSuite::Tester {
void releaseVertexData();
};
struct {
const char* name;
UnsignedInt vertexCount, expectedVertexCount;
} ConstructData[] {
{"implicit vertex count", MeshData::ImplicitVertexCount, 3},
{"explicit vertex count", 3, 3},
{"explicit large vertex count", 17, 17},
{"explicit zero vertex count", 0, 0}
};
struct {
const char* name;
DataFlags indexDataFlags, vertexDataFlags;
@ -207,10 +218,12 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::constructArrayAttribute2DNonContiguous,
&MeshDataTest::constructArrayAttributeTypeErased,
&MeshDataTest::constructArrayAttributeOffsetOnly,
&MeshDataTest::constructArrayAttributeNotAllowed,
&MeshDataTest::constructArrayAttributeNotAllowed});
&MeshDataTest::construct,
&MeshDataTest::constructZeroIndices,
addInstancedTests({&MeshDataTest::construct},
Containers::arraySize(ConstructData));
addTests({&MeshDataTest::constructZeroIndices,
&MeshDataTest::constructZeroAttributes,
&MeshDataTest::constructZeroVertices,
&MeshDataTest::constructIndexless,
@ -228,7 +241,7 @@ MeshDataTest::MeshDataTest() {
Containers::arraySize(SingleNotOwnedData));
addTests({&MeshDataTest::constructIndexDataButNotIndexed,
&MeshDataTest::constructAttributelessInvalidIndices,
&MeshDataTest::constructAttributelessImplicitVertexCount,
&MeshDataTest::constructIndicesNotContained,
&MeshDataTest::constructAttributeNotContained,
&MeshDataTest::constructInconsitentVertexCount,
@ -823,6 +836,9 @@ void MeshDataTest::constructArrayAttributeNotAllowed() {
}
void MeshDataTest::construct() {
auto&& instanceData = ConstructData[testCaseInstanceId()];
setTestCaseDescription(instanceData.name);
struct Vertex {
Vector3 position;
Vector3 normal;
@ -839,8 +855,10 @@ void MeshDataTest::construct() {
indexView[4] = 2;
indexView[5] = 1;
Containers::Array<char> vertexData{3*sizeof(Vertex)};
auto vertexView = Containers::arrayCast<Vertex>(vertexData);
/* Enough vertex data to fit also the case with large explicit vertex count
(but fill just the first 3, as those are only tested) */
Containers::Array<char> vertexData{17*sizeof(Vertex)};
auto vertexView = Containers::arrayCast<Vertex>(vertexData).prefix(3);
vertexView[0].position = {0.1f, 0.2f, 0.3f};
vertexView[1].position = {0.4f, 0.5f, 0.6f};
vertexView[2].position = {0.7f, 0.8f, 0.9f};
@ -854,6 +872,9 @@ void MeshDataTest::construct() {
vertexView[1].id = -374;
vertexView[2].id = 22;
if(instanceData.vertexCount < 3)
vertexView = vertexView.prefix(instanceData.vertexCount);
int importerState;
MeshIndexData indices{indexView};
MeshAttributeData positions{MeshAttribute::Position,
@ -869,7 +890,7 @@ void MeshDataTest::construct() {
MeshData data{MeshPrimitive::Triangles,
std::move(indexData), indices,
/* Texture coordinates deliberately twice (though aliased) */
std::move(vertexData), {positions, textureCoordinates, normals, textureCoordinates, ids}, &importerState};
std::move(vertexData), {positions, textureCoordinates, normals, textureCoordinates, ids}, instanceData.vertexCount, &importerState};
/* Basics */
CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
@ -899,7 +920,7 @@ void MeshDataTest::construct() {
CORRADE_COMPARE(data.indices<UnsignedShort>()[5], 1);
/* Attribute access by ID */
CORRADE_COMPARE(data.vertexCount(), 3);
CORRADE_COMPARE(data.vertexCount(), instanceData.expectedVertexCount);
CORRADE_COMPARE(data.attributeCount(), 5);
CORRADE_COMPARE(data.attributeName(0), MeshAttribute::Position);
CORRADE_COMPARE(data.attributeName(1), MeshAttribute::TextureCoordinates);
@ -927,43 +948,53 @@ void MeshDataTest::construct() {
CORRADE_COMPARE(data.attributeArraySize(4), 0);
/* 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);
CORRADE_COMPARE(data.attribute(0).size()[0], instanceData.expectedVertexCount);
CORRADE_COMPARE(data.mutableAttribute(0).size()[0], instanceData.expectedVertexCount);
if(instanceData.vertexCount) {
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<Vector2>(1)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.attribute<Vector3>(2)[2], Vector3::zAxis());
CORRADE_COMPARE(data.attribute<Vector2>(3)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(4)[1], -374);
CORRADE_COMPARE(data.mutableAttribute<Vector3>(0)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.mutableAttribute<Vector2>(1)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.mutableAttribute<Vector3>(2)[2], Vector3::zAxis());
CORRADE_COMPARE(data.mutableAttribute<Vector2>(3)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.mutableAttribute<Short>(4)[1], -374);
CORRADE_COMPARE(data.attribute<Vector3>(0).size(), instanceData.expectedVertexCount);
CORRADE_COMPARE(data.mutableAttribute<Vector3>(0).size(), instanceData.expectedVertexCount);
if(instanceData.vertexCount) {
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<Vector3>(2)[2], Vector3::zAxis());
CORRADE_COMPARE(data.attribute<Vector2>(3)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(4)[1], -374);
CORRADE_COMPARE(data.mutableAttribute<Vector3>(0)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.mutableAttribute<Vector2>(1)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.mutableAttribute<Vector3>(2)[2], Vector3::zAxis());
CORRADE_COMPARE(data.mutableAttribute<Vector2>(3)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.mutableAttribute<Short>(4)[1], -374);
}
/* Raw attribute data access by ID */
CORRADE_COMPARE(data.attributeData(3).name(), MeshAttribute::TextureCoordinates);
CORRADE_COMPARE(data.attributeData(3).format(), VertexFormat::Vector2);
CORRADE_COMPARE(Containers::arrayCast<const Vector2>(data.attributeData(3).data())[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attributeData(3).data().size(), instanceData.expectedVertexCount);
if(instanceData.vertexCount)
CORRADE_COMPARE(Containers::arrayCast<const Vector2>(data.attributeData(3).data())[1], (Vector2{0.250f, 0.375f}));
/* Attribute access by name */
CORRADE_VERIFY(data.hasAttribute(MeshAttribute::Position));
@ -1009,38 +1040,46 @@ void MeshDataTest::construct() {
CORRADE_COMPARE(data.attributeArraySize(meshAttributeCustom(13)), 0);
/* 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);
CORRADE_COMPARE(data.attribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount);
CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount);
if(instanceData.vertexCount) {
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::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, 1)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(meshAttributeCustom(13))[2], 22);
CORRADE_COMPARE(data.mutableAttribute<Vector3>(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.mutableAttribute<Vector3>(MeshAttribute::Normal)[2], Vector3::zAxis());
CORRADE_COMPARE(data.mutableAttribute<Vector2>(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.mutableAttribute<Vector2>(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(meshAttributeCustom(13))[2], 22);
CORRADE_COMPARE(data.attribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount);
CORRADE_COMPARE(data.mutableAttribute(MeshAttribute::Position).size()[0], instanceData.expectedVertexCount);
if(instanceData.vertexCount) {
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<Vector2>(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.attribute<Vector2>(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(meshAttributeCustom(13))[2], 22);
CORRADE_COMPARE(data.mutableAttribute<Vector3>(MeshAttribute::Position)[1], (Vector3{0.4f, 0.5f, 0.6f}));
CORRADE_COMPARE(data.mutableAttribute<Vector3>(MeshAttribute::Normal)[2], Vector3::zAxis());
CORRADE_COMPARE(data.mutableAttribute<Vector2>(MeshAttribute::TextureCoordinates, 0)[0], (Vector2{0.000f, 0.125f}));
CORRADE_COMPARE(data.mutableAttribute<Vector2>(MeshAttribute::TextureCoordinates, 1)[1], (Vector2{0.250f, 0.375f}));
CORRADE_COMPARE(data.attribute<Short>(meshAttributeCustom(13))[2], 22);
}
}
void MeshDataTest::constructZeroIndices() {
@ -1073,14 +1112,14 @@ void MeshDataTest::constructZeroAttributes() {
auto indexView = Containers::arrayCast<UnsignedInt>(indexData);
MeshData data{MeshPrimitive::Triangles,
std::move(indexData), MeshIndexData{indexView},
std::move(vertexData), {}};
std::move(vertexData), {}, 15};
CORRADE_COMPARE(data.indexCount(), 3);
CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.attributeCount(), 0);
CORRADE_VERIFY(!data.attributeData());
CORRADE_COMPARE(data.vertexData().size(), 3);
CORRADE_COMPARE(data.vertexCount(), 0);
CORRADE_COMPARE(data.vertexCount(), 15);
}
void MeshDataTest::constructZeroVertices() {
@ -1112,7 +1151,7 @@ void MeshDataTest::constructIndexless() {
int importerState;
MeshAttributeData positions{MeshAttribute::Position, vertexView};
MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions}, &importerState};
MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
/* These are empty so it doesn't matter, but this is a nice non-restrictive
default */
@ -1153,7 +1192,7 @@ void MeshDataTest::constructAttributeless() {
int importerState;
MeshIndexData indices{indexView};
MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), indices, &importerState};
MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), indices, 3, &importerState};
/* These are empty so it doesn't matter, but this is a nice non-restrictive
default */
CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
@ -1170,7 +1209,7 @@ void MeshDataTest::constructAttributeless() {
CORRADE_COMPARE(data.indices<UnsignedInt>()[2], 2);
CORRADE_COMPARE(data.indices<UnsignedInt>()[5], 1);
CORRADE_COMPARE(data.vertexCount(), 0); /** @todo what to return here? */
CORRADE_COMPARE(data.vertexCount(), 3);
CORRADE_COMPARE(data.attributeCount(), 0);
}
@ -1184,7 +1223,7 @@ void MeshDataTest::constructNotOwned() {
int importerState;
MeshIndexData indices{indexData};
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)};
MeshData data{MeshPrimitive::Triangles, instanceData.indexDataFlags, Containers::arrayView(indexData), indices, instanceData.vertexDataFlags, Containers::arrayView(vertexData), {positions}, &importerState};
MeshData data{MeshPrimitive::Triangles, instanceData.indexDataFlags, Containers::arrayView(indexData), indices, instanceData.vertexDataFlags, Containers::arrayView(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), instanceData.indexDataFlags);
CORRADE_COMPARE(data.vertexDataFlags(), instanceData.vertexDataFlags);
@ -1234,7 +1273,7 @@ void MeshDataTest::constructIndicesNotOwned() {
int importerState;
MeshIndexData indices{indexData};
MeshAttributeData positions{MeshAttribute::Position, vertexView};
MeshData data{MeshPrimitive::Triangles, instanceData.dataFlags, Containers::arrayView(indexData), indices, std::move(vertexData), {positions}, &importerState};
MeshData data{MeshPrimitive::Triangles, instanceData.dataFlags, Containers::arrayView(indexData), indices, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), instanceData.dataFlags);
CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
@ -1282,7 +1321,7 @@ void MeshDataTest::constructVerticesNotOwned() {
int importerState;
MeshIndexData indices{indexView};
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)};
MeshData data{MeshPrimitive::Triangles, std::move(indexData), indices, instanceData.dataFlags, Containers::arrayView(vertexData), {positions}, &importerState};
MeshData data{MeshPrimitive::Triangles, std::move(indexData), indices, instanceData.dataFlags, Containers::arrayView(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.vertexDataFlags(), instanceData.dataFlags);
@ -1324,7 +1363,7 @@ void MeshDataTest::constructIndexlessNotOwned() {
int importerState;
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayView(vertexData)};
MeshData data{MeshPrimitive::LineLoop, instanceData.dataFlags, vertexData, {positions}, &importerState};
MeshData data{MeshPrimitive::LineLoop, instanceData.dataFlags, vertexData, {positions}, MeshData::ImplicitVertexCount, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.vertexDataFlags(), instanceData.dataFlags);
@ -1351,7 +1390,7 @@ void MeshDataTest::constructAttributelessNotOwned() {
int importerState;
MeshIndexData indices{indexData};
MeshData data{MeshPrimitive::TriangleStrip, instanceData.dataFlags, indexData, indices, &importerState};
MeshData data{MeshPrimitive::TriangleStrip, instanceData.dataFlags, indexData, indices, 5, &importerState};
CORRADE_COMPARE(data.indexDataFlags(), instanceData.dataFlags);
CORRADE_COMPARE(data.vertexDataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.primitive(), MeshPrimitive::TriangleStrip);
@ -1373,7 +1412,7 @@ void MeshDataTest::constructAttributelessNotOwned() {
CORRADE_COMPARE(data.mutableIndices<UnsignedShort>()[2], 0);
}
CORRADE_COMPARE(data.vertexCount(), 0); /** @todo what to return here? */
CORRADE_COMPARE(data.vertexCount(), 5);
CORRADE_COMPARE(data.attributeCount(), 0);
}
@ -1419,11 +1458,11 @@ void MeshDataTest::constructIndexDataButNotIndexed() {
CORRADE_COMPARE(out.str(), "Trade::MeshData: indexData passed for a non-indexed mesh\n");
}
void MeshDataTest::constructAttributelessInvalidIndices() {
void MeshDataTest::constructAttributelessImplicitVertexCount() {
std::ostringstream out;
Error redirectError{&out};
MeshData{MeshPrimitive::Points, nullptr, MeshIndexData{}};
CORRADE_COMPARE(out.str(), "Trade::MeshData: indices are expected to be valid if there are no attributes and vertex count isn't passed explicitly\n");
MeshData{MeshPrimitive::Points, nullptr, {}};
CORRADE_COMPARE(out.str(), "Trade::MeshData: vertex count can't be implicit if there are no attributes\n");
}
void MeshDataTest::constructIndicesNotContained() {
@ -1433,8 +1472,8 @@ void MeshDataTest::constructIndicesNotContained() {
std::ostringstream out;
Error redirectError{&out};
MeshData{MeshPrimitive::Triangles, std::move(indexData), indices};
MeshData{MeshPrimitive::Triangles, nullptr, indices};
MeshData{MeshPrimitive::Triangles, std::move(indexData), indices, 1};
MeshData{MeshPrimitive::Triangles, nullptr, indices, 1};
CORRADE_COMPARE(out.str(),
"Trade::MeshData: indices [0xdead:0xdeb3] are not contained in passed indexData array [0xbadda9:0xbaddaf]\n"
"Trade::MeshData: indices [0xdead:0xdeb3] are not contained in passed indexData array [0x0:0x0]\n");
@ -1449,25 +1488,40 @@ void MeshDataTest::constructAttributeNotContained() {
/* See implementationSpecificVertexFormatNotContained() below for
implementation-specific formats */
/* Here the original positions array is shrunk from 3 items to 2 and the
vertex data too, which should work without asserting -- comparing just
the original view would not pass, which is wrong */
MeshData{MeshPrimitive::Triangles, {}, vertexData.prefix(16), {positions}, 2};
std::ostringstream out;
Error redirectError{&out};
/* Here the original positions array is extended from 3 items to 4, which
makes it not fit anymore, and thus an assert should hit -- comparing
just the original view would pass, which is wrong */
MeshData{MeshPrimitive::Triangles, {}, vertexData, {positions}, 4};
MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}};
MeshData{MeshPrimitive::Triangles, nullptr, {positions}};
MeshData{MeshPrimitive::Triangles, Containers::Array<char>{24}, {positions3}};
CORRADE_COMPARE(out.str(),
"Trade::MeshData: attribute 0 [0xbadda9:0xbaddc9] is not contained in passed vertexData array [0xbadda9:0xbaddc1]\n"
"Trade::MeshData: attribute 1 [0xdead:0xdec5] is not contained in passed vertexData array [0xbadda9:0xbaddc1]\n"
"Trade::MeshData: attribute 0 [0xbadda9:0xbaddc1] is not contained in passed vertexData array [0x0:0x0]\n"
"Trade::MeshData: offset attribute 0 spans 25 bytes but passed vertexData array has only 24\n");
}
void MeshDataTest::constructInconsitentVertexCount() {
Containers::Array<char> vertexData{24};
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData)};
Containers::Array<char> vertexData{136};
MeshAttributeData positions{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData).prefix(3)};
MeshAttributeData positions2{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData).prefix(2)};
std::ostringstream out;
Error redirectError{&out};
MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}};
/* The explicit vertex count should be ignored for the assertion message,
we only check that all passed attribute arrays have the same vertex
count. However, the actual "containment" of the attribute views is
checked with the explicit vertex count -- see the
constructAttributeNotContained() test above. */
MeshData{MeshPrimitive::Triangles, std::move(vertexData), {positions, positions2}, 17};
CORRADE_COMPARE(out.str(),
"Trade::MeshData: attribute 1 has 2 vertices but 3 expected\n");
}
@ -1552,7 +1606,7 @@ void MeshDataTest::constructAttributelessNotOwnedFlagOwned() {
std::ostringstream out;
Error redirectError{&out};
MeshData data{MeshPrimitive::Triangles, DataFlag::Owned, indexData, indices};
MeshData data{MeshPrimitive::Triangles, DataFlag::Owned, indexData, indices, 2};
CORRADE_COMPARE(out.str(),
"Trade::MeshData: can't construct with non-owned index data but Trade::DataFlag::Owned\n");
}
@ -1590,7 +1644,7 @@ void MeshDataTest::constructMove() {
int importerState;
MeshIndexData indices{indexView};
MeshAttributeData positions{MeshAttribute::Position, vertexView};
MeshData a{MeshPrimitive::Triangles, std::move(indexData), indices, std::move(vertexData), {positions}, &importerState};
MeshData a{MeshPrimitive::Triangles, std::move(indexData), indices, std::move(vertexData), {positions}, MeshData::ImplicitVertexCount, &importerState};
MeshData b{std::move(a)};
@ -1680,7 +1734,7 @@ template<class T> void MeshDataTest::indicesAsArray() {
indexView[1] = 131;
indexView[2] = 240;
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}};
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}, 241};
CORRADE_COMPARE_AS(data.indicesAsArray(),
Containers::arrayView<UnsignedInt>({75, 131, 240}),
TestSuite::Compare::Container);
@ -1688,7 +1742,7 @@ template<class T> void MeshDataTest::indicesAsArray() {
void MeshDataTest::indicesIntoArrayInvalidSize() {
Containers::Array<char> indexData{3*sizeof(UnsignedInt)};
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{Containers::arrayCast<UnsignedInt>(indexData)}};
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{Containers::arrayCast<UnsignedInt>(indexData)}, 1};
std::ostringstream out;
Error redirectError{&out};
@ -2338,7 +2392,7 @@ void MeshDataTest::indicesWrongType() {
Containers::Array<char> indexData{sizeof(UnsignedShort)};
auto indexView = Containers::arrayCast<UnsignedShort>(indexData);
indexView[0] = 57616;
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}};
MeshData data{MeshPrimitive::Points, std::move(indexData), MeshIndexData{indexView}, 57617};
std::ostringstream out;
Error redirectError{&out};
@ -2422,7 +2476,7 @@ void MeshDataTest::releaseIndexData() {
Containers::Array<char> indexData{23};
auto indexView = Containers::arrayCast<UnsignedShort>(indexData.slice(6, 12));
MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), MeshIndexData{indexView}};
MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), MeshIndexData{indexView}, 10};
CORRADE_VERIFY(data.isIndexed());
CORRADE_COMPARE(data.indexCount(), 3);
CORRADE_COMPARE(data.indexOffset(), 6);

Loading…
Cancel
Save