diff --git a/src/Magnum/Trade/SceneData.cpp b/src/Magnum/Trade/SceneData.cpp index 02efa08ce..03965be46 100644 --- a/src/Magnum/Trade/SceneData.cpp +++ b/src/Magnum/Trade/SceneData.cpp @@ -25,6 +25,7 @@ #include "SceneData.h" +#include #include #include "Magnum/Math/Matrix3.h" @@ -1146,68 +1147,63 @@ Containers::Array SceneData::unsignedIndexFieldAsArrayInternal(cons return out; } -Containers::Array SceneData::indexFieldAsArrayInternal(const UnsignedInt fieldId) const { - Containers::Array out{NoInit, std::size_t(_fields[fieldId]._size)}; - indexFieldIntoInternal(fieldId, 0, out); - return out; -} +void SceneData::meshesMaterialsIntoInternal(const UnsignedInt fieldId, const std::size_t offset, const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& meshMaterialDestination) const { + /* fieldId, offset, meshDestination.size() and + meshMaterialDestination.size() is assumed to be in bounds, checked by + the callers */ -void SceneData::meshesInto(const Containers::StridedArrayView1D& destination) const { - const UnsignedInt fieldId = fieldFor(SceneField::Mesh); - 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); -} + if(meshDestination) + unsignedIndexFieldIntoInternal(fieldId, offset, meshDestination); -std::size_t SceneData::meshesInto(const std::size_t offset, const Containers::StridedArrayView1D& destination) const { - const UnsignedInt fieldId = fieldFor(SceneField::Mesh); - CORRADE_ASSERT(fieldId != ~UnsignedInt{}, - "Trade::SceneData::meshesInto(): field not found", {}); - CORRADE_ASSERT(offset <= _fields[fieldId]._size, - "Trade::SceneData::meshesInto(): 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); - unsignedIndexFieldIntoInternal(fieldId, offset, destination.prefix(size)); - return size; + /* Copy also the material, if desired. If no such field is present, output + -1 for all meshes. */ + if(meshMaterialDestination) { + const UnsignedInt materialFieldId = fieldFor(SceneField::MeshMaterial); + if(materialFieldId == ~UnsignedInt{}) { + constexpr Int invalid[]{-1}; + Utility::copy(Containers::stridedArrayView(invalid).broadcasted<0>(meshMaterialDestination.size()), meshMaterialDestination); + } else indexFieldIntoInternal(materialFieldId, offset, meshMaterialDestination); + } } -Containers::Array SceneData::meshesAsArray() const { +void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& meshMaterialDestination) const { const UnsignedInt fieldId = fieldFor(SceneField::Mesh); CORRADE_ASSERT(fieldId != ~UnsignedInt{}, - /* Using the same message as in Into() to avoid too many redundant - strings in the binary */ - "Trade::SceneData::meshesInto(): field not found", {}); - return unsignedIndexFieldAsArrayInternal(fieldId); + "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", ); + CORRADE_ASSERT(!meshDestination || meshDestination.size() == _fields[fieldId]._size, + "Trade::SceneData::meshesMaterialsInto(): expected mesh destination view either empty or with" << _fields[fieldId]._size << "elements but got" << meshDestination.size(), ); + 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& destination) const { - const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial); - 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& destination) const { - const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial); +std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& meshMaterialDestination) const { + const UnsignedInt fieldId = fieldFor(SceneField::Mesh); CORRADE_ASSERT(fieldId != ~UnsignedInt{}, - "Trade::SceneData::meshMaterialsInto(): field not found", {}); + "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {}); CORRADE_ASSERT(offset <= _fields[fieldId]._size, - "Trade::SceneData::meshMaterialsInto(): 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); - indexFieldIntoInternal(fieldId, offset, destination.prefix(size)); + "Trade::SceneData::meshesMaterialsInto(): offset" << offset << "out of bounds for a field of size" << _fields[fieldId]._size, {}); + CORRADE_ASSERT(!meshDestination != !meshMaterialDestination || meshMaterialDestination.size() == meshDestination.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; } -Containers::Array SceneData::meshMaterialsAsArray() const { - const UnsignedInt fieldId = fieldFor(SceneField::MeshMaterial); +Containers::Array> SceneData::meshesMaterialsAsArray() const { + const UnsignedInt fieldId = fieldFor(SceneField::Mesh); CORRADE_ASSERT(fieldId != ~UnsignedInt{}, /* Using the same message as in Into() to avoid too many redundant strings in the binary */ - "Trade::SceneData::meshMaterialsInto(): field not found", {}); - return indexFieldAsArrayInternal(fieldId); + "Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {}); + Containers::Array> out{NoInit, std::size_t(_fields[fieldId]._size)}; + /** @todo use slicing once Pair exposes members somehow */ + const Containers::StridedArrayView1D meshesOut{out, reinterpret_cast(reinterpret_cast(out.data())), out.size(), sizeof(decltype(out)::Type)}; + const Containers::StridedArrayView1D meshMaterialsOut{out, reinterpret_cast(reinterpret_cast(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)}; + meshesMaterialsIntoInternal(fieldId, 0, meshesOut, meshMaterialsOut); + return out; } void SceneData::lightsInto(const Containers::StridedArrayView1D& destination) const { diff --git a/src/Magnum/Trade/SceneData.h b/src/Magnum/Trade/SceneData.h index 8e7b7b034..89bf35590 100644 --- a/src/Magnum/Trade/SceneData.h +++ b/src/Magnum/Trade/SceneData.h @@ -202,7 +202,7 @@ enum class SceneField: UnsignedInt { * required. If present, both should share the same object mapping view. * Objects with multiple meshes then have the Nth mesh associated with the * Nth material. - * @see @ref SceneData::meshesAsArray() + * @see @ref SceneData::meshesMaterialsAsArray() */ Mesh, @@ -213,7 +213,7 @@ enum class SceneField: UnsignedInt { * but can be also any of @relativeref{SceneFieldType,Byte} or * @relativeref{SceneFieldType,Short}. Expected to share the * object mapping view with @ref SceneField::Mesh. - * @see @ref SceneData::meshMaterialsAsArray() + * @see @ref SceneData::meshesMaterialsAsArray() */ MeshMaterial, @@ -1116,10 +1116,10 @@ class MAGNUM_TRADE_EXPORT SceneData { * use the overload below by using @cpp T[] @ce instead of @cpp T @ce. * You can also use the non-templated @ref parentsAsArray(), * @ref transformations2DAsArray(), @ref transformations3DAsArray(), - * @ref meshesAsArray(), @ref meshMaterialsAsArray(), - * @ref lightsAsArray(), @ref camerasAsArray(), @ref skinsAsArray() - * accessors to get common fields converted to usual types, but note - * that these operations involve extra allocation and data conversion. + * @ref meshesMaterialsAsArray(), @ref lightsAsArray(), + * @ref camerasAsArray(), @ref skinsAsArray() accessors to get common + * fields converted to usual types, but note that these operations + * involve extra allocation and data conversion. * @see @ref field(SceneField) const, @ref mutableField(UnsignedInt), * @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 * using @cpp T[] @ce instead of @cpp T @ce. You can also use the * non-templated @ref parentsAsArray(), @ref transformations2DAsArray(), - * @ref transformations3DAsArray(), @ref meshesAsArray(), - * @ref meshMaterialsAsArray(), @ref lightsAsArray(), - * @ref camerasAsArray(), @ref skinsAsArray() accessors to get common - * fields converted to usual types, but note that these operations - * involve extra allocation and data conversion. + * @ref transformations3DAsArray(), @ref meshesMaterialsAsArray(), + * @ref lightsAsArray(), @ref camerasAsArray(), @ref skinsAsArray() + * accessors to get common fields converted to usual types, but note + * that these operations involve extra allocation and data conversion. * @see @ref field(UnsignedInt) const, @ref mutableField(SceneField) */ template::value>::type> Containers::StridedArrayView1D field(SceneField name) const; @@ -1447,76 +1446,44 @@ class MAGNUM_TRADE_EXPORT SceneData { std::size_t transformations3DInto(std::size_t offset, const Containers::StridedArrayView1D& destination) const; /** - * @brief Mesh IDs as 32-bit integers + * @brief Mesh and material IDs as 32-bit integers * @m_since_latest * * Convenience alternative to @ref field(SceneField) const with - * @ref SceneField::Mesh 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 meshesInto(), @ref hasField() + * @ref SceneField::Mesh and @ref SceneField::MeshMaterial as the + * argument, as the two are required to share the same object mapping. + * Converts the fields from an arbitrary underlying type and returns it + * 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 meshesAsArray() const; + Containers::Array> 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 * - * Like @ref meshesAsArray(), but puts the result into @p destination - * instead of allocating a new array. Expects that @p destination is - * sized to contain exactly all data. + * Like @ref meshesMaterialsAsArray(), but puts the results into + * @p meshDestination and @p meshMaterialDestination instead of + * 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 */ - void meshesInto(const Containers::StridedArrayView1D& destination) const; + void meshesMaterialsInto(const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& 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 * - * Compared to @ref meshesInto(const Containers::StridedArrayView1D&) const + * Compared to @ref meshesMaterialsInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) 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 - */ - std::size_t meshesInto(std::size_t offset, const Containers::StridedArrayView1D& 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 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& 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&) 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. + * of the views, returning the count of items actually extracted. The + * @p offset is expected to not be larger than the field size, views + * that are not @cpp nullptr @ce are expected to have the same size. * @see @ref fieldSize(SceneField) const */ - std::size_t meshMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D& destination) const; + std::size_t meshesMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& meshMaterialsDestination) const; /** * @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& destination) const; MAGNUM_TRADE_LOCAL void indexFieldIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D& destination) const; MAGNUM_TRADE_LOCAL Containers::Array unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const; - MAGNUM_TRADE_LOCAL Containers::Array indexFieldAsArrayInternal(const UnsignedInt fieldId) const; + MAGNUM_TRADE_LOCAL void meshesMaterialsIntoInternal(UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D& meshDestination, const Containers::StridedArrayView1D& meshMaterialDestination) const; DataFlags _dataFlags; SceneObjectType _objectType; diff --git a/src/Magnum/Trade/Test/SceneDataTest.cpp b/src/Magnum/Trade/Test/SceneDataTest.cpp index fce55fd68..3f3f16d47 100644 --- a/src/Magnum/Trade/Test/SceneDataTest.cpp +++ b/src/Magnum/Trade/Test/SceneDataTest.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -124,12 +125,9 @@ struct SceneDataTest: TestSuite::Tester { void transformations3DIntoArray(); void transformations3DIntoArrayTRS(); void transformations3DIntoArrayInvalidSizeOrOffset(); - template void meshesAsArray(); - void meshesIntoArray(); - void meshesIntoArrayInvalidSizeOrOffset(); - template void meshMaterialsAsArray(); - void meshMaterialsIntoArray(); - void meshMaterialsIntoArrayInvalidSizeOrOffset(); + template void meshesMaterialsAsArray(); + void meshesMaterialsIntoArray(); + void meshesMaterialsIntoArrayInvalidSizeOrOffset(); template void lightsAsArray(); void lightsIntoArray(); void lightsIntoArrayInvalidSizeOrOffset(); @@ -295,22 +293,14 @@ SceneDataTest::SceneDataTest() { Containers::arraySize(IntoArrayOffsetData)); addTests({&SceneDataTest::transformations3DIntoArrayInvalidSizeOrOffset, - &SceneDataTest::meshesAsArray, - &SceneDataTest::meshesAsArray, - &SceneDataTest::meshesAsArray}); + &SceneDataTest::meshesMaterialsAsArray, + &SceneDataTest::meshesMaterialsAsArray, + &SceneDataTest::meshesMaterialsAsArray}); - addInstancedTests({&SceneDataTest::meshesIntoArray}, + addInstancedTests({&SceneDataTest::meshesMaterialsIntoArray}, Containers::arraySize(IntoArrayOffsetData)); - addTests({&SceneDataTest::meshesIntoArrayInvalidSizeOrOffset, - &SceneDataTest::meshMaterialsAsArray, - &SceneDataTest::meshMaterialsAsArray, - &SceneDataTest::meshMaterialsAsArray}); - - addInstancedTests({&SceneDataTest::meshMaterialsIntoArray}, - Containers::arraySize(IntoArrayOffsetData)); - - addTests({&SceneDataTest::meshMaterialsIntoArrayInvalidSizeOrOffset, + addTests({&SceneDataTest::meshesMaterialsIntoArrayInvalidSizeOrOffset, &SceneDataTest::lightsAsArray, &SceneDataTest::lightsAsArray, &SceneDataTest::lightsAsArray}); @@ -2787,32 +2777,60 @@ void SceneDataTest::transformations3DIntoArrayInvalidSizeOrOffset() { "Trade::SceneData::transformations3DInto(): offset 4 out of bounds for a field of size 3\n"); } -template void SceneDataTest::meshesAsArray() { - setTestCaseTemplateName(NameTraits::name()); +template void SceneDataTest::meshesMaterialsAsArray() { + setTestCaseTemplateName({NameTraits::name(), NameTraits::name()}); struct Field { UnsignedByte object; T mesh; - } fields[3]{ - {0, T(15)}, - {1, T(37)}, - {15, T(44)} + U meshMaterial; + } fields[]{ + {0, T(15), U(3)}, + {1, T(37), U(-1)}, + {15, T(44), U(25)} }; Containers::StridedArrayView1D 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::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)} - }}; + SceneFieldData meshes{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(), - Containers::arrayView({15, 37, 44}), - TestSuite::Compare::Container); + /* Both meshes and materials */ + { + 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>({ + {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>({ + {15, -1}, + {37, -1}, + {44, -1} + })), TestSuite::Compare::Container); + } } -void SceneDataTest::meshesIntoArray() { +void SceneDataTest::meshesMaterialsIntoArray() { auto&& data = IntoArrayOffsetData[testCaseInstanceId()]; setTestCaseDescription(data.name); @@ -2823,10 +2841,11 @@ void SceneDataTest::meshesIntoArray() { struct Field { UnsignedInt object; UnsignedInt mesh; + Int meshMaterial; } fields[]{ - {1, 15}, - {0, 37}, - {4, 44} + {1, 15, 3}, + {0, 37, -1}, + {4, 44, 22} }; Containers::StridedArrayView1D view = fields; @@ -2837,148 +2856,112 @@ void SceneDataTest::meshesIntoArray() { SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)}, + SceneFieldData{SceneField::MeshMaterial, + view.slice(&Field::object), + view.slice(&Field::meshMaterial)}, }}; /* The offset-less overload should give back all data */ { - UnsignedInt out[3]; - scene.meshesInto(out); - CORRADE_COMPARE_AS(Containers::stridedArrayView(out), + UnsignedInt meshesOut[3]; + Int meshMaterialsOut[3]; + scene.meshesMaterialsInto(meshesOut, meshMaterialsOut); + CORRADE_COMPARE_AS(Containers::stridedArrayView(meshesOut), view.slice(&Field::mesh), 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 out{data.size}; - CORRADE_COMPARE(scene.meshesInto(data.offset, out), data.expectedSize); - CORRADE_COMPARE_AS(out.prefix(data.expectedSize), - view.slice(&Field::mesh) - .slice(data.offset, data.offset + data.expectedSize), + UnsignedInt meshesOut[3]; + scene.meshesMaterialsInto(meshesOut, nullptr); + CORRADE_COMPARE_AS(Containers::stridedArrayView(meshesOut), + view.slice(&Field::mesh), 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 view = fields; - - SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, { - SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)} - }}; - - std::ostringstream out; - 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 void SceneDataTest::meshMaterialsAsArray() { - setTestCaseTemplateName(NameTraits::name()); - - struct Field { - UnsignedByte object; - T meshMaterial; - } fields[]{ - {0, T(15)}, - {1, T(-1)}, - {15, T(44)} - }; - - Containers::StridedArrayView1D 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({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} - }; + /* Variant with just materials */ + } { + Int meshMaterialsOut[3]; + scene.meshesMaterialsInto(nullptr, meshMaterialsOut); + CORRADE_COMPARE_AS(Containers::stridedArrayView(meshMaterialsOut), + view.slice(&Field::meshMaterial), + TestSuite::Compare::Container); - Containers::StridedArrayView1D view = fields; + /* Variant with neither is stupid, but should work too */ + } { + scene.meshesMaterialsInto(nullptr, nullptr); - SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, { - /* To verify it isn't just picking the first ever field */ - SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr}, - SceneFieldData{SceneField::MeshMaterial, - view.slice(&Field::object), - view.slice(&Field::meshMaterial)}, - }}; + /* The offset variant should give back only a subset */ + } { + Containers::Array meshesOut{data.size}; + Containers::Array meshMaterialsOut{data.size}; + CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, meshesOut, meshMaterialsOut), data.expectedSize); + 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 */ - { - Int out[3]; - scene.meshMaterialsInto(out); - CORRADE_COMPARE_AS(Containers::stridedArrayView(out), - view.slice(&Field::meshMaterial), + /* Variant with just meshes */ + } { + Containers::Array meshesOut{data.size}; + CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, meshesOut, nullptr), data.expectedSize); + CORRADE_COMPARE_AS(meshesOut.prefix(data.expectedSize), + view.slice(&Field::mesh) + .slice(data.offset, data.offset + data.expectedSize), TestSuite::Compare::Container); - /* The offset variant only a subset */ + /* Variant with just materials */ } { - Containers::Array out{data.size}; - CORRADE_COMPARE(scene.meshMaterialsInto(data.offset, out), data.expectedSize); - CORRADE_COMPARE_AS(out.prefix(data.expectedSize), + Containers::Array meshMaterialsOut{data.size}; + CORRADE_COMPARE(scene.meshesMaterialsInto(data.offset, nullptr, meshMaterialsOut), data.expectedSize); + CORRADE_COMPARE_AS(meshMaterialsOut.prefix(data.expectedSize), view.slice(&Field::meshMaterial) .slice(data.offset, data.offset + data.expectedSize), 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 CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif struct Field { UnsignedInt object; - Int meshMaterial; + UnsignedInt mesh; } fields[3]{}; Containers::StridedArrayView1D view = 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; Error redirectError{&out}; - Int destination[2]; - scene.meshMaterialsInto(destination); - scene.meshMaterialsInto(4, destination); + UnsignedInt meshDestinationCorrect[3]; + UnsignedInt meshDestination[2]; + 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(), - "Trade::SceneData::meshMaterialsInto(): expected a view 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 destination view either empty or with 3 elements but got 2\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 void SceneDataTest::lightsAsArray() { @@ -3448,12 +3431,9 @@ void SceneDataTest::fieldNotFound() { scene.transformations3DAsArray(); scene.transformations3DInto(nullptr); scene.transformations3DInto(0, nullptr); - scene.meshesAsArray(); - scene.meshesInto(nullptr); - scene.meshesInto(0, nullptr); - scene.meshMaterialsAsArray(); - scene.meshMaterialsInto(nullptr); - scene.meshMaterialsInto(0, nullptr); + scene.meshesMaterialsAsArray(); + scene.meshesMaterialsInto(nullptr, nullptr); + scene.meshesMaterialsInto(0, nullptr, nullptr); scene.lightsAsArray(); scene.lightsInto(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::meshesInto(): field not found\n" - "Trade::SceneData::meshesInto(): field not found\n" - "Trade::SceneData::meshesInto(): field 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::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n" + "Trade::SceneData::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n" + "Trade::SceneData::meshesMaterialsInto(): field Trade::SceneField::Mesh not found\n" "Trade::SceneData::lightsInto(): field not found\n" "Trade::SceneData::lightsInto(): field not found\n" "Trade::SceneData::lightsInto(): field not found\n"