Browse Source

Trade: combine mesh and material SceneData convenience APIs together.

In most cases the user would want to fetch both anyway, and since
they're forced to share the same object mapping this is easy to do.
pull/525/head
Vladimír Vondruš 5 years ago
parent
commit
7192517e6a
  1. 88
      src/Magnum/Trade/SceneData.cpp
  2. 97
      src/Magnum/Trade/SceneData.h
  3. 283
      src/Magnum/Trade/Test/SceneDataTest.cpp

88
src/Magnum/Trade/SceneData.cpp

@ -25,6 +25,7 @@
#include "SceneData.h" #include "SceneData.h"
#include <Corrade/Containers/Pair.h>
#include <Corrade/Utility/Algorithms.h> #include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix3.h"
@ -1146,68 +1147,63 @@ Containers::Array<UnsignedInt> SceneData::unsignedIndexFieldAsArrayInternal(cons
return out; return out;
} }
Containers::Array<Int> SceneData::indexFieldAsArrayInternal(const UnsignedInt fieldId) const { void SceneData::meshesMaterialsIntoInternal(const UnsignedInt fieldId, const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
Containers::Array<Int> out{NoInit, std::size_t(_fields[fieldId]._size)}; /* fieldId, offset, meshDestination.size() and
indexFieldIntoInternal(fieldId, 0, out); meshMaterialDestination.size() is assumed to be in bounds, checked by
return out; the callers */
}
void SceneData::meshesInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const { if(meshDestination)
const UnsignedInt fieldId = fieldFor(SceneField::Mesh); unsignedIndexFieldIntoInternal(fieldId, offset, meshDestination);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshesInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::meshesInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
unsignedIndexFieldIntoInternal(fieldId, 0, destination);
}
std::size_t SceneData::meshesInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const { /* Copy also the material, if desired. If no such field is present, output
const UnsignedInt fieldId = fieldFor(SceneField::Mesh); -1 for all meshes. */
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, if(meshMaterialDestination) {
"Trade::SceneData::meshesInto(): field not found", {}); const UnsignedInt materialFieldId = fieldFor(SceneField::MeshMaterial);
CORRADE_ASSERT(offset <= _fields[fieldId]._size, if(materialFieldId == ~UnsignedInt{}) {
"Trade::SceneData::meshesInto(): offset" << offset << "out of bounds for a field of size" << _fields[fieldId]._size, {}); constexpr Int invalid[]{-1};
const std::size_t size = Math::min(destination.size(), std::size_t(_fields[fieldId]._size) - offset); Utility::copy(Containers::stridedArrayView(invalid).broadcasted<0>(meshMaterialDestination.size()), meshMaterialDestination);
unsignedIndexFieldIntoInternal(fieldId, offset, destination.prefix(size)); } else indexFieldIntoInternal(materialFieldId, offset, meshMaterialDestination);
return size; }
} }
Containers::Array<UnsignedInt> SceneData::meshesAsArray() const { void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Mesh); const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", );
strings in the binary */ CORRADE_ASSERT(!meshDestination || meshDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::meshesInto(): field not found", {}); "Trade::SceneData::meshesMaterialsInto(): expected mesh destination view either empty or with" << _fields[fieldId]._size << "elements but got" << meshDestination.size(), );
return unsignedIndexFieldAsArrayInternal(fieldId); CORRADE_ASSERT(!meshMaterialDestination || meshMaterialDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::meshesMaterialsInto(): expected mesh material destination view either empty or with" << _fields[fieldId]._size << "elements but got" << meshMaterialDestination.size(), );
meshesMaterialsIntoInternal(fieldId, 0, meshDestination, meshMaterialDestination);
} }
void SceneData::meshMaterialsInto(const Containers::StridedArrayView1D<Int>& destination) const { std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial); const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshMaterialsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::meshMaterialsInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
indexFieldIntoInternal(fieldId, 0, destination);
}
std::size_t SceneData::meshMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshMaterialsInto(): field not found", {}); "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size, CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::meshMaterialsInto(): offset" << offset << "out of bounds for a field of size" << _fields[fieldId]._size, {}); "Trade::SceneData::meshesMaterialsInto(): offset" << offset << "out of bounds for a field of size" << _fields[fieldId]._size, {});
const std::size_t size = Math::min(destination.size(), std::size_t(_fields[fieldId]._size) - offset); CORRADE_ASSERT(!meshDestination != !meshMaterialDestination || meshMaterialDestination.size() == meshDestination.size(),
indexFieldIntoInternal(fieldId, offset, destination.prefix(size)); "Trade::SceneData::meshesMaterialsInto(): mesh and mesh material destination views have different size," << meshDestination.size() << "vs" << meshMaterialDestination.size(), {});
const std::size_t size = Math::min(Math::max(meshDestination.size(), meshMaterialDestination.size()), std::size_t(_fields[fieldId]._size) - offset);
meshesMaterialsIntoInternal(fieldId, offset,
meshDestination ? meshDestination.prefix(size) : nullptr,
meshMaterialDestination ? meshMaterialDestination.prefix(size) : nullptr);
return size; return size;
} }
Containers::Array<Int> SceneData::meshMaterialsAsArray() const { Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::meshesMaterialsAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial); const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant /* Using the same message as in Into() to avoid too many redundant
strings in the binary */ strings in the binary */
"Trade::SceneData::meshMaterialsInto(): field not found", {}); "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {});
return indexFieldAsArrayInternal(fieldId); Containers::Array<Containers::Pair<UnsignedInt, Int>> out{NoInit, std::size_t(_fields[fieldId]._size)};
/** @todo use slicing once Pair exposes members somehow */
const Containers::StridedArrayView1D<UnsignedInt> meshesOut{out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Int> meshMaterialsOut{out, reinterpret_cast<Int*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)};
meshesMaterialsIntoInternal(fieldId, 0, meshesOut, meshMaterialsOut);
return out;
} }
void SceneData::lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const { void SceneData::lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {

97
src/Magnum/Trade/SceneData.h

@ -202,7 +202,7 @@ enum class SceneField: UnsignedInt {
* required. If present, both should share the same object mapping view. * required. If present, both should share the same object mapping view.
* Objects with multiple meshes then have the Nth mesh associated with the * Objects with multiple meshes then have the Nth mesh associated with the
* Nth material. * Nth material.
* @see @ref SceneData::meshesAsArray() * @see @ref SceneData::meshesMaterialsAsArray()
*/ */
Mesh, Mesh,
@ -213,7 +213,7 @@ enum class SceneField: UnsignedInt {
* but can be also any of @relativeref{SceneFieldType,Byte} or * but can be also any of @relativeref{SceneFieldType,Byte} or
* @relativeref{SceneFieldType,Short}. Expected to share the * @relativeref{SceneFieldType,Short}. Expected to share the
* object mapping view with @ref SceneField::Mesh. * object mapping view with @ref SceneField::Mesh.
* @see @ref SceneData::meshMaterialsAsArray() * @see @ref SceneData::meshesMaterialsAsArray()
*/ */
MeshMaterial, MeshMaterial,
@ -1116,10 +1116,10 @@ class MAGNUM_TRADE_EXPORT SceneData {
* use the overload below by using @cpp T[] @ce instead of @cpp T @ce. * use the overload below by using @cpp T[] @ce instead of @cpp T @ce.
* You can also use the non-templated @ref parentsAsArray(), * You can also use the non-templated @ref parentsAsArray(),
* @ref transformations2DAsArray(), @ref transformations3DAsArray(), * @ref transformations2DAsArray(), @ref transformations3DAsArray(),
* @ref meshesAsArray(), @ref meshMaterialsAsArray(), * @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref lightsAsArray(), @ref camerasAsArray(), @ref skinsAsArray() * @ref camerasAsArray(), @ref skinsAsArray() accessors to get common
* accessors to get common fields converted to usual types, but note * fields converted to usual types, but note that these operations
* that these operations involve extra allocation and data conversion. * involve extra allocation and data conversion.
* @see @ref field(SceneField) const, @ref mutableField(UnsignedInt), * @see @ref field(SceneField) const, @ref mutableField(UnsignedInt),
* @ref fieldArraySize() * @ref fieldArraySize()
*/ */
@ -1193,11 +1193,10 @@ class MAGNUM_TRADE_EXPORT SceneData {
* not be an array, in that case you need to use the overload below by * not be an array, in that case you need to use the overload below by
* using @cpp T[] @ce instead of @cpp T @ce. You can also use the * using @cpp T[] @ce instead of @cpp T @ce. You can also use the
* non-templated @ref parentsAsArray(), @ref transformations2DAsArray(), * non-templated @ref parentsAsArray(), @ref transformations2DAsArray(),
* @ref transformations3DAsArray(), @ref meshesAsArray(), * @ref transformations3DAsArray(), @ref meshesMaterialsAsArray(),
* @ref meshMaterialsAsArray(), @ref lightsAsArray(), * @ref lightsAsArray(), @ref camerasAsArray(), @ref skinsAsArray()
* @ref camerasAsArray(), @ref skinsAsArray() accessors to get common * accessors to get common fields converted to usual types, but note
* fields converted to usual types, but note that these operations * that these operations involve extra allocation and data conversion.
* involve extra allocation and data conversion.
* @see @ref field(UnsignedInt) const, @ref mutableField(SceneField) * @see @ref field(UnsignedInt) const, @ref mutableField(SceneField)
*/ */
template<class T, class = typename std::enable_if<!std::is_array<T>::value>::type> Containers::StridedArrayView1D<const T> field(SceneField name) const; template<class T, class = typename std::enable_if<!std::is_array<T>::value>::type> Containers::StridedArrayView1D<const T> field(SceneField name) const;
@ -1447,76 +1446,44 @@ class MAGNUM_TRADE_EXPORT SceneData {
std::size_t transformations3DInto(std::size_t offset, const Containers::StridedArrayView1D<Matrix4>& destination) const; std::size_t transformations3DInto(std::size_t offset, const Containers::StridedArrayView1D<Matrix4>& destination) const;
/** /**
* @brief Mesh IDs as 32-bit integers * @brief Mesh and material IDs as 32-bit integers
* @m_since_latest * @m_since_latest
* *
* Convenience alternative to @ref field(SceneField) const with * Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Mesh as the argument that converts the field from * @ref SceneField::Mesh and @ref SceneField::MeshMaterial as the
* an arbitrary underlying type and returns it in a newly-allocated * argument, as the two are required to share the same object mapping.
* array. The field is expected to exist. * Converts the fields from an arbitrary underlying type and returns it
* @see @ref meshesInto(), @ref hasField() * in a newly-allocated array. The @ref SceneField::Mesh field is
* expected to exist, if @ref SceneField::MeshMaterial isn't present,
* the second returned values are all @cpp -1 @ce.
* @see @ref meshesMaterialsInto(), @ref hasField()
*/ */
Containers::Array<UnsignedInt> meshesAsArray() const; Containers::Array<Containers::Pair<UnsignedInt, Int>> meshesMaterialsAsArray() const;
/** /**
* @brief Mesh IDs as 32-bit integers into a pre-allocated view * @brief Mesh and material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest * @m_since_latest
* *
* Like @ref meshesAsArray(), but puts the result into @p destination * Like @ref meshesMaterialsAsArray(), but puts the results into
* instead of allocating a new array. Expects that @p destination is * @p meshDestination and @p meshMaterialDestination instead of
* sized to contain exactly all data. * allocating a new array. Expects that each view is either
* @cpp nullptr @ce or sized to contain exactly all data.
* @see @ref fieldSize(SceneField) const * @see @ref fieldSize(SceneField) const
*/ */
void meshesInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const; void meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const;
/** /**
* @brief A subrange of mesh IDs as 32-bit integers into a pre-allocated view * @brief A subrange of mesh and material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest * @m_since_latest
* *
* Compared to @ref meshesInto(const Containers::StridedArrayView1D<UnsignedInt>&) const * Compared to @ref meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Int>&) const
* extracts only a subrange of the field defined by @p offset and size * extracts only a subrange of the field defined by @p offset and size
* of the @p destination view, returning the count of items actually * of the views, returning the count of items actually extracted. The
* extracted. The @p offset is expected to not be larger than the field * @p offset is expected to not be larger than the field size, views
* size. * that are not @cpp nullptr @ce are expected to have the same size.
* @see @ref fieldSize(SceneField) const
*/
std::size_t meshesInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
/**
* @brief Mesh material IDs as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::MeshMaterial as the argument that converts the
* field from an arbitrary underlying type and returns it in a
* newly-allocated array. The field is expected to exist.
* @see @ref meshMaterialsInto(), @ref hasField()
*/
Containers::Array<Int> meshMaterialsAsArray() const;
/**
* @brief Mesh material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Like @ref meshMaterialsAsArray(), 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 fieldSize(SceneField) const
*/
void meshMaterialsInto(const Containers::StridedArrayView1D<Int>& destination) const;
/**
* @brief A subrange of mesh material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref meshMaterialsInto(const Containers::StridedArrayView1D<Int>&) const
* extracts only a subrange of the field defined by @p offset and size
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const * @see @ref fieldSize(SceneField) const
*/ */
std::size_t meshMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const; std::size_t meshesMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialsDestination) const;
/** /**
* @brief Light IDs as 32-bit integers * @brief Light IDs as 32-bit integers
@ -1692,7 +1659,7 @@ class MAGNUM_TRADE_EXPORT SceneData {
MAGNUM_TRADE_LOCAL void unsignedIndexFieldIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const; MAGNUM_TRADE_LOCAL void unsignedIndexFieldIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
MAGNUM_TRADE_LOCAL void indexFieldIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const; MAGNUM_TRADE_LOCAL void indexFieldIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const;
MAGNUM_TRADE_LOCAL Containers::Array<UnsignedInt> unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const; MAGNUM_TRADE_LOCAL Containers::Array<UnsignedInt> unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const;
MAGNUM_TRADE_LOCAL Containers::Array<Int> indexFieldAsArrayInternal(const UnsignedInt fieldId) const; MAGNUM_TRADE_LOCAL void meshesMaterialsIntoInternal(UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const;
DataFlags _dataFlags; DataFlags _dataFlags;
SceneObjectType _objectType; SceneObjectType _objectType;

283
src/Magnum/Trade/Test/SceneDataTest.cpp

@ -25,6 +25,7 @@
#include <sstream> #include <sstream>
#include <Corrade/Containers/ArrayTuple.h> #include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h> #include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -124,12 +125,9 @@ struct SceneDataTest: TestSuite::Tester {
void transformations3DIntoArray(); void transformations3DIntoArray();
void transformations3DIntoArrayTRS(); void transformations3DIntoArrayTRS();
void transformations3DIntoArrayInvalidSizeOrOffset(); void transformations3DIntoArrayInvalidSizeOrOffset();
template<class T> void meshesAsArray(); template<class T, class U> void meshesMaterialsAsArray();
void meshesIntoArray(); void meshesMaterialsIntoArray();
void meshesIntoArrayInvalidSizeOrOffset(); void meshesMaterialsIntoArrayInvalidSizeOrOffset();
template<class T> void meshMaterialsAsArray();
void meshMaterialsIntoArray();
void meshMaterialsIntoArrayInvalidSizeOrOffset();
template<class T> void lightsAsArray(); template<class T> void lightsAsArray();
void lightsIntoArray(); void lightsIntoArray();
void lightsIntoArrayInvalidSizeOrOffset(); void lightsIntoArrayInvalidSizeOrOffset();
@ -295,22 +293,14 @@ SceneDataTest::SceneDataTest() {
Containers::arraySize(IntoArrayOffsetData)); Containers::arraySize(IntoArrayOffsetData));
addTests({&SceneDataTest::transformations3DIntoArrayInvalidSizeOrOffset, addTests({&SceneDataTest::transformations3DIntoArrayInvalidSizeOrOffset,
&SceneDataTest::meshesAsArray<UnsignedByte>, &SceneDataTest::meshesMaterialsAsArray<UnsignedByte, Int>,
&SceneDataTest::meshesAsArray<UnsignedShort>, &SceneDataTest::meshesMaterialsAsArray<UnsignedShort, Byte>,
&SceneDataTest::meshesAsArray<UnsignedInt>}); &SceneDataTest::meshesMaterialsAsArray<UnsignedInt, Short>});
addInstancedTests({&SceneDataTest::meshesIntoArray}, addInstancedTests({&SceneDataTest::meshesMaterialsIntoArray},
Containers::arraySize(IntoArrayOffsetData)); Containers::arraySize(IntoArrayOffsetData));
addTests({&SceneDataTest::meshesIntoArrayInvalidSizeOrOffset, addTests({&SceneDataTest::meshesMaterialsIntoArrayInvalidSizeOrOffset,
&SceneDataTest::meshMaterialsAsArray<Byte>,
&SceneDataTest::meshMaterialsAsArray<Short>,
&SceneDataTest::meshMaterialsAsArray<Int>});
addInstancedTests({&SceneDataTest::meshMaterialsIntoArray},
Containers::arraySize(IntoArrayOffsetData));
addTests({&SceneDataTest::meshMaterialsIntoArrayInvalidSizeOrOffset,
&SceneDataTest::lightsAsArray<UnsignedByte>, &SceneDataTest::lightsAsArray<UnsignedByte>,
&SceneDataTest::lightsAsArray<UnsignedShort>, &SceneDataTest::lightsAsArray<UnsignedShort>,
&SceneDataTest::lightsAsArray<UnsignedInt>}); &SceneDataTest::lightsAsArray<UnsignedInt>});
@ -2787,32 +2777,60 @@ void SceneDataTest::transformations3DIntoArrayInvalidSizeOrOffset() {
"Trade::SceneData::transformations3DInto(): offset 4 out of bounds for a field of size 3\n"); "Trade::SceneData::transformations3DInto(): offset 4 out of bounds for a field of size 3\n");
} }
template<class T> void SceneDataTest::meshesAsArray() { template<class T, class U> void SceneDataTest::meshesMaterialsAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName({NameTraits<T>::name(), NameTraits<U>::name()});
struct Field { struct Field {
UnsignedByte object; UnsignedByte object;
T mesh; T mesh;
} fields[3]{ U meshMaterial;
{0, T(15)}, } fields[]{
{1, T(37)}, {0, T(15), U(3)},
{15, T(44)} {1, T(37), U(-1)},
{15, T(44), U(25)}
}; };
Containers::StridedArrayView1D<Field> view = fields; Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedByte, 50, {}, fields, { SceneFieldData meshes{SceneField::Mesh,
/* To verify it isn't just picking the first ever field */ view.slice(&Field::object),
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Int, nullptr}, view.slice(&Field::mesh)};
SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)} SceneFieldData meshMaterials{SceneField::MeshMaterial,
}}; view.slice(&Field::object),
view.slice(&Field::meshMaterial)};
CORRADE_COMPARE_AS(scene.meshesAsArray(), /* Both meshes and materials */
Containers::arrayView<UnsignedInt>({15, 37, 44}), {
TestSuite::Compare::Container); SceneData scene{SceneObjectType::UnsignedByte, 50, {}, fields, {
/* To verify it isn't just picking the first ever field */
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Int, nullptr},
meshes,
meshMaterials
}};
CORRADE_COMPARE_AS(scene.meshesMaterialsAsArray(),
(Containers::arrayView<Containers::Pair<UnsignedInt, Int>>({
{15, 3},
{37, -1},
{44, 25}
})), TestSuite::Compare::Container);
/* Only meshes */
} {
SceneData scene{SceneObjectType::UnsignedByte, 50, {}, fields, {
meshes
}};
CORRADE_COMPARE_AS(scene.meshesMaterialsAsArray(),
(Containers::arrayView<Containers::Pair<UnsignedInt, Int>>({
{15, -1},
{37, -1},
{44, -1}
})), TestSuite::Compare::Container);
}
} }
void SceneDataTest::meshesIntoArray() { void SceneDataTest::meshesMaterialsIntoArray() {
auto&& data = IntoArrayOffsetData[testCaseInstanceId()]; auto&& data = IntoArrayOffsetData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -2823,10 +2841,11 @@ void SceneDataTest::meshesIntoArray() {
struct Field { struct Field {
UnsignedInt object; UnsignedInt object;
UnsignedInt mesh; UnsignedInt mesh;
Int meshMaterial;
} fields[]{ } fields[]{
{1, 15}, {1, 15, 3},
{0, 37}, {0, 37, -1},
{4, 44} {4, 44, 22}
}; };
Containers::StridedArrayView1D<Field> view = fields; Containers::StridedArrayView1D<Field> view = fields;
@ -2837,148 +2856,112 @@ void SceneDataTest::meshesIntoArray() {
SceneFieldData{SceneField::Mesh, SceneFieldData{SceneField::Mesh,
view.slice(&Field::object), view.slice(&Field::object),
view.slice(&Field::mesh)}, view.slice(&Field::mesh)},
SceneFieldData{SceneField::MeshMaterial,
view.slice(&Field::object),
view.slice(&Field::meshMaterial)},
}}; }};
/* The offset-less overload should give back all data */ /* The offset-less overload should give back all data */
{ {
UnsignedInt out[3]; UnsignedInt meshesOut[3];
scene.meshesInto(out); Int meshMaterialsOut[3];
CORRADE_COMPARE_AS(Containers::stridedArrayView(out), scene.meshesMaterialsInto(meshesOut, meshMaterialsOut);
CORRADE_COMPARE_AS(Containers::stridedArrayView(meshesOut),
view.slice(&Field::mesh), view.slice(&Field::mesh),
TestSuite::Compare::Container); TestSuite::Compare::Container);
CORRADE_COMPARE_AS(Containers::stridedArrayView(meshMaterialsOut),
view.slice(&Field::meshMaterial),
TestSuite::Compare::Container);
/* The offset variant only a subset */ /* Variant with just meshes */
} { } {
Containers::Array<UnsignedInt> out{data.size}; UnsignedInt meshesOut[3];
CORRADE_COMPARE(scene.meshesInto(data.offset, out), data.expectedSize); scene.meshesMaterialsInto(meshesOut, nullptr);
CORRADE_COMPARE_AS(out.prefix(data.expectedSize), CORRADE_COMPARE_AS(Containers::stridedArrayView(meshesOut),
view.slice(&Field::mesh) view.slice(&Field::mesh),
.slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container); TestSuite::Compare::Container);
}
}
void SceneDataTest::meshesIntoArrayInvalidSizeOrOffset() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct Field {
UnsignedInt object;
UnsignedInt mesh;
} fields[3]{};
Containers::StridedArrayView1D<Field> view = fields; /* Variant with just materials */
} {
SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, { Int meshMaterialsOut[3];
SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)} scene.meshesMaterialsInto(nullptr, meshMaterialsOut);
}}; CORRADE_COMPARE_AS(Containers::stridedArrayView(meshMaterialsOut),
view.slice(&Field::meshMaterial),
std::ostringstream out; TestSuite::Compare::Container);
Error redirectError{&out};
UnsignedInt destination[2];
scene.meshesInto(destination);
scene.meshesInto(4, destination);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::meshesInto(): expected a view with 3 elements but got 2\n"
"Trade::SceneData::meshesInto(): offset 4 out of bounds for a field of size 3\n");
}
template<class T> void SceneDataTest::meshMaterialsAsArray() {
setTestCaseTemplateName(NameTraits<T>::name());
struct Field {
UnsignedByte object;
T meshMaterial;
} fields[]{
{0, T(15)},
{1, T(-1)},
{15, T(44)}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedByte, 50, {}, fields, {
/* To verify it isn't just picking the first ever field */
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::MeshMaterial, view.slice(&Field::object), view.slice(&Field::meshMaterial)}
}};
CORRADE_COMPARE_AS(scene.meshMaterialsAsArray(),
Containers::arrayView<Int>({15, -1, 44}),
TestSuite::Compare::Container);
}
void SceneDataTest::meshMaterialsIntoArray() {
auto&& data = IntoArrayOffsetData[testCaseInstanceId()];
setTestCaseDescription(data.name);
/* Both AsArray() and Into() share a common helper. The AsArray() test
above verified handling of various data types and this checks the
offset/size parameters of the Into() variant. */
struct Field {
UnsignedInt object;
Int meshMaterial;
} fields[]{
{1, 15},
{0, -1},
{4, 44}
};
Containers::StridedArrayView1D<Field> view = fields; /* Variant with neither is stupid, but should work too */
} {
scene.meshesMaterialsInto(nullptr, nullptr);
SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, { /* The offset variant should give back only a subset */
/* To verify it isn't just picking the first ever field */ } {
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr}, Containers::Array<UnsignedInt> meshesOut{data.size};
SceneFieldData{SceneField::MeshMaterial, Containers::Array<Int> meshMaterialsOut{data.size};
view.slice(&Field::object), CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, meshesOut, meshMaterialsOut), data.expectedSize);
view.slice(&Field::meshMaterial)}, CORRADE_COMPARE_AS(meshesOut.prefix(data.expectedSize),
}}; view.slice(&Field::mesh)
.slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(meshMaterialsOut.prefix(data.expectedSize),
view.slice(&Field::meshMaterial)
.slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container);
/* The offset-less overload should give back all data */ /* Variant with just meshes */
{ } {
Int out[3]; Containers::Array<UnsignedInt> meshesOut{data.size};
scene.meshMaterialsInto(out); CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, meshesOut, nullptr), data.expectedSize);
CORRADE_COMPARE_AS(Containers::stridedArrayView(out), CORRADE_COMPARE_AS(meshesOut.prefix(data.expectedSize),
view.slice(&Field::meshMaterial), view.slice(&Field::mesh)
.slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container); TestSuite::Compare::Container);
/* The offset variant only a subset */ /* Variant with just materials */
} { } {
Containers::Array<Int> out{data.size}; Containers::Array<Int> meshMaterialsOut{data.size};
CORRADE_COMPARE(scene.meshMaterialsInto(data.offset, out), data.expectedSize); CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, nullptr, meshMaterialsOut), data.expectedSize);
CORRADE_COMPARE_AS(out.prefix(data.expectedSize), CORRADE_COMPARE_AS(meshMaterialsOut.prefix(data.expectedSize),
view.slice(&Field::meshMaterial) view.slice(&Field::meshMaterial)
.slice(data.offset, data.offset + data.expectedSize), .slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container); TestSuite::Compare::Container);
/* Variant with neither is stupid, but should work too */
} {
CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, nullptr, nullptr), 0);
} }
} }
void SceneDataTest::meshMaterialsIntoArrayInvalidSizeOrOffset() { void SceneDataTest::meshesMaterialsIntoArrayInvalidSizeOrOffset() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct Field { struct Field {
UnsignedInt object; UnsignedInt object;
Int meshMaterial; UnsignedInt mesh;
} fields[3]{}; } fields[3]{};
Containers::StridedArrayView1D<Field> view = fields; Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, { SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, {
SceneFieldData{SceneField::MeshMaterial, view.slice(&Field::object), view.slice(&Field::meshMaterial)} SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)}
}}; }};
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
Int destination[2]; UnsignedInt meshDestinationCorrect[3];
scene.meshMaterialsInto(destination); UnsignedInt meshDestination[2];
scene.meshMaterialsInto(4, destination); Int meshMaterialDestinationCorrect[3];
Int meshMaterialDestination[2];
scene.meshesMaterialsInto(meshDestination, meshMaterialDestinationCorrect);
scene.meshesMaterialsInto(meshDestinationCorrect, meshMaterialDestination);
scene.meshesMaterialsInto(4, meshDestination, meshMaterialDestination);
scene.meshesMaterialsInto(0, meshDestinationCorrect, meshMaterialDestination);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::SceneData::meshMaterialsInto(): expected a view with 3 elements but got 2\n" "Trade::SceneData::meshesMaterialsInto(): expected mesh destination view either empty or with 3 elements but got 2\n"
"Trade::SceneData::meshMaterialsInto(): offset 4 out of bounds for a field of size 3\n"); "Trade::SceneData::meshesMaterialsInto(): expected mesh material destination view either empty or with 3 elements but got 2\n"
"Trade::SceneData::meshesMaterialsInto(): offset 4 out of bounds for a field of size 3\n"
"Trade::SceneData::meshesMaterialsInto(): mesh and mesh material destination views have different size, 3 vs 2\n");
} }
template<class T> void SceneDataTest::lightsAsArray() { template<class T> void SceneDataTest::lightsAsArray() {
@ -3448,12 +3431,9 @@ void SceneDataTest::fieldNotFound() {
scene.transformations3DAsArray(); scene.transformations3DAsArray();
scene.transformations3DInto(nullptr); scene.transformations3DInto(nullptr);
scene.transformations3DInto(0, nullptr); scene.transformations3DInto(0, nullptr);
scene.meshesAsArray(); scene.meshesMaterialsAsArray();
scene.meshesInto(nullptr); scene.meshesMaterialsInto(nullptr, nullptr);
scene.meshesInto(0, nullptr); scene.meshesMaterialsInto(0, nullptr, nullptr);
scene.meshMaterialsAsArray();
scene.meshMaterialsInto(nullptr);
scene.meshMaterialsInto(0, nullptr);
scene.lightsAsArray(); scene.lightsAsArray();
scene.lightsInto(nullptr); scene.lightsInto(nullptr);
scene.lightsInto(0, nullptr); scene.lightsInto(0, nullptr);
@ -3499,12 +3479,9 @@ void SceneDataTest::fieldNotFound() {
"Trade::SceneData::transformations3DInto(): no transformation-related field found\n" "Trade::SceneData::transformations3DInto(): no transformation-related field found\n"
"Trade::SceneData::transformations3DInto(): no transformation-related field found\n" "Trade::SceneData::transformations3DInto(): no transformation-related field found\n"
"Trade::SceneData::transformations3DInto(): no transformation-related field found\n" "Trade::SceneData::transformations3DInto(): no transformation-related field found\n"
"Trade::SceneData::meshesInto(): field not found\n" "Trade::SceneData::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n"
"Trade::SceneData::meshesInto(): field not found\n" "Trade::SceneData::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n"
"Trade::SceneData::meshesInto(): field not found\n" "Trade::SceneData::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n"
"Trade::SceneData::meshMaterialsInto(): field not found\n"
"Trade::SceneData::meshMaterialsInto(): field not found\n"
"Trade::SceneData::meshMaterialsInto(): field not found\n"
"Trade::SceneData::lightsInto(): field not found\n" "Trade::SceneData::lightsInto(): field not found\n"
"Trade::SceneData::lightsInto(): field not found\n" "Trade::SceneData::lightsInto(): field not found\n"
"Trade::SceneData::lightsInto(): field not found\n" "Trade::SceneData::lightsInto(): field not found\n"

Loading…
Cancel
Save