Browse Source

Trade: implement support for object IDs in MeshData.

pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
8a2a7e4547
  1. 26
      src/Magnum/Trade/MeshData.cpp
  2. 54
      src/Magnum/Trade/MeshData.h
  3. 45
      src/Magnum/Trade/Test/MeshDataTest.cpp

26
src/Magnum/Trade/MeshData.cpp

@ -747,6 +747,31 @@ Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const {
return out;
}
void MeshData::objectIdsInto(const Containers::StridedArrayView1D<UnsignedInt> destination, const UnsignedInt id) const {
const UnsignedInt attributeId = attributeFor(MeshAttribute::ObjectId, id);
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(), );
const MeshAttributeData& attribute = _attributes[attributeId];
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::objectIdsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);
const auto destination1ui = Containers::arrayCast<2, UnsignedInt>(destination);
if(attribute._format == VertexFormat::UnsignedInt)
Utility::copy(Containers::arrayCast<const UnsignedInt>(attributeData), destination);
else if(attribute._format == VertexFormat::UnsignedShort)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 1), destination1ui);
else if(attribute._format == VertexFormat::UnsignedByte)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 1), destination1ui);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Array<UnsignedInt> MeshData::objectIdsAsArray(const UnsignedInt id) const {
Containers::Array<UnsignedInt> out{_vertexCount};
objectIdsInto(out, id);
return out;
}
Containers::Array<char> MeshData::releaseIndexData() {
_indices = {_indices.data(), 0};
Containers::Array<char> out = std::move(_indexData);
@ -780,6 +805,7 @@ Debug& operator<<(Debug& debug, const MeshAttribute value) {
_c(Normal)
_c(TextureCoordinates)
_c(Color)
_c(ObjectId)
#undef _c
/* LCOV_EXCL_STOP */

54
src/Magnum/Trade/MeshData.h

@ -136,6 +136,14 @@ enum class MeshAttribute: UnsignedShort {
*/
Color,
/**
* (Instanced) object ID for editor selection or scene annotation. Type is
* usually @ref VertexFormat::UnsignedInt, but can be also
* @ref VertexFormat::UnsignedShort or @ref VertexFormat::UnsignedByte.
* @see @ref MeshData::objectIdsAsArray()
*/
ObjectId,
/**
* This and all higher values are for importer-specific attributes. Can be
* of any type. See documentation of a particular importer for details.
@ -594,11 +602,11 @@ the @ref Primitives library.
The simplest usage is through the convenience functions @ref positions2DAsArray(),
@ref positions3DAsArray(), @ref tangentsAsArray(), @ref bitangentsAsArray(),
@ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray()
and @ref colorsAsArray(). Each of these takes an index (as there can be
multiple sets of texture coordinates, for example) and you're expected to check
for attribute presence first with either @ref hasAttribute() or
@ref attributeCount(MeshAttribute) const:
@ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray(),
@ref colorsAsArray() and @ref objectIdsAsArray(). Each of these takes an index
(as there can be multiple sets of texture coordinates, for example) and you're
expected to check for attribute presence first with either @ref hasAttribute()
or @ref attributeCount(MeshAttribute) const:
@snippet MagnumTrade.cpp MeshData-usage
@ -1326,10 +1334,10 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @ref positions2DAsArray(), @ref positions3DAsArray(),
* @ref tangentsAsArray(), @ref bitangentSignsAsArray(),
* @ref bitangentsAsArray(), @ref normalsAsArray(),
* @ref textureCoordinates2DAsArray() and @ref colorsAsArray()
* accessors to get common attributes converted to usual types, but
* note that these operations involve extra allocation and data
* conversion.
* @ref textureCoordinates2DAsArray(), @ref colorsAsArray() and
* @ref objectIdsAsArray() accessors to get common attributes converted
* to usual types, but note that these operations involve extra
* allocation and data conversion.
* @see @ref attribute(MeshAttribute, UnsignedInt) const,
* @ref mutableAttribute(MeshAttribute, UnsignedInt),
* @ref isVertexFormatImplementationSpecific(),
@ -1675,6 +1683,30 @@ class MAGNUM_TRADE_EXPORT MeshData {
*/
void colorsInto(Containers::StridedArrayView1D<Color4> destination, UnsignedInt id = 0) const;
/**
* @brief Object IDs as 32-bit integers
*
* Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const
* with @ref MeshAttribute::ObjectId as the first argument. Converts
* the object ID array from an arbitrary underlying type and returns it
* in a newly-allocated array. Expects that the vertex format is *not*
* implementation-specific, in that case you can only access the
* attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const.
* @see @ref objectIdsInto(), @ref attributeFormat(),
* @ref isVertexFormatImplementationSpecific()
*/
Containers::Array<UnsignedInt> objectIdsAsArray(UnsignedInt id = 0) const;
/**
* @brief Object IDs as 32-bit integers into a pre-allocated view
*
* Like @ref objectIdsAsArray(), but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
* @see @ref vertexCount()
*/
void objectIdsInto(Containers::StridedArrayView1D<UnsignedInt> destination, UnsignedInt id = 0) const;
/**
* @brief Release index data storage
*
@ -2014,6 +2046,10 @@ namespace Implementation {
format == VertexFormat::Vector2usNormalized ||
format == VertexFormat::Vector2s ||
format == VertexFormat::Vector2sNormalized)) ||
(name == MeshAttribute::ObjectId &&
(format == VertexFormat::UnsignedInt ||
format == VertexFormat::UnsignedShort ||
format == VertexFormat::UnsignedByte)) ||
/* Custom attributes can be anything */
isMeshAttributeCustom(name);
}

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

@ -143,6 +143,8 @@ struct MeshDataTest: TestSuite::Tester {
template<class T> void colorsAsArray();
template<class T> void colorsAsArrayPackedUnsignedNormalized();
void colorsIntoArrayInvalidSize();
template<class T> void objectIdsAsArray();
void objectIdsIntoArrayInvalidSize();
void implementationSpecificVertexFormat();
void implementationSpecificVertexFormatWrongAccess();
@ -353,6 +355,10 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4ub>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4us>,
&MeshDataTest::colorsIntoArrayInvalidSize,
&MeshDataTest::objectIdsAsArray<UnsignedByte>,
&MeshDataTest::objectIdsAsArray<UnsignedShort>,
&MeshDataTest::objectIdsAsArray<UnsignedInt>,
&MeshDataTest::objectIdsIntoArrayInvalidSize,
&MeshDataTest::implementationSpecificVertexFormat,
&MeshDataTest::implementationSpecificVertexFormatWrongAccess,
@ -2308,6 +2314,35 @@ void MeshDataTest::colorsIntoArrayInvalidSize() {
"Trade::MeshData::colorsInto(): expected a view with 3 elements but got 2\n");
}
template<class T> void MeshDataTest::objectIdsAsArray() {
setTestCaseTemplateName(Math::TypeTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto objectIdsView = Containers::arrayCast<T>(vertexData);
/* Can't use e.g. 0xff3366_rgbf because that's not representable in
half-floats */
objectIdsView[0] = {157};
objectIdsView[1] = {24};
objectIdsView[2] = {1};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::ObjectId, objectIdsView}}};
CORRADE_COMPARE_AS(data.objectIdsAsArray(), Containers::arrayView<UnsignedInt>({
157, 24, 1
}), TestSuite::Compare::Container);
}
void MeshDataTest::objectIdsIntoArrayInvalidSize() {
Containers::Array<char> vertexData{3*sizeof(UnsignedInt)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::ObjectId, Containers::arrayCast<UnsignedInt>(vertexData)}}};
std::ostringstream out;
Error redirectError{&out};
UnsignedInt destination[2];
data.objectIdsInto(destination);
CORRADE_COMPARE(out.str(),
"Trade::MeshData::objectIdsInto(): expected a view with 3 elements but got 2\n");
}
/* MSVC 2015 doesn't like anonymous bitfields in inline structs, so putting the
declaration outside */
struct VertexWithImplementationSpecificData {
@ -2375,6 +2410,8 @@ void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
MeshAttributeData{MeshAttribute::TextureCoordinates,
vertexFormatWrap(0xdead3), attribute},
MeshAttributeData{MeshAttribute::Color,
vertexFormatWrap(0xdead4), attribute},
MeshAttributeData{MeshAttribute::ObjectId,
vertexFormatWrap(0xdead4), attribute}}};
std::ostringstream out;
@ -2395,6 +2432,7 @@ void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
data.normalsAsArray();
data.textureCoordinates2DAsArray();
data.colorsAsArray();
data.objectIdsAsArray();
CORRADE_COMPARE(out.str(),
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead1\n"
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead2\n"
@ -2411,7 +2449,8 @@ void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
"Trade::MeshData::bitangentsInto(): can't extract data out of an implementation-specific vertex format 0xdead2\n"
"Trade::MeshData::normalsInto(): can't extract data out of an implementation-specific vertex format 0xdead2\n"
"Trade::MeshData::textureCoordinatesInto(): can't extract data out of an implementation-specific vertex format 0xdead3\n"
"Trade::MeshData::colorsInto(): can't extract data out of an implementation-specific vertex format 0xdead4\n");
"Trade::MeshData::colorsInto(): can't extract data out of an implementation-specific vertex format 0xdead4\n"
"Trade::MeshData::objectIdsInto(): can't extract data out of an implementation-specific vertex format 0xdead4\n");
}
void MeshDataTest::implementationSpecificVertexFormatNotContained() {
@ -2624,6 +2663,7 @@ void MeshDataTest::attributeNotFound() {
data.normalsAsArray();
data.textureCoordinates2DAsArray();
data.colorsAsArray(2);
data.objectIdsAsArray();
CORRADE_COMPARE(out.str(),
"Trade::MeshData::attributeName(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attributeFormat(): index 2 out of range for 2 attributes\n"
@ -2653,7 +2693,8 @@ void MeshDataTest::attributeNotFound() {
"Trade::MeshData::bitangentsInto(): index 0 out of range for 0 bitangent attributes\n"
"Trade::MeshData::normalsInto(): index 0 out of range for 0 normal attributes\n"
"Trade::MeshData::textureCoordinates2DInto(): index 0 out of range for 0 texture coordinate attributes\n"
"Trade::MeshData::colorsInto(): index 2 out of range for 2 color attributes\n");
"Trade::MeshData::colorsInto(): index 2 out of range for 2 color attributes\n"
"Trade::MeshData::objectIdsInto(): index 0 out of range for 0 object ID attributes\n");
}
void MeshDataTest::attributeWrongType() {

Loading…
Cancel
Save