Browse Source

Trade: SceneData::*AsArray() and *Into() now return object IDs as well.

Because that way one can query a field with *AsArray() and iterate
through it in a single expression. This also resolves the pending issue
where it was more than annoying to fetch object mapping for TRS fields
when only a subset of the fields is available.
pull/525/head
Vladimír Vondruš 5 years ago
parent
commit
efd3b9cadb
  1. 18
      src/Magnum/MeshTools/sceneconverter.cpp
  2. 3
      src/Magnum/Trade/Implementation/sceneTools.h
  3. 444
      src/Magnum/Trade/SceneData.cpp
  4. 422
      src/Magnum/Trade/SceneData.h
  5. 1396
      src/Magnum/Trade/Test/SceneDataTest.cpp
  6. 51
      src/Magnum/Trade/Test/SceneToolsTest.cpp

18
src/Magnum/MeshTools/sceneconverter.cpp

@ -417,22 +417,22 @@ used.)")
for(UnsignedInt j = 0; j != scene->fieldCount(); ++j) {
const Trade::SceneField name = scene->fieldName(j);
if(name == Trade::SceneField::Mesh) for(const Containers::Pair<UnsignedInt, Int>& meshMaterial: scene->meshesMaterialsAsArray()) {
if(name == Trade::SceneField::Mesh) for(const Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>& meshMaterial: scene->meshesMaterialsAsArray()) {
if(meshMaterial.first() < meshReferenceCount.size())
++meshReferenceCount[meshMaterial.first()];
if(UnsignedInt(meshMaterial.second()) < materialReferenceCount.size())
++materialReferenceCount[meshMaterial.second()];
if(UnsignedInt(meshMaterial.second().second()) < materialReferenceCount.size())
++materialReferenceCount[meshMaterial.second().second()];
}
if(name == Trade::SceneField::Skin) for(const UnsignedInt skin: scene->skinsAsArray()) {
if(skin < skinReferenceCount.size())
++skinReferenceCount[skin];
if(name == Trade::SceneField::Skin) for(const Containers::Pair<UnsignedInt, UnsignedInt> skin: scene->skinsAsArray()) {
if(skin.second() < skinReferenceCount.size())
++skinReferenceCount[skin.second()];
/** @todo 2D/3D distinction */
}
if(name == Trade::SceneField::Light) for(const UnsignedInt light: scene->lightsAsArray()) {
if(light < lightReferenceCount.size())
++lightReferenceCount[light];
if(name == Trade::SceneField::Light) for(const Containers::Pair<UnsignedInt, UnsignedInt>& light: scene->lightsAsArray()) {
if(light.second() < lightReferenceCount.size())
++lightReferenceCount[light.second()];
}
arrayAppend(info.fields, InPlaceInit,

3
src/Magnum/Trade/Implementation/sceneTools.h

@ -254,8 +254,7 @@ inline SceneData sceneConvertToSingleFunctionObjects(const SceneData& scene, Con
/* Copy existing parent object/field data to a prefix of the output */
const Containers::StridedArrayView1D<UnsignedInt> outParentObjects = out.mutableObjects<UnsignedInt>(parentFieldId);
const Containers::StridedArrayView1D<Int> outParents = out.mutableField<Int>(parentFieldId);
CORRADE_INTERNAL_ASSERT_OUTPUT(scene.objectsInto(parentFieldId, 0, outParentObjects) == scene.fieldSize(parentFieldId));
CORRADE_INTERNAL_ASSERT_OUTPUT(scene.parentsInto(0, outParents) == scene.fieldSize(parentFieldId));
CORRADE_INTERNAL_ASSERT_OUTPUT(scene.parentsInto(0, outParentObjects, outParents) == scene.fieldSize(parentFieldId));
/* List new objects at the end of the extended parent field */
const Containers::StridedArrayView1D<UnsignedInt> newParentObjects = outParentObjects.suffix(scene.fieldSize(parentFieldId));

444
src/Magnum/Trade/SceneData.cpp

@ -1162,34 +1162,43 @@ void SceneData::parentsIntoInternal(const UnsignedInt fieldId, const std::size_t
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
void SceneData::parentsInto(const Containers::StridedArrayView1D<Int>& destination) const {
void SceneData::parentsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Int>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::parentsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::parentsInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
parentsIntoInternal(fieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::parentsInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::parentsInto(): expected field destination view either empty or with" << _fields[fieldId]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldId, 0, objectDestination);
parentsIntoInternal(fieldId, 0, fieldDestination);
}
std::size_t SceneData::parentsInto(const std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const {
std::size_t SceneData::parentsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Int>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::parentsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::parentsInto(): 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);
parentsIntoInternal(fieldId, offset, destination.prefix(size));
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::parentsInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::parentsInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
if(fieldDestination) parentsIntoInternal(fieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<Int> SceneData::parentsAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::parentsAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::parentsInto(): field not found", {});
Containers::Array<Int> out{NoInit, std::size_t(_fields[fieldId]._size)};
parentsIntoInternal(fieldId, 0, out);
Containers::Array<Containers::Pair<UnsignedInt, Int>> out{NoInit, std::size_t(_fields[fieldId]._size)};
/** @todo use slicing once Pair exposes members somehow */
objectsIntoInternal(fieldId, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
parentsIntoInternal(fieldId, 0, {out, reinterpret_cast<Int*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)});
return out;
}
@ -1241,7 +1250,7 @@ template<class Source, class Destination> void applyScaling(const Containers::St
}
std::size_t SceneData::findTransformFields(UnsignedInt& transformationFieldId, UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId, UnsignedInt* const fieldWithObjectMappingDestination) const {
UnsignedInt SceneData::findTransformFields(UnsignedInt& transformationFieldId, UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId) const {
UnsignedInt fieldWithObjectMapping = ~UnsignedInt{};
transformationFieldId = ~UnsignedInt{};
translationFieldId = ~UnsignedInt{};
@ -1262,15 +1271,10 @@ std::size_t SceneData::findTransformFields(UnsignedInt& transformationFieldId, U
}
}
if(fieldWithObjectMappingDestination)
*fieldWithObjectMappingDestination = fieldWithObjectMapping;
/* Assuming the caller fires an appropriate assertion */
return fieldWithObjectMapping == ~UnsignedInt{} ?
~std::size_t{} : _fields[fieldWithObjectMapping]._size;
return fieldWithObjectMapping;
}
std::size_t SceneData::findTranslationRotationScalingFields(UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId, UnsignedInt* const fieldWithObjectMappingDestination) const {
UnsignedInt SceneData::findTranslationRotationScalingFields(UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId) const {
UnsignedInt fieldWithObjectMapping = ~UnsignedInt{};
translationFieldId = ~UnsignedInt{};
rotationFieldId = ~UnsignedInt{};
@ -1285,12 +1289,7 @@ std::size_t SceneData::findTranslationRotationScalingFields(UnsignedInt& transla
}
}
if(fieldWithObjectMappingDestination)
*fieldWithObjectMappingDestination = fieldWithObjectMapping;
/* Assuming the caller fires an appropriate assertion */
return fieldWithObjectMapping == ~UnsignedInt{} ?
~std::size_t{} : _fields[fieldWithObjectMapping]._size;
return fieldWithObjectMapping;
}
void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFieldId, const UnsignedInt translationFieldId, const UnsignedInt rotationFieldId, const UnsignedInt scalingFieldId, std::size_t offset, const Containers::StridedArrayView1D<Matrix3>& destination) const {
@ -1369,40 +1368,46 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
void SceneData::transformations2DInto(const Containers::StridedArrayView1D<Matrix3>& destination) const {
void SceneData::transformations2DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix3>& fieldDestination) const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
#ifndef CORRADE_NO_ASSERT
const std::size_t expectedSize =
#endif
findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::transformations2DInto(): no transformation-related field found", );
CORRADE_ASSERT(expectedSize == destination.size(),
"Trade::SceneData::transformations2DInto(): expected a view with" << expectedSize << "elements but got" << destination.size(), );
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::transformations2DInto(): expected object destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::transformations2DInto(): expected field destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldWithObjectMapping, 0, objectDestination);
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, fieldDestination);
}
std::size_t SceneData::transformations2DInto(const std::size_t offset, const Containers::StridedArrayView1D<Matrix3>& destination) const {
std::size_t SceneData::transformations2DInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix3>& fieldDestination) const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::transformations2DInto(): no transformation-related field found", {});
CORRADE_ASSERT(offset <= expectedSize,
"Trade::SceneData::transformations2DInto(): offset" << offset << "out of bounds for a field of size" << expectedSize, {});
const std::size_t size = Math::min(destination.size(), expectedSize - offset);
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, destination.prefix(size));
const std::size_t fieldSize = _fields[fieldWithObjectMapping]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::transformations2DInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::transformations2DInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldWithObjectMapping, offset, objectDestination.prefix(size));
if(fieldDestination) transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<Matrix3> SceneData::transformations2DAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Matrix3>> SceneData::transformations2DAsArray() const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::transformations2DInto(): no transformation-related field found", {});
Containers::Array<Matrix3> out{NoInit, expectedSize};
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, out);
Containers::Array<Containers::Pair<UnsignedInt, Matrix3>> out{NoInit, std::size_t(_fields[fieldWithObjectMapping]._size)};
/** @todo use slicing once Pair exposes members somehow */
objectsIntoInternal(fieldWithObjectMapping, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, {out, reinterpret_cast<Matrix3*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)});
return out;
}
@ -1469,37 +1474,45 @@ void SceneData::translationsRotationsScalings2DIntoInternal(const UnsignedInt tr
}
}
void SceneData::translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const {
void SceneData::translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
#ifndef CORRADE_NO_ASSERT
const std::size_t expectedSize =
#endif
findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::translationsRotationsScalings2DInto(): no transformation-related field found", );
CORRADE_ASSERT(!translationDestination || translationDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected translation destination view either empty or with" << expectedSize << "elements but got" << translationDestination.size(), );
CORRADE_ASSERT(!rotationDestination || rotationDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected rotation destination view either empty or with" << expectedSize << "elements but got" << rotationDestination.size(), );
CORRADE_ASSERT(!scalingDestination || scalingDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected scaling destination view either empty or with" << expectedSize << "elements but got" << scalingDestination.size(), );
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected object destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!translationDestination || translationDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected translation destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << translationDestination.size(), );
CORRADE_ASSERT(!rotationDestination || rotationDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected rotation destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << rotationDestination.size(), );
CORRADE_ASSERT(!scalingDestination || scalingDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings2DInto(): expected scaling destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << scalingDestination.size(), );
objectsIntoInternal(fieldWithObjectMapping, 0, objectDestination);
translationsRotationsScalings2DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, 0, translationDestination, rotationDestination, scalingDestination);
}
std::size_t SceneData::translationsRotationsScalings2DInto(const std::size_t offset, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const {
std::size_t SceneData::translationsRotationsScalings2DInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::translationsRotationsScalings2DInto(): no transformation-related field found", {});
CORRADE_ASSERT(offset <= expectedSize,
"Trade::SceneData::translationsRotationsScalings2DInto(): offset" << offset << "out of bounds for a field of size" << expectedSize, {});
const std::size_t fieldSize = _fields[fieldWithObjectMapping]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::translationsRotationsScalings2DInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !translationDestination || objectDestination.size() == translationDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): object and translation destination views have different size," << objectDestination.size() << "vs" << translationDestination.size(), {});
CORRADE_ASSERT(!objectDestination != !rotationDestination || objectDestination.size() == rotationDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): object and rotation destination views have different size," << objectDestination.size() << "vs" << rotationDestination.size(), {});
CORRADE_ASSERT(!objectDestination != !scalingDestination || objectDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): object and scaling destination views have different size," << objectDestination.size() << "vs" << scalingDestination.size(), {});
CORRADE_ASSERT(!translationDestination != !rotationDestination || translationDestination.size() == rotationDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): translation and rotation destination views have different size," << translationDestination.size() << "vs" << rotationDestination.size(), {});
CORRADE_ASSERT(!translationDestination != !scalingDestination || translationDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): translation and scaling destination views have different size," << translationDestination.size() << "vs" << scalingDestination.size(), {});
CORRADE_ASSERT(!rotationDestination != !scalingDestination || rotationDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings2DInto(): rotation and scaling destination views have different size," << rotationDestination.size() << "vs" << scalingDestination.size(), {});
const std::size_t size = Math::min(Math::max({translationDestination.size(), rotationDestination.size(), scalingDestination.size()}), expectedSize - offset);
const std::size_t size = Math::min(Math::max({objectDestination.size(), translationDestination.size(), rotationDestination.size(), scalingDestination.size()}), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldWithObjectMapping, offset, objectDestination.prefix(size));
translationsRotationsScalings2DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, offset,
translationDestination ? translationDestination.prefix(size) : nullptr,
rotationDestination ? rotationDestination.prefix(size) : nullptr,
@ -1507,18 +1520,19 @@ std::size_t SceneData::translationsRotationsScalings2DInto(const std::size_t off
return size;
}
Containers::Array<Containers::Triple<Vector2, Complex, Vector2>> SceneData::translationsRotationsScalings2DAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector2, Complex, Vector2>>> SceneData::translationsRotationsScalings2DAsArray() const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::translationsRotationsScalings2DInto(): no transformation-related field found", {});
Containers::Array<Containers::Triple<Vector2, Complex, Vector2>> out{NoInit, expectedSize};
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector2, Complex, Vector2>>> out{NoInit, std::size_t(_fields[fieldWithObjectMapping]._size)};
/** @todo use slicing once Triple exposes members somehow */
const Containers::StridedArrayView1D<Vector2> translationsOut{out, reinterpret_cast<Vector2*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Complex> rotationsOut{out, reinterpret_cast<Complex*>(reinterpret_cast<char*>(out.data()) + sizeof(Vector2)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Vector2> scalingsOut{out, reinterpret_cast<Vector2*>(reinterpret_cast<char*>(out.data()) + sizeof(Vector2) + sizeof(Complex)), out.size(), sizeof(decltype(out)::Type)};
objectsIntoInternal(fieldWithObjectMapping, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
const Containers::StridedArrayView1D<Vector2> translationsOut{out, reinterpret_cast<Vector2*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Complex> rotationsOut{out, reinterpret_cast<Complex*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt) + sizeof(Vector2)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Vector2> scalingsOut{out, reinterpret_cast<Vector2*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt) + sizeof(Vector2) + sizeof(Complex)), out.size(), sizeof(decltype(out)::Type)};
translationsRotationsScalings2DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, 0, translationsOut, rotationsOut, scalingsOut);
return out;
}
@ -1599,40 +1613,46 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
void SceneData::transformations3DInto(const Containers::StridedArrayView1D<Matrix4>& destination) const {
void SceneData::transformations3DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix4>& fieldDestination) const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
#ifndef CORRADE_NO_ASSERT
const std::size_t expectedSize =
#endif
findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const std::size_t fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::transformations3DInto(): no transformation-related field found", );
CORRADE_ASSERT(expectedSize == destination.size(),
"Trade::SceneData::transformations3DInto(): expected a view with" << expectedSize << "elements but got" << destination.size(), );
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::transformations3DInto(): expected object destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::transformations3DInto(): expected field destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldWithObjectMapping, 0, objectDestination);
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, fieldDestination);
}
std::size_t SceneData::transformations3DInto(const std::size_t offset, const Containers::StridedArrayView1D<Matrix4>& destination) const {
std::size_t SceneData::transformations3DInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix4>& fieldDestination) const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::transformations3DInto(): no transformation-related field found", {});
CORRADE_ASSERT(offset <= expectedSize,
"Trade::SceneData::transformations3DInto(): offset" << offset << "out of bounds for a field of size" << expectedSize, {});
const std::size_t size = Math::min(destination.size(), expectedSize - offset);
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, destination.prefix(size));
const std::size_t fieldSize = _fields[fieldWithObjectMapping]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::transformations3DInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::transformations3DInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldWithObjectMapping, offset, objectDestination.prefix(size));
if(fieldDestination) transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<Matrix4> SceneData::transformations3DAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Matrix4>> SceneData::transformations3DAsArray() const {
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::transformations3DInto(): no transformation-related field found", {});
Containers::Array<Matrix4> out{NoInit, expectedSize};
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, out);
Containers::Array<Containers::Pair<UnsignedInt, Matrix4>> out{NoInit, std::size_t(_fields[fieldWithObjectMapping]._size)};
/** @todo use slicing once Pair exposes members somehow */
objectsIntoInternal(fieldWithObjectMapping, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, 0, {out, reinterpret_cast<Matrix4*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)});
return out;
}
@ -1699,37 +1719,45 @@ void SceneData::translationsRotationsScalings3DIntoInternal(const UnsignedInt tr
}
}
void SceneData::translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const {
void SceneData::translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
#ifndef CORRADE_NO_ASSERT
const std::size_t expectedSize =
#endif
findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::translationsRotationsScalings3DInto(): no transformation-related field found", );
CORRADE_ASSERT(!translationDestination || translationDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected translation destination view either empty or with" << expectedSize << "elements but got" << translationDestination.size(), );
CORRADE_ASSERT(!rotationDestination || rotationDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected rotation destination view either empty or with" << expectedSize << "elements but got" << rotationDestination.size(), );
CORRADE_ASSERT(!scalingDestination || scalingDestination.size() == expectedSize,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected scaling destination view either empty or with" << expectedSize << "elements but got" << scalingDestination.size(), );
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected object destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!translationDestination || translationDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected translation destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << translationDestination.size(), );
CORRADE_ASSERT(!rotationDestination || rotationDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected rotation destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << rotationDestination.size(), );
CORRADE_ASSERT(!scalingDestination || scalingDestination.size() == _fields[fieldWithObjectMapping]._size,
"Trade::SceneData::translationsRotationsScalings3DInto(): expected scaling destination view either empty or with" << _fields[fieldWithObjectMapping]._size << "elements but got" << scalingDestination.size(), );
objectsIntoInternal(fieldWithObjectMapping, 0, objectDestination);
translationsRotationsScalings3DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, 0, translationDestination, rotationDestination, scalingDestination);
}
std::size_t SceneData::translationsRotationsScalings3DInto(const std::size_t offset, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const {
std::size_t SceneData::translationsRotationsScalings3DInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
"Trade::SceneData::translationsRotationsScalings3DInto(): no transformation-related field found", {});
CORRADE_ASSERT(offset <= expectedSize,
"Trade::SceneData::translationsRotationsScalings3DInto(): offset" << offset << "out of bounds for a field of size" << expectedSize, {});
const std::size_t fieldSize = _fields[fieldWithObjectMapping]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::translationsRotationsScalings3DInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !translationDestination || objectDestination.size() == translationDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): object and translation destination views have different size," << objectDestination.size() << "vs" << translationDestination.size(), {});
CORRADE_ASSERT(!objectDestination != !rotationDestination || objectDestination.size() == rotationDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): object and rotation destination views have different size," << objectDestination.size() << "vs" << rotationDestination.size(), {});
CORRADE_ASSERT(!objectDestination != !scalingDestination || objectDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): object and scaling destination views have different size," << objectDestination.size() << "vs" << scalingDestination.size(), {});
CORRADE_ASSERT(!translationDestination != !rotationDestination || translationDestination.size() == rotationDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): translation and rotation destination views have different size," << translationDestination.size() << "vs" << rotationDestination.size(), {});
CORRADE_ASSERT(!translationDestination != !scalingDestination || translationDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): translation and scaling destination views have different size," << translationDestination.size() << "vs" << scalingDestination.size(), {});
CORRADE_ASSERT(!rotationDestination != !scalingDestination || rotationDestination.size() == scalingDestination.size(),
"Trade::SceneData::translationsRotationsScalings3DInto(): rotation and scaling destination views have different size," << rotationDestination.size() << "vs" << scalingDestination.size(), {});
const std::size_t size = Math::min(Math::max({translationDestination.size(), rotationDestination.size(), scalingDestination.size()}), expectedSize - offset);
const std::size_t size = Math::min(Math::max({objectDestination.size(), translationDestination.size(), rotationDestination.size(), scalingDestination.size()}), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldWithObjectMapping, offset, objectDestination.prefix(size));
translationsRotationsScalings3DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, offset,
translationDestination ? translationDestination.prefix(size) : nullptr,
rotationDestination ? rotationDestination.prefix(size) : nullptr,
@ -1737,18 +1765,19 @@ std::size_t SceneData::translationsRotationsScalings3DInto(const std::size_t off
return size;
}
Containers::Array<Containers::Triple<Vector3, Quaternion, Vector3>> SceneData::translationsRotationsScalings3DAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector3, Quaternion, Vector3>>> SceneData::translationsRotationsScalings3DAsArray() const {
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const std::size_t expectedSize = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(expectedSize != ~std::size_t{},
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
CORRADE_ASSERT(fieldWithObjectMapping != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::translationsRotationsScalings3DInto(): no transformation-related field found", {});
Containers::Array<Containers::Triple<Vector3, Quaternion, Vector3>> out{NoInit, expectedSize};
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector3, Quaternion, Vector3>>> out{NoInit, std::size_t(_fields[fieldWithObjectMapping]._size)};
/** @todo use slicing once Triple exposes members somehow */
const Containers::StridedArrayView1D<Vector3> translationsOut{out, reinterpret_cast<Vector3*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Quaternion> rotationsOut{out, reinterpret_cast<Quaternion*>(reinterpret_cast<char*>(out.data()) + sizeof(Vector3)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Vector3> scalingsOut{out, reinterpret_cast<Vector3*>(reinterpret_cast<char*>(out.data()) + sizeof(Vector3) + sizeof(Quaternion)), out.size(), sizeof(decltype(out)::Type)};
objectsIntoInternal(fieldWithObjectMapping, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
const Containers::StridedArrayView1D<Vector3> translationsOut{out, reinterpret_cast<Vector3*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Quaternion> rotationsOut{out, reinterpret_cast<Quaternion*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt) + sizeof(Vector3)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Vector3> scalingsOut{out, reinterpret_cast<Vector3*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt) + sizeof(Vector3) + sizeof(Quaternion)), out.size(), sizeof(decltype(out)::Type)};
translationsRotationsScalings3DIntoInternal(translationFieldId, rotationFieldId, scalingFieldId, 0, translationsOut, rotationsOut, scalingsOut);
return out;
}
@ -1787,9 +1816,11 @@ void SceneData::indexFieldIntoInternal(const UnsignedInt fieldId, const std::siz
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Array<UnsignedInt> SceneData::unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const {
Containers::Array<UnsignedInt> out{NoInit, std::size_t(_fields[fieldId]._size)};
unsignedIndexFieldIntoInternal(fieldId, 0, out);
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> SceneData::unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const {
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> out{NoInit, std::size_t(_fields[fieldId]._size)};
/** @todo use slicing once Pair exposes members somehow */
objectsIntoInternal(fieldId, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
unsignedIndexFieldIntoInternal(fieldId, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)});
return out;
}
@ -1812,67 +1843,84 @@ void SceneData::meshesMaterialsIntoInternal(const UnsignedInt fieldId, const std
}
}
void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", );
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::meshesMaterialsInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
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(), );
objectsIntoInternal(fieldId, 0, objectDestination);
meshesMaterialsIntoInternal(fieldId, 0, meshDestination, meshMaterialDestination);
}
std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::meshesMaterialsInto(): offset" << offset << "out of bounds for a field of size" << _fields[fieldId]._size, {});
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::meshesMaterialsInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !meshDestination || objectDestination.size() == meshDestination.size(),
"Trade::SceneData::meshesMaterialsInto(): object and mesh destination views have different size," << objectDestination.size() << "vs" << meshDestination.size(), {});
CORRADE_ASSERT(!objectDestination != !meshMaterialDestination || objectDestination.size() == meshMaterialDestination.size(),
"Trade::SceneData::meshesMaterialsInto(): object and mesh material destination views have different size," << objectDestination.size() << "vs" << meshMaterialDestination.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);
const std::size_t size = Math::min(Math::max({objectDestination.size(), meshDestination.size(), meshMaterialDestination.size()}), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
meshesMaterialsIntoInternal(fieldId, offset,
meshDestination ? meshDestination.prefix(size) : nullptr,
meshMaterialDestination ? meshMaterialDestination.prefix(size) : nullptr);
return size;
}
Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::meshesMaterialsAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> SceneData::meshesMaterialsAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {});
Containers::Array<Containers::Pair<UnsignedInt, Int>> out{NoInit, std::size_t(_fields[fieldId]._size)};
Containers::Array<Containers::Pair<UnsignedInt, 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)};
objectsIntoInternal(fieldId, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
const Containers::StridedArrayView1D<UnsignedInt> meshesOut{out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt)), out.size(), sizeof(decltype(out)::Type)};
const Containers::StridedArrayView1D<Int> meshMaterialsOut{out, reinterpret_cast<Int*>(reinterpret_cast<char*>(out.data()) + sizeof(UnsignedInt) + 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>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::lightsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::lightsInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
unsignedIndexFieldIntoInternal(fieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::lightsInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::lightsInto(): expected field destination view either empty or with" << _fields[fieldId]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldId, 0, objectDestination);
unsignedIndexFieldIntoInternal(fieldId, 0, fieldDestination);
}
std::size_t SceneData::lightsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
std::size_t SceneData::lightsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::lightsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::lightsInto(): 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));
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::lightsInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::lightsInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
if(fieldDestination) unsignedIndexFieldIntoInternal(fieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<UnsignedInt> SceneData::lightsAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> SceneData::lightsAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
@ -1881,27 +1929,34 @@ Containers::Array<UnsignedInt> SceneData::lightsAsArray() const {
return unsignedIndexFieldAsArrayInternal(fieldId);
}
void SceneData::camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
void SceneData::camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::camerasInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::camerasInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
unsignedIndexFieldIntoInternal(fieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::camerasInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::camerasInto(): expected field destination view either empty or with" << _fields[fieldId]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldId, 0, objectDestination);
unsignedIndexFieldIntoInternal(fieldId, 0, fieldDestination);
}
std::size_t SceneData::camerasInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
std::size_t SceneData::camerasInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::camerasInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::camerasInto(): 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));
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::camerasInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::camerasInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
if(fieldDestination) unsignedIndexFieldIntoInternal(fieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<UnsignedInt> SceneData::camerasAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> SceneData::camerasAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
@ -1910,27 +1965,34 @@ Containers::Array<UnsignedInt> SceneData::camerasAsArray() const {
return unsignedIndexFieldAsArrayInternal(fieldId);
}
void SceneData::skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
void SceneData::skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::skinsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::skinsInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
unsignedIndexFieldIntoInternal(fieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::skinsInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::skinsInto(): expected field destination view either empty or with" << _fields[fieldId]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldId, 0, objectDestination);
unsignedIndexFieldIntoInternal(fieldId, 0, fieldDestination);
}
std::size_t SceneData::skinsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
std::size_t SceneData::skinsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::skinsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::skinsInto(): 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));
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::skinsInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::skinsInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
if(fieldDestination) unsignedIndexFieldIntoInternal(fieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<UnsignedInt> SceneData::skinsAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> SceneData::skinsAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
@ -1949,34 +2011,52 @@ void SceneData::importerStateIntoInternal(const UnsignedInt fieldId, const std::
Utility::copy(Containers::arrayCast<const void* const>(fieldDataFieldViewInternal(field, offset, destination.size())), destination);
}
void SceneData::importerStateInto(const Containers::StridedArrayView1D<const void*>& destination) const {
void SceneData::importerStateInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<const void*>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::importerStateInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
"Trade::SceneData::importerStateInto(): expected a view with" << _fields[fieldId]._size << "elements but got" << destination.size(), );
importerStateIntoInternal(fieldId, 0, destination);
CORRADE_ASSERT(!objectDestination || objectDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::importerStateInto(): expected object destination view either empty or with" << _fields[fieldId]._size << "elements but got" << objectDestination.size(), );
CORRADE_ASSERT(!fieldDestination || fieldDestination.size() == _fields[fieldId]._size,
"Trade::SceneData::importerStateInto(): expected field destination view either empty or with" << _fields[fieldId]._size << "elements but got" << fieldDestination.size(), );
objectsIntoInternal(fieldId, 0, objectDestination);
importerStateIntoInternal(fieldId, 0, fieldDestination);
}
std::size_t SceneData::importerStateInto(const std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const {
std::size_t SceneData::importerStateInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<const void*>& fieldDestination) const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::importerStateInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
"Trade::SceneData::importerStateInto(): 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);
importerStateIntoInternal(fieldId, offset, destination.prefix(size));
const std::size_t fieldSize = _fields[fieldId]._size;
CORRADE_ASSERT(offset <= fieldSize,
"Trade::SceneData::importerStateInto(): offset" << offset << "out of bounds for a field of size" << fieldSize, {});
CORRADE_ASSERT(!objectDestination != !fieldDestination|| objectDestination.size() == fieldDestination.size(),
"Trade::SceneData::importerStateInto(): object and field destination views have different size," << objectDestination.size() << "vs" << fieldDestination.size(), {});
const std::size_t size = Math::min(Math::max(objectDestination.size(), fieldDestination.size()), fieldSize - offset);
if(objectDestination) objectsIntoInternal(fieldId, offset, objectDestination.prefix(size));
if(fieldDestination) importerStateIntoInternal(fieldId, offset, fieldDestination.prefix(size));
return size;
}
Containers::Array<const void*> SceneData::importerStateAsArray() const {
Containers::Array<Containers::Pair<UnsignedInt, const void*>> SceneData::importerStateAsArray() const {
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
"Trade::SceneData::importerStateInto(): field not found", {});
Containers::Array<const void*> out{NoInit, std::size_t(_fields[fieldId]._size)};
importerStateIntoInternal(fieldId, 0, out);
Containers::Array<Containers::Pair<UnsignedInt, const void*>> out{
/* There's padding before the pointer on 64bit, zero-initialize to
avoid keeping random bytes in there */
#ifdef CORRADE_TARGET_32BIT
NoInit
#else
ValueInit
#endif
, std::size_t(_fields[fieldId]._size)};
/** @todo use slicing once Pair exposes members somehow, especially because
this is EXTREMELY prone to bugs due to the padding before the pointer */
objectsIntoInternal(fieldId, 0, {out, reinterpret_cast<UnsignedInt*>(reinterpret_cast<char*>(out.data())), out.size(), sizeof(decltype(out)::Type)});
importerStateIntoInternal(fieldId, 0, {out, reinterpret_cast<const void**>(reinterpret_cast<char*>(out.data()) + sizeof(const void*)), out.size(), sizeof(decltype(out)::Type)});
return out;
}
@ -2040,8 +2120,9 @@ Containers::Optional<Matrix3> SceneData::transformation2DFor(const UnsignedInt o
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::transformation2DFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping;
if(findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {};
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
if(fieldWithObjectMapping == ~UnsignedInt{}) return {};
/* If is2D() returned false as well, all *FieldId would be invalid, which
is handled above. */
@ -2060,8 +2141,9 @@ Containers::Optional<Containers::Triple<Vector2, Complex, Vector2>> SceneData::t
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::translationRotationScaling2DFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping;
if(findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {};
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
if(fieldWithObjectMapping == ~UnsignedInt{}) return {};
/* If is2D() returned false as well, all *FieldId would be invalid, which
is handled above. */
@ -2082,8 +2164,9 @@ Containers::Optional<Matrix4> SceneData::transformation3DFor(const UnsignedInt o
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::transformation3DFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping;
if(findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {};
UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId;
const UnsignedInt fieldWithObjectMapping = findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId);
if(fieldWithObjectMapping == ~UnsignedInt{}) return {};
/* If is3D() returned false as well, all *FieldId would be invalid, which
is handled above. */
@ -2102,8 +2185,9 @@ Containers::Optional<Containers::Triple<Vector3, Quaternion, Vector3>> SceneData
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::translationRotationScaling3DFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping;
if(findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {};
UnsignedInt translationFieldId, rotationFieldId, scalingFieldId;
const UnsignedInt fieldWithObjectMapping = findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId);
if(fieldWithObjectMapping == ~UnsignedInt{}) return {};
/* If is3D() returned false as well, all *FieldId would be invalid, which
is handled above. */

422
src/Magnum/Trade/SceneData.h

@ -1240,10 +1240,18 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @m_since_latest
*
* The @p fieldId is expected to be smaller than @ref fieldCount() and
* @p T is expected to correspond to @ref objectType(). You can also
* use the non-templated @ref objectsAsArray() accessor to get the
* object mapping converted to the usual type, but note that such
* operation involves extra allocation and data conversion.
* @p T is expected to correspond to @ref objectType().
*
* You can also use the non-templated @ref objectsAsArray() accessor
* (or the combined @ref parentsAsArray(),
* @ref transformations2DAsArray(), @ref transformations3DAsArray(),
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors) to get the object mapping
* converted to the usual type, but note that these operations involve
* extra allocation and data conversion.
* @see @ref mutableObjects(UnsignedInt)
*/
template<class T> Containers::StridedArrayView1D<const T> objects(UnsignedInt fieldId) const;
@ -1287,10 +1295,18 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @m_since_latest
*
* The @p fieldName is expected to exist and @p T is expected to
* correspond to @ref objectType(). You can also use the non-templated
* @ref objectsAsArray() accessor to get the object mapping converted
* to the usual type, but note that such operation involves extra
* allocation and data conversion.
* correspond to @ref objectType().
*
* You can also use the non-templated @ref objectsAsArray() accessor
* (or the combined @ref parentsAsArray(),
* @ref transformations2DAsArray(), @ref transformations3DAsArray(),
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors) to get the object mapping
* converted to the usual type, but note that these operations involve
* extra allocation and data conversion.
* @see @ref hasField(), @ref objects(UnsignedInt) const,
* @ref mutableObjects(UnsignedInt)
*/
@ -1338,6 +1354,7 @@ class MAGNUM_TRADE_EXPORT SceneData {
* is expected to correspond to @ref fieldType(UnsignedInt) const. The
* field is also expected to 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 translationsRotationsScalings2DAsArray(),
@ -1418,8 +1435,9 @@ class MAGNUM_TRADE_EXPORT SceneData {
* The @p name is expected to exist and @p T is expected to correspond
* to @ref fieldType(SceneField) const. The field is also expected to
* 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(),
* using @cpp T[] @ce instead of @cpp T @ce.
*
* You can also use the non-templated @ref parentsAsArray(),
* @ref transformations2DAsArray(), @ref transformations3DAsArray(),
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
@ -1474,6 +1492,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref objects(UnsignedInt) const that converts the field from an
* arbitrary underlying type and returns it in a newly-allocated array.
* The @p fieldId is expected to be smaller than @ref fieldCount().
*
* Note that, for common fields, you can also use the
* @ref parentsAsArray(), @ref transformations2DAsArray(),
* @ref transformations3DAsArray(),
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors, which give out the object
* mapping together with the field data.
* @see @ref objectsInto(UnsignedInt, const Containers::StridedArrayView1D<UnsignedInt>&) const
*/
Containers::Array<UnsignedInt> objectsAsArray(UnsignedInt fieldId) const;
@ -1485,6 +1513,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* Like @ref objectsAsArray(UnsignedInt) const, but puts the result
* into @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
*
* Note that, for common fields, you can also use the
* @ref parentsInto(), @ref transformations2DInto(),
* @ref transformations3DInto(),
* @ref translationsRotationsScalings2DInto(),
* @ref translationsRotationsScalings3DInto(),
* @ref meshesMaterialsInto(), @ref lightsInto(), @ref camerasInto(),
* @ref skinsInto(), @ref importerStateInto() accessors, which can give
* out the object mapping together with the field data.
*
* @see @ref fieldSize(UnsignedInt) const
*/
void objectsInto(UnsignedInt fieldId, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1498,6 +1536,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* 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.
*
* Note that, for common fields, you can also use the
* @ref parentsInto(), @ref transformations2DInto(),
* @ref transformations3DInto(),
* @ref translationsRotationsScalings2DInto(),
* @ref translationsRotationsScalings3DInto(),
* @ref meshesMaterialsInto(), @ref lightsInto(), @ref camerasInto(),
* @ref skinsInto(), @ref importerStateInto() accessors, which can give
* out the object mapping together with the field data.
*
* @see @ref fieldSize(UnsignedInt) const,
* @ref fieldObjectOffset(UnsignedInt, UnsignedInt, std::size_t) const
*/
@ -1511,6 +1559,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref objects(SceneField) const that converts the field from an
* arbitrary underlying type and returns it in a newly-allocated array.
* The @p fieldName is expected to exist.
*
* Note that, for common fields, you can also use the
* @ref parentsAsArray(), @ref transformations2DAsArray(),
* @ref transformations3DAsArray(),
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors, which give out the object
* mapping together with the field data.
* @see @ref objectsInto(SceneField, const Containers::StridedArrayView1D<UnsignedInt>&) const,
* @ref hasField()
*/
@ -1523,6 +1581,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* Like @ref objectsAsArray(SceneField) const, but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
*
* Note that, for common fields, you can also use the
* @ref parentsInto(), @ref transformations2DInto(),
* @ref transformations3DInto(),
* @ref translationsRotationsScalings2DInto(),
* @ref translationsRotationsScalings3DInto(),
* @ref meshesMaterialsInto(), @ref lightsInto(), @ref camerasInto(),
* @ref skinsInto(), @ref importerStateInto() accessors, which can give
* out the object mapping together with the field data.
*
* @see @ref fieldSize(SceneField) const
*/
void objectsInto(SceneField fieldName, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1536,6 +1604,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* 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.
*
* Note that, for common fields, you can also use the
* @ref parentsInto(), @ref transformations2DInto(),
* @ref transformations3DInto(),
* @ref translationsRotationsScalings2DInto(),
* @ref translationsRotationsScalings3DInto(),
* @ref meshesMaterialsInto(), @ref lightsInto(), @ref camerasInto(),
* @ref skinsInto(), @ref importerStateInto() accessors, which can give
* out the object mapping together with the field data.
*
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
@ -1545,95 +1623,107 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Parent indices as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Parent as the argument that converts the field from
* an arbitrary underlying type and returns it in a newly-allocated
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Parent as
* the argument. Converts the object mapping and the field from
* arbitrary underlying types and returns them in a newly-allocated
* array. The field is expected to exist.
* @see @ref parentsInto(), @ref hasField(), @ref parentFor(),
* @ref childrenFor()
*/
Containers::Array<Int> parentsAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Int>> parentsAsArray() const;
/**
* @brief Parent indices as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Like @ref parentsAsArray(), 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 parentsAsArray(), but puts the result into
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with @ref SceneField::Parent.
* @see @ref fieldSize(SceneField) const
*/
void parentsInto(const Containers::StridedArrayView1D<Int>& destination) const;
void parentsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Int>& fieldDestination) const;
/**
* @brief A subrange of parent indices as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref parentsInto(const Containers::StridedArrayView1D<Int>&) const
* Compared to @ref parentsInto(const Containers::StridedArrayView1D<UnsignedInt>&, 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.
* 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t parentsInto(std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const;
std::size_t parentsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Int>& fieldDestination) const;
/**
* @brief 2D transformations as 3x3 float matrices
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with
* @ref SceneField::Transformation as the argument, or, if not present,
* to a matrix created out of a subset of the
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling fields that's present. The transformation
* is converted and composed from an arbitrary underlying type and
* returned in a newly-allocated array. At least one of the fields is
* @ref SceneField::Scaling fields that's present. Converts the object
* mapping and the fields from arbitrary underlying types and returns
* them in a newly-allocated array. At least one of the fields is
* expected to exist and they are expected to have a type corresponding
* to 2D, otherwise you're supposed to use
* @ref transformations3DAsArray().
* @see @ref is2D(), @ref transformations2DInto(), @ref hasField(),
* @ref fieldType(SceneField) const, @ref transformation2DFor()
*/
Containers::Array<Matrix3> transformations2DAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Matrix3>> transformations2DAsArray() const;
/**
* @brief 2D transformations as 3x3 float matrices into a pre-allocated view
* @m_since_latest
*
* Like @ref transformations2DAsArray(), but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with the first of the
* @ref SceneField::Transformation, @ref SceneField::Translation,
* @ref SceneField::Rotation and @ref SceneField::Scaling fields that's
* present.
* @see @ref fieldSize(SceneField) const
*/
void transformations2DInto(const Containers::StridedArrayView1D<Matrix3>& destination) const;
void transformations2DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix3>& fieldDestination) const;
/**
* @brief A subrange of 2D transformations as 3x3 float matrices into a pre-allocated view
* @m_since_latest
*
* Compared to @ref transformations2DInto(const Containers::StridedArrayView1D<Matrix3>&) const
* Compared to @ref transformations2DInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Matrix3>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t transformations2DInto(std::size_t offset, const Containers::StridedArrayView1D<Matrix3>& destination) const;
std::size_t transformations2DInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix3>& fieldDestination) const;
/**
* @brief 2D transformations as float translation, rotation and scaling components
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling as the arguments, as these are required to
* share the same object mapping. Converts the fields from an arbitrary
* underlying type and returns them in a newly-allocated array. At
* least one of the fields is expected to exist and they are expected
* to have a type corresponding to 2D, otherwise you're supposed to use
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Translation,
* @ref SceneField::Rotation and @ref SceneField::Scaling as the
* arguments, as these are required to share the same object mapping.
* Converts the object mapping and the fields from arbitrary underlying
* types and returns them in a newly-allocated array. At least one of
* the fields is expected to exist and they are expected to have a type
* corresponding to 2D, otherwise you're supposed to use
* @ref translationsRotationsScalings3DAsArray(). If the
* @ref SceneField::Translation field isn't present, the first returned
* value is a zero vector. If the @relativeref{SceneField,Rotation}
@ -1644,26 +1734,31 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref hasField(), @ref fieldType(SceneField) const,
* @ref translationRotationScaling2DFor()
*/
Containers::Array<Containers::Triple<Vector2, Complex, Vector2>> translationsRotationsScalings2DAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector2, Complex, Vector2>>> translationsRotationsScalings2DAsArray() const;
/**
* @brief 2D transformations as float translation, rotation and scaling components into a pre-allocated view
* @m_since_latest
*
* Like @ref translationsRotationsScalings2DAsArray(), but puts the
* result into @p translationDestination, @p rotationDestination and
* @p scalingDestination instead of allocating a new array. Expects
* that each view is either @cpp nullptr @ce or sized to contain
* exactly all data.
* result into @p objectDestination, @p translationDestination,
* @p rotationDestination and @p scalingDestination instead of
* allocating a new array. Expects that each view is either
* @cpp nullptr @ce or sized to contain exactly all data. If
* @p translationDestination, @p rotationDestination and
* @p scalingDestination are all @cpp nullptr @ce, the effect is the
* same as calling @ref objectsInto() with one of the
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling fields that's present.
* @see @ref fieldSize(SceneField) const
*/
void translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const;
void translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const;
/**
* @brief A subrange of 2D transformations as float translation, rotation and scaling components into a pre-allocated view
* @m_since_latest
*
* Compared to @ref translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<Vector2>&, const Containers::StridedArrayView1D<Complex>&, const Containers::StridedArrayView1D<Vector2>&) const
* Compared to @ref translationsRotationsScalings2DInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Vector2>&, const Containers::StridedArrayView1D<Complex>&, const Containers::StridedArrayView1D<Vector2>&) const
* extracts only a subrange of the field defined by @p offset and 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
@ -1671,63 +1766,71 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t translationsRotationsScalings2DInto(std::size_t offset, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const;
std::size_t translationsRotationsScalings2DInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const;
/**
* @brief 3D transformations as 4x4 float matrices
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with
* @ref SceneField::Transformation as the argument, or, if not present,
* to a matrix created out of a subset of the
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling fields that's present. The transformation
* is converted and composed from an arbitrary underlying type and
* returned in a newly-allocated array. At least one of the fields is
* @ref SceneField::Scaling fields that's present. Converts the object
* mapping and the fields from arbitrary underlying types and returns
* them in a newly-allocated array. At least one of the fields is
* expected to exist and they are expected to have a type corresponding
* to 3D, otherwise you're supposed to use
* @ref transformations2DAsArray().
* @see @ref is3D(), @ref transformations3DInto(), @ref hasField(),
* @ref fieldType(SceneField) const, @ref transformation3DFor()
*/
Containers::Array<Matrix4> transformations3DAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Matrix4>> transformations3DAsArray() const;
/**
* @brief 3D transformations as 4x4 float matrices into a pre-allocated view
* @m_since_latest
*
* Like @ref transformations3DAsArray(), but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that the two views are either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with the first of the
* @ref SceneField::Transformation, @ref SceneField::Translation,
* @ref SceneField::Rotation and @ref SceneField::Scaling fields that's
* present.
* @see @ref fieldSize(SceneField) const
*/
void transformations3DInto(const Containers::StridedArrayView1D<Matrix4>& destination) const;
void transformations3DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix4>& destination) const;
/**
* @brief A subrange of 3D transformations as 4x4 float matrices into a pre-allocated view
* @m_since_latest
*
* Compared to @ref transformations3DInto(const Containers::StridedArrayView1D<Matrix4>&) const
* Compared to @ref transformations3DInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Matrix4>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
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<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Matrix4>& destination) const;
/**
* @brief 3D transformations as float translation, rotation and scaling components
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling as the arguments, as these are required to
* share the same object mapping. Converts the fields from an arbitrary
* underlying type and returns them in a newly-allocated array. At
* least one of the fields is expected to exist and they are expected
* to have a type corresponding to 3D, otherwise you're supposed to use
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Translation,
* @ref SceneField::Rotation and @ref SceneField::Scaling as the
* arguments, as these are required to share the same object mapping.
* Converts the object mapping and the fields from arbitrary underlying
* types and returns them in a newly-allocated array. At least one of
* the fields is expected to exist and they are expected to have a type
* corresponding to 3D, otherwise you're supposed to use
* @ref translationsRotationsScalings2DAsArray(). If the
* @ref SceneField::Translation field isn't present, the first returned
* value is a zero vector. If the @relativeref{SceneField,Rotation}
@ -1738,26 +1841,31 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref hasField(), @ref fieldType(SceneField) const,
* @ref translationRotationScaling3DFor()
*/
Containers::Array<Containers::Triple<Vector3, Quaternion, Vector3>> translationsRotationsScalings3DAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Containers::Triple<Vector3, Quaternion, Vector3>>> translationsRotationsScalings3DAsArray() const;
/**
* @brief 3D transformations as float translation, rotation and scaling components into a pre-allocated view
* @m_since_latest
*
* Like @ref translationsRotationsScalings3DAsArray(), but puts the
* result into @p translationDestination, @p rotationDestination and
* @p scalingDestination instead of allocating a new array. Expects
* that each view is either @cpp nullptr @ce or sized to contain
* exactly all data.
* result into @p objectDestination, @p translationDestination,
* @p rotationDestination and @p scalingDestination instead of
* allocating a new array. Expects that each view is either
* @cpp nullptr @ce or sized to contain exactly all data. If
* @p translationDestination, @p rotationDestination and
* @p scalingDestination are all @cpp nullptr @ce, the effect is the
* same as calling @ref objectsInto() with one of the
* @ref SceneField::Translation, @ref SceneField::Rotation and
* @ref SceneField::Scaling fields that's present.
* @see @ref fieldSize(SceneField) const
*/
void translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const;
void translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const;
/**
* @brief A subrange of 3D transformations as float translation, rotation and scaling components into a pre-allocated view
* @m_since_latest
*
* Compared to @ref translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<Vector3>&, const Containers::StridedArrayView1D<Quaternion>&, const Containers::StridedArrayView1D<Vector3>&) const
* Compared to @ref translationsRotationsScalings3DInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Vector3>&, const Containers::StridedArrayView1D<Quaternion>&, const Containers::StridedArrayView1D<Vector3>&) const
* extracts only a subrange of the field defined by @p offset and 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
@ -1765,41 +1873,45 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t translationsRotationsScalings3DInto(std::size_t offset, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const;
std::size_t translationsRotationsScalings3DInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) const;
/**
* @brief Mesh and material IDs as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @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
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Mesh and
* @ref SceneField::MeshMaterial as the argument, as the two are
* required to share the same object mapping. Converts the object
* mapping and the fields from arbitrary underlying types and returns
* them 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(),
* @ref meshesMaterialsFor()
*/
Containers::Array<Containers::Pair<UnsignedInt, Int>> meshesMaterialsAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> meshesMaterialsAsArray() const;
/**
* @brief Mesh and material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* 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.
* @p objectDestination, @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. If @p meshDestination and
* @p meshMaterialDestination are both @cpp nullptr @ce, the effect is
* the same as calling @ref objectsInto() with @ref SceneField::Mesh.
* @see @ref fieldSize(SceneField) const
*/
void meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const;
void meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const;
/**
* @brief A subrange of mesh and material IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Int>&) const
* Compared to @ref meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<Int>&) const
* extracts only a subrange of the field defined by @p offset and 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
@ -1807,158 +1919,174 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t meshesMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialsDestination) const;
std::size_t meshesMaterialsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialsDestination) const;
/**
* @brief Light IDs as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Light 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.
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Light as the
* argument. Converts the object mapping and the field from arbitrary
* underlying types and returns them in a newly-allocated array. The
* field is expected to exist.
* @see @ref lightsInto(), @ref hasField(), @ref lightsFor()
*/
Containers::Array<UnsignedInt> lightsAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> lightsAsArray() const;
/**
* @brief Light IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Like @ref lightsAsArray(), 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 lightsAsArray(), but puts the result into
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref lightsInto() with @ref SceneField::Light.
* @see @ref fieldSize(SceneField) const
*/
void lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
void lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief A subrange of light IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref lightsInto(const Containers::StridedArrayView1D<UnsignedInt>&) const
* Compared to @ref lightsInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<UnsignedInt>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t lightsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
std::size_t lightsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief Camera IDs as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Camera as the argument that converts the field from
* an arbitrary underlying type and returns it in a newly-allocated
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Camera as
* the argument. Converts the object mapping and the field from
* arbitrary underlying types and returns them in a newly-allocated
* array. The field is expected to exist.
* @see @ref camerasInto(), @ref hasField(), @ref camerasFor()
*/
Containers::Array<UnsignedInt> camerasAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> camerasAsArray() const;
/**
* @brief Camera IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Like @ref camerasAsArray(), but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with @ref SceneField::Camera.
* @see @ref fieldSize(SceneField) const
*/
void camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
void camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief A subrange of camera IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref camerasInto(const Containers::StridedArrayView1D<UnsignedInt>&) const
* Compared to @ref camerasInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<UnsignedInt>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t camerasInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
std::size_t camerasInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief Skin IDs as 32-bit integers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::Skin 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.
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::Skin as the
* argument. Converts the object mapping and the field from arbitrary
* underlying types and returns them in a newly-allocated array. The
* field is expected to exist.
* @see @ref skinsInto(), @ref hasField(), @ref skinsFor()
*/
Containers::Array<UnsignedInt> skinsAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> skinsAsArray() const;
/**
* @brief Skin IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Like @ref skinsAsArray(), 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 skinsAsArray(), but puts the result into
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with @ref SceneField::Skin.
* @see @ref fieldSize(SceneField) const
*/
void skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
void skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief A subrange of skin IDs as 32-bit integers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref skinsInto(const Containers::StridedArrayView1D<UnsignedInt>&) const
* Compared to @ref skinsInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<UnsignedInt>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t skinsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
std::size_t skinsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<UnsignedInt>& fieldDestination) const;
/**
* @brief Per-object importer state as `void` pointers
* @m_since_latest
*
* Convenience alternative to @ref field(SceneField) const with
* @ref SceneField::ImporterState 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.
* Convenience alternative to @ref objects(SceneField) const together
* with @ref field(SceneField) const with @ref SceneField::ImporterState
* as the argument. Converts the object mapping and the field from
* arbitrary underlying types and returns them in a newly-allocated
* array. The field is expected to exist.
*
* This is different from @ref importerState(), which returns importer
* state for the scene itself, not particular objects.
* @see @ref importerStateInto(), @ref hasField(), @ref importerStateFor()
*/
Containers::Array<const void*> importerStateAsArray() const;
Containers::Array<Containers::Pair<UnsignedInt, const void*>> importerStateAsArray() const;
/**
* @brief Per-object importer state as `void` pointers into a pre-allocated view
* @m_since_latest
*
* Like @ref importerStateAsArray(), but puts the result into
* @p destination instead of allocating a new array. Expects that
* @p destination is sized to contain exactly all data.
* @p objectDestination and @p fieldDestination instead of allocating a
* new array. Expects that each view is either @cpp nullptr @ce or
* sized to contain exactly all data. If @p fieldDestination is
* @cpp nullptr @ce, the effect is the same as calling
* @ref objectsInto() with @ref SceneField::ImporterState.
* @see @ref fieldSize(SceneField) const
*/
void importerStateInto(const Containers::StridedArrayView1D<const void*>& destination) const;
void importerStateInto(const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<const void*>& fieldDestination) const;
/**
* @brief A subrange of per-object importer state as `void` pointers into a pre-allocated view
* @m_since_latest
*
* Compared to @ref importerStateInto(const Containers::StridedArrayView1D<const void*>&) const
* Compared to @ref importerStateInto(const Containers::StridedArrayView1D<UnsignedInt>&, const Containers::StridedArrayView1D<const void*>&) 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,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t importerStateInto(std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const;
std::size_t importerStateInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& objectDestination, const Containers::StridedArrayView1D<const void*>& fieldDestination) const;
/**
* @brief Parent for given object
@ -2300,15 +2428,15 @@ class MAGNUM_TRADE_EXPORT SceneData {
MAGNUM_TRADE_LOCAL void objectsIntoInternal(UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
MAGNUM_TRADE_LOCAL void parentsIntoInternal(UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const;
MAGNUM_TRADE_LOCAL std::size_t findTransformFields(UnsignedInt& transformationFieldId, UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId, UnsignedInt* fieldWithObjectMappingDestination = nullptr) const;
MAGNUM_TRADE_LOCAL std::size_t findTranslationRotationScalingFields(UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId, UnsignedInt* fieldWithObjectMappingDestination = nullptr) const;
MAGNUM_TRADE_LOCAL UnsignedInt findTransformFields(UnsignedInt& transformationFieldId, UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId) const;
MAGNUM_TRADE_LOCAL UnsignedInt findTranslationRotationScalingFields(UnsignedInt& translationFieldId, UnsignedInt& rotationFieldId, UnsignedInt& scalingFieldId) const;
MAGNUM_TRADE_LOCAL void transformations2DIntoInternal(UnsignedInt transformationFieldId, UnsignedInt translationFieldId, UnsignedInt rotationFieldId, UnsignedInt scalingFieldId, std::size_t offset, const Containers::StridedArrayView1D<Matrix3>& destination) const;
MAGNUM_TRADE_LOCAL void translationsRotationsScalings2DIntoInternal(UnsignedInt translationFieldId, UnsignedInt rotationFieldId, UnsignedInt scalingFieldId, std::size_t offset, const Containers::StridedArrayView1D<Vector2>& translationDestination, const Containers::StridedArrayView1D<Complex>& rotationDestination, const Containers::StridedArrayView1D<Vector2>& scalingDestination) const;
MAGNUM_TRADE_LOCAL void transformations3DIntoInternal(UnsignedInt transformationFieldId, UnsignedInt translationFieldId, UnsignedInt rotationFieldId, UnsignedInt scalingFieldId, std::size_t offset, const Containers::StridedArrayView1D<Matrix4>& destination) const;
MAGNUM_TRADE_LOCAL void translationsRotationsScalings3DIntoInternal(UnsignedInt translationFieldId, UnsignedInt rotationFieldId, UnsignedInt scalingFieldId, std::size_t offset, const Containers::StridedArrayView1D<Vector3>& translationDestination, const Containers::StridedArrayView1D<Quaternion>& rotationDestination, const Containers::StridedArrayView1D<Vector3>& scalingDestination) 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 Containers::Array<UnsignedInt> unsignedIndexFieldAsArrayInternal(const UnsignedInt fieldId) const;
MAGNUM_TRADE_LOCAL Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> unsignedIndexFieldAsArrayInternal(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;
MAGNUM_TRADE_LOCAL void importerStateIntoInternal(const UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const;

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

File diff suppressed because it is too large Load Diff

51
src/Magnum/Trade/Test/SceneToolsTest.cpp

@ -423,32 +423,35 @@ void SceneToolsTest::convertToSingleFunctionObjects() {
/* To be extra sure, verify the actual data. Parents have a few objects
added, the rest is the same */
CORRADE_COMPARE_AS(scene.objectsAsArray(SceneField::Parent), Containers::arrayView<UnsignedInt>({
15, 21, 22, 23, 1, 63, 64, 65, 66
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.parentsAsArray(), Containers::arrayView<Int>({
-1, -1, 1, 2, -1, 3, 3, 0, 4
}), TestSuite::Compare::Container);
/* Meshes have certain objects reassigned (and materials as well, as they
share the same object mapping view), field data stay the same */
CORRADE_COMPARE_AS(scene.objectsAsArray(SceneField::Mesh), Containers::arrayView<UnsignedInt>({
15, 23, 63, 64, 1, 65, 21
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.objectsAsArray(SceneField::MeshMaterial), Containers::arrayView<UnsignedInt>({
15, 23, 63, 64, 1, 65, 21
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.meshesMaterialsAsArray(),
Containers::arrayView(meshesMaterials),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.parentsAsArray(), (Containers::arrayView<Containers::Pair<UnsignedInt, Int>>({
{15, -1},
{21, -1},
{22, 1},
{23, 2},
{1, -1},
{63, 3},
{64, 3},
{65, 0},
{66, 4}
})), TestSuite::Compare::Container);
/* Meshes / materials have certain objects reassigned, field data stay the
same */
CORRADE_COMPARE_AS(scene.meshesMaterialsAsArray(), (Containers::arrayView<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>>({
{15, {6, 4}},
{23, {1, 0}},
{63, {2, 3}},
{64, {4, 2}},
{1, {7, 2}},
{65, {3, 1}},
{21, {5, -1}}
})), TestSuite::Compare::Container);
/* Cameras have certain objects reassigned, field data stay the same */
CORRADE_COMPARE_AS(scene.objectsAsArray(SceneField::Camera), Containers::arrayView<UnsignedInt>({
22, 66
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.camerasAsArray(),
Containers::arrayView(cameras),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.camerasAsArray(), (Containers::arrayView<Containers::Pair<UnsignedInt, UnsignedInt>>({
{22, 1},
{66, 5}
})), TestSuite::Compare::Container);
}
}}}}

Loading…
Cancel
Save