Browse Source

Trade: support morph targets in MeshData.

Attributes that are morph targets are marked with a morph target ID,
those then get treated separately in name-based lookups.
pull/623/head
Vladimír Vondruš 3 years ago
parent
commit
f84c3679c3
  1. 3
      doc/changelog.dox
  2. 2
      doc/developers.dox
  3. 17
      doc/snippets/MagnumTrade.cpp
  4. 22
      src/Magnum/MeshTools/Transform.h
  5. 260
      src/Magnum/Trade/MeshData.cpp
  6. 467
      src/Magnum/Trade/MeshData.h
  7. 715
      src/Magnum/Trade/Test/MeshDataTest.cpp

3
doc/changelog.dox

@ -769,6 +769,9 @@ See also:
- @ref Trade::MeshData now allows array attributes to have - @ref Trade::MeshData now allows array attributes to have
implementation-specific vertex formats as well. The restriction didn't make implementation-specific vertex formats as well. The restriction didn't make
sense, as there was nothing in the design preventing them from being used. sense, as there was nothing in the design preventing them from being used.
- @ref Trade::MeshData can now store morph target attributes next to the
base attributes, they're then accessed using a concrete morph target ID in
name-based lookup APIs
- Added @ref Trade::MeshData::findAttributeId() for an ability to check that - Added @ref Trade::MeshData::findAttributeId() for an ability to check that
an attribute exists and retrieve its ID in a single step, avoiding a double an attribute exists and retrieve its ID in a single step, avoiding a double
lookup compared to @relativeref{Trade::MeshData,hasAttribute()} + lookup compared to @relativeref{Trade::MeshData,hasAttribute()} +

2
doc/developers.dox

@ -604,7 +604,7 @@ in inverse --- but usually @ref developers-deprecation "deprecate first".
`isVertexFormatCompatibleWithAttribute()` if there's more than one entry `isVertexFormatCompatibleWithAttribute()` if there's more than one entry
corresponding to a particular C++ type. If the mapping is unconventional, corresponding to a particular C++ type. If the mapping is unconventional,
be sure to mention it in the be sure to mention it in the
@ref Trade::MeshAttributeData::MeshAttributeData(MeshAttribute, const Containers::StridedArrayView1D<T>&) @ref Trade::MeshAttributeData::MeshAttributeData(MeshAttribute, const Containers::StridedArrayView1D<T>&, Int)
constructor docs. constructor docs.
4. Update corresponding `Trade::MeshData::*Into()` convenience getters to 4. Update corresponding `Trade::MeshData::*Into()` convenience getters to
ensure they can handle this type ensure they can handle this type

17
doc/snippets/MagnumTrade.cpp

