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; 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() { Containers::Array<char> MeshData::releaseIndexData() {
_indices = {_indices.data(), 0}; _indices = {_indices.data(), 0};
Containers::Array<char> out = std::move(_indexData); Containers::Array<char> out = std::move(_indexData);
@ -780,6 +805,7 @@ Debug& operator<<(Debug& debug, const MeshAttribute value) {
_c(Normal) _c(Normal)
_c(TextureCoordinates) _c(TextureCoordinates)
_c(Color) _c(Color)
_c(ObjectId)
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */

54
src/Magnum/Trade/MeshData.h

@ -136,6 +136,14 @@ enum class MeshAttribute: UnsignedShort {
*/ */
Color, 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 * This and all higher values are for importer-specific attributes. Can be
* of any type. See documentation of a particular importer for details. * 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(), The simplest usage is through the convenience functions @ref positions2DAsArray(),
@ref positions3DAsArray(), @ref tangentsAsArray(), @ref bitangentsAsArray(), @ref positions3DAsArray(), @ref tangentsAsArray(), @ref bitangentsAsArray(),
@ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray() @ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray(),
and @ref colorsAsArray(). Each of these takes an index (as there can be @ref colorsAsArray() and @ref objectIdsAsArray(). Each of these takes an index
multiple sets of texture coordinates, for example) and you're expected to check (as there can be multiple sets of texture coordinates, for example) and you're
for attribute presence first with either @ref hasAttribute() or expected to check for attribute presence first with either @ref hasAttribute()
@ref attributeCount(MeshAttribute) const: or @ref attributeCount(MeshAttribute) const:
@snippet MagnumTrade.cpp MeshData-usage @snippet MagnumTrade.cpp MeshData-usage
@ -1326,10 +1334,10 @@ class MAGNUM_TRADE_EXPORT MeshData {
* @ref positions2DAsArray(), @ref positions3DAsArray(), * @ref positions2DAsArray(), @ref positions3DAsArray(),
* @ref tangentsAsArray(), @ref bitangentSignsAsArray(), * @ref tangentsAsArray(), @ref bitangentSignsAsArray(),
* @ref bitangentsAsArray(), @ref normalsAsArray(), * @ref bitangentsAsArray(), @ref normalsAsArray(),
* @ref textureCoordinates2DAsArray() and @ref colorsAsArray() * @ref textureCoordinates2DAsArray(), @ref colorsAsArray() and
* accessors to get common attributes converted to usual types, but * @ref objectIdsAsArray() accessors to get common attributes converted
* note that these operations involve extra allocation and data * to usual types, but note that these operations involve extra
* conversion. * allocation and data conversion.
* @see @ref attribute(MeshAttribute, UnsignedInt) const, * @see @ref attribute(MeshAttribute, UnsignedInt) const,
* @ref mutableAttribute(MeshAttribute, UnsignedInt), * @ref mutableAttribute(MeshAttribute, UnsignedInt),
* @ref isVertexFormatImplementationSpecific(), * @ref isVertexFormatImplementationSpecific(),
@ -1675,6 +1683,30 @@ class MAGNUM_TRADE_EXPORT MeshData {
*/ */
void colorsInto(Containers::StridedArrayView1D<Color4> destination, UnsignedInt id = 0) const; 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 * @brief Release index data storage
* *
@ -2014,6 +2046,10 @@ namespace Implementation {
format == VertexFormat::Vector2usNormalized || format == VertexFormat::Vector2usNormalized ||
format == VertexFormat::Vector2s || format == VertexFormat::Vector2s ||
format == VertexFormat::Vector2sNormalized)) || format == VertexFormat::Vector2sNormalized)) ||
(name == MeshAttribute::ObjectId &&
(format == VertexFormat::UnsignedInt ||
format == VertexFormat::UnsignedShort ||
format == VertexFormat::UnsignedByte)) ||
/* Custom attributes can be anything */ /* Custom attributes can be anything */
isMeshAttributeCustom(name); 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 colorsAsArray();
template<class T> void colorsAsArrayPackedUnsignedNormalized(); template<class T> void colorsAsArrayPackedUnsignedNormalized();
void colorsIntoArrayInvalidSize(); void colorsIntoArrayInvalidSize();
template<class T> void objectIdsAsArray();
void objectIdsIntoArrayInvalidSize();
void implementationSpecificVertexFormat(); void implementationSpecificVertexFormat();
void implementationSpecificVertexFormatWrongAccess(); void implementationSpecificVertexFormatWrongAccess();
@ -353,6 +355,10 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4ub>, &MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4ub>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4us>, &MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4us>,
&MeshDataTest::colorsIntoArrayInvalidSize, &MeshDataTest::colorsIntoArrayInvalidSize,
&MeshDataTest::objectIdsAsArray<UnsignedByte>,
&MeshDataTest::objectIdsAsArray<UnsignedShort>,
&MeshDataTest::objectIdsAsArray<UnsignedInt>,
&MeshDataTest::objectIdsIntoArrayInvalidSize,
&MeshDataTest::implementationSpecificVertexFormat, &MeshDataTest::implementationSpecificVertexFormat,
&MeshDataTest::implementationSpecificVertexFormatWrongAccess, &MeshDataTest::implementationSpecificVertexFormatWrongAccess,
@ -2308,6 +2314,35 @@ void MeshDataTest::colorsIntoArrayInvalidSize() {
"Trade::MeshData::colorsInto(): expected a view with 3 elements but got 2\n"); "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 /* MSVC 2015 doesn't like anonymous bitfields in inline structs, so putting the
declaration outside */ declaration outside */
struct VertexWithImplementationSpecificData { struct VertexWithImplementationSpecificData {
@ -2375,6 +2410,8 @@ void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
MeshAttributeData{MeshAttribute::TextureCoordinates, MeshAttributeData{MeshAttribute::TextureCoordinates,
vertexFormatWrap(0xdead3), attribute}, vertexFormatWrap(0xdead3), attribute},
MeshAttributeData{MeshAttribute::Color, MeshAttributeData{MeshAttribute::Color,
vertexFormatWrap(0xdead4), attribute},
MeshAttributeData{MeshAttribute::ObjectId,
vertexFormatWrap(0xdead4), attribute}}}; vertexFormatWrap(0xdead4), attribute}}};
std::ostringstream out; std::ostringstream out;
@ -2395,6 +2432,7 @@ void MeshDataTest::implementationSpecificVertexFormatWrongAccess() {
data.normalsAsArray(); data.normalsAsArray();
data.textureCoordinates2DAsArray(); data.textureCoordinates2DAsArray();
data.colorsAsArray(); data.colorsAsArray();
data.objectIdsAsArray();
CORRADE_COMPARE(out.str(), 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 0xdead1\n"
"Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 0xdead2\n" "Trade::MeshData::attribute(): can't cast data from an implementation-specific vertex format 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::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::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::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() { void MeshDataTest::implementationSpecificVertexFormatNotContained() {
@ -2624,6 +2663,7 @@ void MeshDataTest::attributeNotFound() {
data.normalsAsArray(); data.normalsAsArray();
data.textureCoordinates2DAsArray(); data.textureCoordinates2DAsArray();
data.colorsAsArray(2); data.colorsAsArray(2);
data.objectIdsAsArray();
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::MeshData::attributeName(): index 2 out of range for 2 attributes\n" "Trade::MeshData::attributeName(): index 2 out of range for 2 attributes\n"
"Trade::MeshData::attributeFormat(): 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::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::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::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() { void MeshDataTest::attributeWrongType() {

Loading…
Cancel
Save