Browse Source

Trade: make MeshData::release*() less brutal, add releaseAttributeData().

It only resets count of released thing to zero, not going all nuclear.
Otherwise it wouldn't be possible to release attribute data and then
vertex data as releasing one would wipe the other.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
a3c5c0052d
  1. 29
      src/Magnum/Trade/MeshData.cpp
  2. 40
      src/Magnum/Trade/MeshData.h
  3. 59
      src/Magnum/Trade/Test/MeshDataTest.cpp

29
src/Magnum/Trade/MeshData.cpp

@ -282,9 +282,11 @@ UnsignedInt MeshData::attributeStride(MeshAttribute name, UnsignedInt id) const
Containers::StridedArrayView2D<const char> MeshData::attribute(UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(),
"Trade::MeshData::attribute(): index" << id << "out of range for" << _attributes.size() << "attributes", nullptr);
/* Build a 2D view using information about attribute type size */
/* Build a 2D view using information about attribute type size, return only
a prefix of the actual vertex count (which is zero in case vertex data
is released) */
return Containers::arrayCast<2, const char>(_attributes[id]._data,
vertexFormatSize(_attributes[id]._format));
vertexFormatSize(_attributes[id]._format)).prefix(_vertexCount);
}
Containers::StridedArrayView2D<char> MeshData::mutableAttribute(UnsignedInt id) {
@ -292,9 +294,11 @@ 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);
/* Build a 2D view using information about attribute type size */
/* Build a 2D view using information about attribute type size, return only
a prefix of the actual vertex count (which is zero in case vertex data
is released) */
auto out = Containers::arrayCast<2, const char>(_attributes[id]._data,
vertexFormatSize(_attributes[id]._format));
vertexFormatSize(_attributes[id]._format)).prefix(_vertexCount);
/** @todo some arrayConstCast? UGH */
return Containers::StridedArrayView2D<char>{
/* The view size is there only for a size assert, we're pretty sure the
@ -458,14 +462,21 @@ Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const {
}
Containers::Array<char> MeshData::releaseIndexData() {
_indexType = MeshIndexType{}; /* so isIndexed() returns false */
_indices = nullptr;
return std::move(_indexData);
_indices = {_indices.data(), 0};
Containers::Array<char> out = std::move(_indexData);
_indexData = Containers::Array<char>{out.data(), 0, Implementation::nonOwnedArrayDeleter};
return out;
}
Containers::Array<MeshAttributeData> MeshData::releaseAttributeData() {
return std::move(_attributes);
}
Containers::Array<char> MeshData::releaseVertexData() {
_attributes = nullptr;
return std::move(_vertexData);
_vertexCount = 0;
Containers::Array<char> out = std::move(_vertexData);
_vertexData = Containers::Array<char>{out.data(), 0, Implementation::nonOwnedArrayDeleter};
return out;
}
Debug& operator<<(Debug& debug, const MeshAttribute value) {

40
src/Magnum/Trade/MeshData.h

@ -1073,21 +1073,45 @@ class MAGNUM_TRADE_EXPORT MeshData {
*
* Releases the ownership of the index data array and resets internal
* index-related state to default. The mesh then behaves like
* non-indexed. Note that the returned array has a custom no-op deleter
* when the data are not owned by the mesh, and while the returned
* array type is mutable, the actual memory might be not.
* it has zero indices (but it can still have a non-zero vertex count),
* however @ref indexData() still return a zero-sized non-null array so
* index offset calculation continues to work as expected.
*
* Note that the returned array has a custom no-op deleter when the
* data are not owned by the mesh, and while the returned array type is
* mutable, the actual memory might be not.
* @see @ref indexData(), @ref indexDataFlags()
*/
Containers::Array<char> releaseIndexData();
/**
* @brief Release attribute data storage
*
* Releases the ownership of the attribute data array and resets
* internal attribute-related state to default. The mesh then behaves
* like if it has no attributes (but it can still have a non-zero
* vertex count). Note that the returned array has a custom no-op
* deleter when the data are not owned by the mesh, and while the
* returned array type is mutable, the actual memory might be not ---
* use this function only if you are sure about the origin of the
* array.
* @see @ref attributeData()
*/
Containers::Array<MeshAttributeData> releaseAttributeData();
/**
* @brief Release vertex data storage
*
* Releases the ownership of the index data array and resets internal
* attribute-related state to default. The mesh then behaves like if
* it has no attributes. Note that the returned array has a custom
* no-op deleter when the data are not owned by the mesh, and while the
* returned array type is mutable, the actual memory might be not.
* Releases the ownership of the vertex data array and resets internal
* attribute-related state to default. The mesh then behaves like it
* has zero vertices (but it can still have a non-zero amount of
* attributes), however @ref vertexData() will still return a zero-
* sized non-null array so attribute offset calculation continues to
* work as expected.
*
* Note that the returned array has a custom no-op deleter when the
* data are not owned by the mesh, and while the returned array type is
* mutable, the actual memory might be not.
* @see @ref vertexData(), @ref vertexDataFlags()
*/
Containers::Array<char> releaseVertexData();

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

@ -115,6 +115,7 @@ struct MeshDataTest: TestSuite::Tester {
void attributeWrongType();
void releaseIndexData();
void releaseAttributeData();
void releaseVertexData();
};
@ -223,6 +224,7 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::attributeWrongType,
&MeshDataTest::releaseIndexData,
&MeshDataTest::releaseAttributeData,
&MeshDataTest::releaseVertexData});
}
@ -1581,19 +1583,26 @@ void MeshDataTest::attributeWrongType() {
}
void MeshDataTest::releaseIndexData() {
Containers::Array<char> indexData{6};
auto indexView = Containers::arrayCast<UnsignedShort>(indexData);
Containers::Array<char> indexData{23};
auto indexView = Containers::arrayCast<UnsignedShort>(indexData.slice(6, 12));
MeshData data{MeshPrimitive::TriangleStrip, std::move(indexData), MeshIndexData{indexView}};
CORRADE_VERIFY(data.isIndexed());
CORRADE_COMPARE(data.indexCount(), 3);
CORRADE_COMPARE(data.indexOffset(), 6);
Containers::Array<char> released = data.releaseIndexData();
CORRADE_COMPARE(static_cast<void*>(released.data()), indexView.data());
CORRADE_COMPARE(data.indexData(), nullptr);
CORRADE_VERIFY(!data.isIndexed());
CORRADE_COMPARE(static_cast<void*>(released.data() + 6), indexView.data());
/* This is not null as we still need the value for calculating offsets */
CORRADE_COMPARE(static_cast<const void*>(data.indexData()), released.data());
CORRADE_COMPARE(data.indexData().size(), 0);
CORRADE_VERIFY(data.isIndexed());
CORRADE_COMPARE(data.indexCount(), 0);
CORRADE_COMPARE(data.indexType(), MeshIndexType::UnsignedShort);
CORRADE_COMPARE(data.indexOffset(), 6);
}
void MeshDataTest::releaseVertexData() {
void MeshDataTest::releaseAttributeData() {
Containers::Array<char> vertexData{16};
auto vertexView = Containers::arrayCast<Vector2>(vertexData);
@ -1601,9 +1610,43 @@ void MeshDataTest::releaseVertexData() {
MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions, positions}};
CORRADE_COMPARE(data.attributeCount(), 2);
Containers::Array<char> released = data.releaseVertexData();
CORRADE_COMPARE(data.vertexData(), nullptr);
Containers::Array<MeshAttributeData> released = data.releaseAttributeData();
CORRADE_COMPARE(released.size(), 2);
CORRADE_COMPARE(static_cast<const void*>(released[0].data().data()), vertexView.data());
CORRADE_COMPARE(released[0].data().size(), 2);
/* Unlike the other two, this is null as we don't need the value for
calculating anything */
CORRADE_COMPARE(static_cast<const void*>(data.attributeData()), nullptr);
CORRADE_COMPARE(data.attributeCount(), 0);
CORRADE_COMPARE(static_cast<const void*>(data.vertexData()), vertexView);
CORRADE_COMPARE(data.vertexCount(), 2);
}
void MeshDataTest::releaseVertexData() {
Containers::Array<char> vertexData{80};
auto vertexView = Containers::arrayCast<Vector2>(vertexData.slice(48, 72));
MeshAttributeData positions{MeshAttribute::Position, vertexView};
MeshData data{MeshPrimitive::LineLoop, std::move(vertexData), {positions, positions}};
CORRADE_COMPARE(data.attributeCount(), 2);
CORRADE_COMPARE(data.vertexCount(), 3);
CORRADE_COMPARE(data.attributeOffset(0), 48);
Containers::Array<char> released = data.releaseVertexData();
CORRADE_VERIFY(data.attributeData());
CORRADE_COMPARE(data.attributeCount(), 2);
CORRADE_COMPARE(static_cast<const void*>(static_cast<const char*>(data.attribute(0).data())), vertexView.data());
CORRADE_COMPARE(static_cast<const void*>(static_cast<const char*>(data.mutableAttribute(0).data())), vertexView.data());
/* Returned views should be patched to have zero size (but not the direct
access, there it stays as it's an internal API really) */
CORRADE_COMPARE(data.attribute(0).size()[0], 0);
CORRADE_COMPARE(data.mutableAttribute(0).size()[0], 0);
CORRADE_COMPARE(data.attributeData()[0].data().size(), 3);
CORRADE_COMPARE(static_cast<void*>(released.data() + 48), vertexView.data());
/* This is not null as we still need the value for calculating offsets */
CORRADE_COMPARE(static_cast<const void*>(data.vertexData()), released.data());
CORRADE_COMPARE(data.vertexCount(), 0);
CORRADE_COMPARE(data.attributeOffset(0), 48);
}
}}}}

Loading…
Cancel
Save