@ -867,6 +867,23 @@ MeshTools::transformPointsInPlace(Matrix4::scaling(Vector3{2.0f}),
/* [MeshData-usage-mutable] */ /* [MeshData-usage-mutable] */
} }
{
Trade::MeshData data{MeshPrimitive::Points, 0};
/* [MeshData-usage-morph-targets] */
Float weights[]{0.25f, 0.5f};
/* Calculate morphed positions with the above weights, assuming the mesh has
a Vector3 Position attribute in morph targets 0 and 1 */
Containers::Array<Vector3> positions = data.positions3DAsArray(0, -1);
for(Int morphTargetId: {0, 1}) {
Containers::StridedArrayView1D<const Vector3> morphed =
data.attribute<Vector3>(Trade::MeshAttribute::Position, 0, morphTargetId);
for(std::size_t i = 0; i != data.vertexCount(); ++i)
positions[i] += morphed[i]*weights[morphTargetId];
}
/* [MeshData-usage-morph-targets] */
}
{ {
Trade::MeshData data{MeshPrimitive::Points, 0}; Trade::MeshData data{MeshPrimitive::Points, 0};
/* [MeshData-usage-special-layouts] */ /* [MeshData-usage-special-layouts] */

22
src/Magnum/MeshTools/Transform.h

@ -161,8 +161,8 @@ See also @ref transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Interl
for a potentially more efficient operation instead of always performing a full for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using @ref transform2DInPlace(). copy, you can also do an in-place transformation using @ref transform2DInPlace().
@see @ref transform3D(), @ref transformTextureCoordinates2D(), @see @ref transform3D(), @ref transformTextureCoordinates2D(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const, @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
@ -191,8 +191,8 @@ packed types, the in-place operation requires the position type to be
@p id, and indices (if any) are left untouched. @p id, and indices (if any) are left untouched.
@see @ref transform3DInPlace(), @ref transformTextureCoordinates2DInPlace(), @see @ref transform3DInPlace(), @ref transformTextureCoordinates2DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0);
@ -219,8 +219,8 @@ See also @ref transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Interl
for a potentially more efficient operation instead of always performing a full for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using @ref transform3DInPlace(). copy, you can also do an in-place transformation using @ref transform3DInPlace().
@see @ref transform2D(), @ref transformTextureCoordinates2D(), @see @ref transform2D(), @ref transformTextureCoordinates2D(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const, @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
@ -255,8 +255,8 @@ operation requires the position, normal and bitangent types to be
than @p id, and indices (if any) are left untouched. than @p id, and indices (if any) are left untouched.
@see @ref transform2DInPlace(), @ref transformTextureCoordinates2DInPlace(), @see @ref transform2DInPlace(), @ref transformTextureCoordinates2DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0);
@ -277,7 +277,7 @@ for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using copy, you can also do an in-place transformation using
@ref transformTextureCoordinates2DInPlace(). @ref transformTextureCoordinates2DInPlace().
@see @ref transform2D(), @ref transform3D(), @see @ref transform2D(), @ref transform3D(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
@ -308,8 +308,8 @@ coordinate attributes other than @p id, and indices (if any) are passed through
untouched. untouched.
@see @ref transform2DInPlace(), @ref transform3DInPlace(), @see @ref transform2DInPlace(), @ref transform3DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0);

260
src/Magnum/Trade/MeshData.cpp

@ -59,13 +59,13 @@ MeshIndexData::MeshIndexData(const Containers::StridedArrayView2D<const char>& d
"Trade::MeshIndexData: second view dimension is not contiguous", ); "Trade::MeshIndexData: second view dimension is not contiguous", );
} }
MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, UnsignedShort arraySize) noexcept: MeshAttributeData{nullptr, name, format, data, arraySize} { MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, const UnsignedShort arraySize, const Int morphTargetId) noexcept: MeshAttributeData{nullptr, name, format, data, arraySize, morphTargetId} {
/* Yes, this calls into a constexpr function defined in the header -- /* Yes, this calls into a constexpr function defined in the header --
because I feel that makes more sense than duplicating the full assert because I feel that makes more sense than duplicating the full assert
logic */ logic */
} }
MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView2D<const char>& data, UnsignedShort arraySize) noexcept: MeshAttributeData{nullptr, name, format, Containers::StridedArrayView1D<const void>{{data.data(), ~std::size_t{}}, data.size()[0], data.stride()[0]}, arraySize} { MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView2D<const char>& data, UnsignedShort arraySize, const Int morphTargetId) noexcept: MeshAttributeData{nullptr, name, format, Containers::StridedArrayView1D<const void>{{data.data(), ~std::size_t{}}, data.size()[0], data.stride()[0]}, arraySize, morphTargetId} {
/* Yes, this calls into a constexpr function defined in the header -- /* Yes, this calls into a constexpr function defined in the header --
because I feel that makes more sense than duplicating the full assert because I feel that makes more sense than duplicating the full assert
logic */ logic */
@ -218,6 +218,12 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
"Trade::MeshData: attribute" << i << "[" << Debug::nospace << reinterpret_cast<const void*>(begin) << Debug::nospace << ":" << Debug::nospace << reinterpret_cast<const void*>(end) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_vertexData.end()) << Debug::nospace << "]", ); "Trade::MeshData: attribute" << i << "[" << Debug::nospace << reinterpret_cast<const void*>(begin) << Debug::nospace << ":" << Debug::nospace << reinterpret_cast<const void*>(end) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_vertexData.end()) << Debug::nospace << "]", );
} }
} }
/** @todo verify that (custom) integer attributes aren't morph targets?
(can't check that in MeshAttributeData constructors as
isVertexFormatInteger() -- once implemented -- wouldn't be
constexpr); or just leave that unchecked, as those are often used
for custom unheard-of behavior anyway? */
} }
/* Verify that count and array sizes of skin joint IDs and weights match */ /* Verify that count and array sizes of skin joint IDs and weights match */
@ -371,11 +377,19 @@ Containers::StridedArrayView1D<const void> MeshData::attributeDataViewInternal(c
_vertexCount, attribute._stride}; _vertexCount, attribute._stride};
} }
UnsignedInt MeshData::attributeCount(const Int morphTargetId) const {
UnsignedInt count = 0;
for(const MeshAttributeData& attribute: _attributes)
if(attribute._morphTargetId == morphTargetId)
++count;
return count;
}
MeshAttributeData MeshData::attributeData(const UnsignedInt id) const { MeshAttributeData MeshData::attributeData(const UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(), CORRADE_ASSERT(id < _attributes.size(),
"Trade::MeshData::attributeData(): index" << id << "out of range for" << _attributes.size() << "attributes", MeshAttributeData{}); "Trade::MeshData::attributeData(): index" << id << "out of range for" << _attributes.size() << "attributes", MeshAttributeData{});
const MeshAttributeData& attribute = _attributes[id]; const MeshAttributeData& attribute = _attributes[id];
return MeshAttributeData{attribute._name, attribute._format, attributeDataViewInternal(attribute), attribute._arraySize}; return MeshAttributeData{attribute._name, attribute._format, attributeDataViewInternal(attribute), attribute._arraySize, attribute._morphTargetId};
} }
MeshAttribute MeshData::attributeName(const UnsignedInt id) const { MeshAttribute MeshData::attributeName(const UnsignedInt id) const {
@ -388,9 +402,12 @@ UnsignedInt MeshData::attributeId(const UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(), CORRADE_ASSERT(id < _attributes.size(),
"Trade::MeshData::attributeId(): index" << id << "out of range for" << _attributes.size() << "attributes", {}); "Trade::MeshData::attributeId(): index" << id << "out of range for" << _attributes.size() << "attributes", {});
const MeshAttribute name = _attributes[id]._name; const MeshAttribute name = _attributes[id]._name;
const Int morphTargetId = _attributes[id]._morphTargetId;
UnsignedInt count = 0; UnsignedInt count = 0;
for(UnsignedInt i = 0; i != id; ++i) for(UnsignedInt i = 0; i != id; ++i)
if(_attributes[i]._name == name) ++count; if(_attributes[i]._name == name &&
_attributes[i]._morphTargetId == morphTargetId)
++count;
return count; return count;
} }
@ -419,54 +436,89 @@ UnsignedShort MeshData::attributeArraySize(const UnsignedInt id) const {
return _attributes[id]._arraySize; return _attributes[id]._arraySize;
} }
UnsignedInt MeshData::attributeCount(const MeshAttribute name) const { Int MeshData::attributeMorphTargetId(const UnsignedInt id) const {
CORRADE_ASSERT(id < _attributes.size(),
"Trade::MeshData::attributeMorphTargetId(): index" << id << "out of range for" << _attributes.size() << "attributes", {});
return _attributes[id]._morphTargetId;
}
UnsignedInt MeshData::attributeCount(const MeshAttribute name, const Int morphTargetId) const {
UnsignedInt count = 0; UnsignedInt count = 0;
for(const MeshAttributeData& attribute: _attributes) for(const MeshAttributeData& attribute: _attributes)
if(attribute._name == name) ++count; if(attribute._name == name &&
attribute._morphTargetId == morphTargetId)
++count;
return count; return count;
} }
UnsignedInt MeshData::findAttributeIdInternal(const MeshAttribute name, UnsignedInt id) const { UnsignedInt MeshData::findAttributeIdInternal(const MeshAttribute name, UnsignedInt id, const Int morphTargetId) const {
for(std::size_t i = 0; i != _attributes.size(); ++i) { for(std::size_t i = 0; i != _attributes.size(); ++i) {
if(_attributes[i]._name != name) continue; if(_attributes[i]._name != name ||
_attributes[i]._morphTargetId != morphTargetId)
continue;
if(id-- == 0) return i; if(id-- == 0) return i;
} }
return ~UnsignedInt{}; return ~UnsignedInt{};
} }
Containers::Optional<UnsignedInt> MeshData::findAttributeId(const MeshAttribute name, UnsignedInt id) const { Containers::Optional<UnsignedInt> MeshData::findAttributeId(const MeshAttribute name, UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
return attributeId == ~UnsignedInt{} ? Containers::Optional<UnsignedInt>{} : attributeId; return attributeId == ~UnsignedInt{} ? Containers::Optional<UnsignedInt>{} : attributeId;
} }
UnsignedInt MeshData::attributeId(const MeshAttribute name, const UnsignedInt id) const { UnsignedInt MeshData::attributeId(const MeshAttribute name, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attributeId(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeId(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeId(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return attributeId; return attributeId;
} }
VertexFormat MeshData::attributeFormat(const MeshAttribute name, const UnsignedInt id) const { VertexFormat MeshData::attributeFormat(const MeshAttribute name, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attributeFormat(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeFormat(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeFormat(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return _attributes[attributeId]._format; return _attributes[attributeId]._format;
} }
std::size_t MeshData::attributeOffset(const MeshAttribute name, const UnsignedInt id) const { std::size_t MeshData::attributeOffset(const MeshAttribute name, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attributeOffset(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeOffset(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeOffset(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
/* Calculation is non-trivial, delegating */ /* Calculation is non-trivial, delegating */
return attributeOffset(attributeId); return attributeOffset(attributeId);
} }
Short MeshData::attributeStride(const MeshAttribute name, const UnsignedInt id) const { Short MeshData::attributeStride(const MeshAttribute name, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attributeStride(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeStride(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeStride(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return _attributes[attributeId]._stride; return _attributes[attributeId]._stride;
} }
UnsignedShort MeshData::attributeArraySize(const MeshAttribute name, const UnsignedInt id) const { UnsignedShort MeshData::attributeArraySize(const MeshAttribute name, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attributeArraySize(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeArraySize(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attributeArraySize(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return _attributes[attributeId]._arraySize; return _attributes[attributeId]._arraySize;
} }
@ -502,17 +554,27 @@ Containers::StridedArrayView2D<char> MeshData::mutableAttribute(const UnsignedIn
out.size(), out.stride()}; out.size(), out.stride()};
} }
Containers::StridedArrayView2D<const char> MeshData::attribute(const MeshAttribute name, UnsignedInt id) const { Containers::StridedArrayView2D<const char> MeshData::attribute(const MeshAttribute name, UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::attribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attribute(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::attribute(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return attribute(attributeId); return attribute(attributeId);
} }
Containers::StridedArrayView2D<char> MeshData::mutableAttribute(const MeshAttribute name, UnsignedInt id) { Containers::StridedArrayView2D<char> MeshData::mutableAttribute(const MeshAttribute name, UnsignedInt id, const Int morphTargetId) {
CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable, CORRADE_ASSERT(_vertexDataFlags & DataFlag::Mutable,
"Trade::MeshData::mutableAttribute(): vertex data not mutable", {}); "Trade::MeshData::mutableAttribute(): vertex data not mutable", {});
const UnsignedInt attributeId = findAttributeIdInternal(name, id); const UnsignedInt attributeId = findAttributeIdInternal(name, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << attributeCount(name) << name << "attributes", {}); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes", {});
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::mutableAttribute(): index" << id << "out of range for" << attributeCount(name, morphTargetId) << name << "attributes in morph target" << morphTargetId, {});
#endif
return mutableAttribute(attributeId); return mutableAttribute(attributeId);
} }
@ -544,9 +606,14 @@ Containers::Array<UnsignedInt> MeshData::indicesAsArray() const {
return output; return output;
} }
void MeshData::positions2DInto(const Containers::StridedArrayView1D<Vector2>& destination, const UnsignedInt id) const { void MeshData::positions2DInto(const Containers::StridedArrayView1D<Vector2>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Position, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::positions2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position) << "position attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::positions2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position, morphTargetId) << "position attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::positions2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position, morphTargetId) << "position attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -588,15 +655,20 @@ void MeshData::positions2DInto(const Containers::StridedArrayView1D<Vector2>& de
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
Containers::Array<Vector2> MeshData::positions2DAsArray(const UnsignedInt id) const { Containers::Array<Vector2> MeshData::positions2DAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector2> out{NoInit, _vertexCount}; Containers::Array<Vector2> out{NoInit, _vertexCount};
positions2DInto(out, id); positions2DInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id) const { void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Position, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::positions3DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position) << "position attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::positions3DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position, morphTargetId) << "position attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::positions3DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Position, morphTargetId) << "position attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions3DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions3DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -669,9 +741,9 @@ void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3>& de
} }
} }
Containers::Array<Vector3> MeshData::positions3DAsArray(const UnsignedInt id) const { Containers::Array<Vector3> MeshData::positions3DAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector3> out{NoInit, _vertexCount}; Containers::Array<Vector3> out{NoInit, _vertexCount};
positions3DInto(out, id); positions3DInto(out, id, morphTargetId);
return out; return out;
} }
@ -693,9 +765,14 @@ void tangentsOrNormalsInto(const Containers::StridedArrayView1D<const void>& att
} }
void MeshData::tangentsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id) const { void MeshData::tangentsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Tangent, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Tangent, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::tangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent) << "tangent attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::tangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent, morphTargetId) << "tangent attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::tangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent, morphTargetId) << "tangent attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::tangentsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::tangentsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -716,15 +793,20 @@ void MeshData::tangentsInto(const Containers::StridedArrayView1D<Vector3>& desti
tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, format); tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, format);
} }
Containers::Array<Vector3> MeshData::tangentsAsArray(const UnsignedInt id) const { Containers::Array<Vector3> MeshData::tangentsAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector3> out{NoInit, _vertexCount}; Containers::Array<Vector3> out{NoInit, _vertexCount};
tangentsInto(out, id); tangentsInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::bitangentSignsInto(const Containers::StridedArrayView1D<Float>& destination, const UnsignedInt id) const { void MeshData::bitangentSignsInto(const Containers::StridedArrayView1D<Float>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Tangent, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Tangent, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::bitangentSignsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent) << "tangent attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::bitangentSignsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent, morphTargetId) << "tangent attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::bitangentSignsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Tangent, morphTargetId) << "tangent attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::bitangentSignsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::bitangentSignsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -743,15 +825,20 @@ void MeshData::bitangentSignsInto(const Containers::StridedArrayView1D<Float>& d
else CORRADE_ASSERT_UNREACHABLE("Trade::MeshData::bitangentSignsInto(): expected four-component tangents, but got" << attribute._format, ); else CORRADE_ASSERT_UNREACHABLE("Trade::MeshData::bitangentSignsInto(): expected four-component tangents, but got" << attribute._format, );
} }
Containers::Array<Float> MeshData::bitangentSignsAsArray(const UnsignedInt id) const { Containers::Array<Float> MeshData::bitangentSignsAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Float> out{NoInit, _vertexCount}; Containers::Array<Float> out{NoInit, _vertexCount};
bitangentSignsInto(out, id); bitangentSignsInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::bitangentsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id) const { void MeshData::bitangentsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Bitangent, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Bitangent, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::bitangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Bitangent) << "bitangent attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::bitangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Bitangent, morphTargetId) << "bitangent attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::bitangentsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Bitangent, morphTargetId) << "bitangent attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::bitangentsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::bitangentsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -759,15 +846,20 @@ void MeshData::bitangentsInto(const Containers::StridedArrayView1D<Vector3>& des
tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, attribute._format); tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, attribute._format);
} }
Containers::Array<Vector3> MeshData::bitangentsAsArray(const UnsignedInt id) const { Containers::Array<Vector3> MeshData::bitangentsAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector3> out{NoInit, _vertexCount}; Containers::Array<Vector3> out{NoInit, _vertexCount};
bitangentsInto(out, id); bitangentsInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id) const { void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Normal, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Normal, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::normalsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Normal) << "normal attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::normalsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Normal, morphTargetId) << "normal attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::normalsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Normal, morphTargetId) << "normal attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -775,15 +867,20 @@ void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3>& destin
tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, attribute._format); tangentsOrNormalsInto(attributeDataViewInternal(attribute), destination, attribute._format);
} }
Containers::Array<Vector3> MeshData::normalsAsArray(const UnsignedInt id) const { Containers::Array<Vector3> MeshData::normalsAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector3> out{NoInit, _vertexCount}; Containers::Array<Vector3> out{NoInit, _vertexCount};
normalsInto(out, id); normalsInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vector2>& destination, const UnsignedInt id) const { void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vector2>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::TextureCoordinates, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::TextureCoordinates, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::textureCoordinates2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::TextureCoordinates) << "texture coordinate attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::textureCoordinates2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::TextureCoordinates, morphTargetId) << "texture coordinate attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::textureCoordinates2DInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::TextureCoordinates, morphTargetId) << "texture coordinate attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -814,15 +911,20 @@ void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vec
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
Containers::Array<Vector2> MeshData::textureCoordinates2DAsArray(const UnsignedInt id) const { Containers::Array<Vector2> MeshData::textureCoordinates2DAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Vector2> out{NoInit, _vertexCount}; Containers::Array<Vector2> out{NoInit, _vertexCount};
textureCoordinates2DInto(out, id); textureCoordinates2DInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4>& destination, const UnsignedInt id) const { void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4>& destination, const UnsignedInt id, const Int morphTargetId) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Color, id); const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Color, id, morphTargetId);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::colorsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Color) << "color attributes", ); #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::colorsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Color, morphTargetId) << "color attributes", );
else CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::colorsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Color, morphTargetId) << "color attributes in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::colorsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::colorsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
@ -867,14 +969,15 @@ void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4>& destinat
} }
} }
Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const { Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id, const Int morphTargetId) const {
Containers::Array<Color4> out{NoInit, _vertexCount}; Containers::Array<Color4> out{NoInit, _vertexCount};
colorsInto(out, id); colorsInto(out, id, morphTargetId);
return out; return out;
} }
void MeshData::jointIdsInto(const Containers::StridedArrayView2D<UnsignedInt>& destination, const UnsignedInt id) const { void MeshData::jointIdsInto(const Containers::StridedArrayView2D<UnsignedInt>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id); /* Joint IDs can't have morph targets */
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id, -1);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::jointIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", ); "Trade::MeshData::jointIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
@ -899,7 +1002,8 @@ void MeshData::jointIdsInto(const Containers::StridedArrayView2D<UnsignedInt>& d
} }
Containers::Array<UnsignedInt> MeshData::jointIdsAsArray(const UnsignedInt id) const { Containers::Array<UnsignedInt> MeshData::jointIdsAsArray(const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id); /* Joint IDs can't have morph targets */
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id, -1);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::jointIdsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", {}); "Trade::MeshData::jointIdsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", {});
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
@ -909,7 +1013,8 @@ Containers::Array<UnsignedInt> MeshData::jointIdsAsArray(const UnsignedInt id) c
} }
void MeshData::weightsInto(const Containers::StridedArrayView2D<Float>& destination, const UnsignedInt id) const { void MeshData::weightsInto(const Containers::StridedArrayView2D<Float>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id); /* Weights can't have morph targets */
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id, -1);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::weightsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Weights) << "weight attributes", ); "Trade::MeshData::weightsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Weights) << "weight attributes", );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
@ -936,7 +1041,8 @@ void MeshData::weightsInto(const Containers::StridedArrayView2D<Float>& destinat
} }
Containers::Array<Float> MeshData::weightsAsArray(const UnsignedInt id) const { Containers::Array<Float> MeshData::weightsAsArray(const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id); /* Weights can't have morph targets */
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id, -1);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::weightsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "weight attributes", {}); CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::weightsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "weight attributes", {});
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
Containers::Array<Float> out{_vertexCount*attribute._arraySize}; Containers::Array<Float> out{_vertexCount*attribute._arraySize};
@ -945,7 +1051,8 @@ Containers::Array<Float> MeshData::weightsAsArray(const UnsignedInt id) const {
} }
void MeshData::objectIdsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination, const UnsignedInt id) const { void MeshData::objectIdsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::ObjectId, id); /* Object IDs can't have morph targets */
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::ObjectId, id, -1);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::objectIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::ObjectId) << "object ID attributes", ); CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::objectIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::ObjectId) << "object ID attributes", );
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::objectIdsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::objectIdsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
@ -965,6 +1072,7 @@ void MeshData::objectIdsInto(const Containers::StridedArrayView1D<UnsignedInt>&
Containers::Array<UnsignedInt> MeshData::objectIdsAsArray(const UnsignedInt id) const { Containers::Array<UnsignedInt> MeshData::objectIdsAsArray(const UnsignedInt id) const {
Containers::Array<UnsignedInt> out{NoInit, _vertexCount}; Containers::Array<UnsignedInt> out{NoInit, _vertexCount};
/* Object IDs can't have morph targets */
objectIdsInto(out, id); objectIdsInto(out, id);
return out; return out;
} }

467
src/Magnum/Trade/MeshData.h

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save