Browse Source

Trade: add public SceneData APIs for finding fields and objects.

Using hasField() + fieldId() was a bad usage pattern leading to a double
linear lookup, so there's now findFieldId() returning an Optional which
covers both. Similarly for finding an object offset in an field, there's
a findFieldObjectOffset() returning an Optional, fieldObjectOffset()
asserting if an object is not found (for convenience to avoid explicit
error handling on user side) and hasFieldObject().

The internal helpers were also renamed and the offset argument moved to
be last for consistency.
pull/525/head
Vladimír Vondruš 4 years ago
parent
commit
6e1bb5f838
  1. 259
      src/Magnum/Trade/SceneData.cpp
  2. 299
      src/Magnum/Trade/SceneData.h
  3. 218
      src/Magnum/Trade/Test/SceneDataTest.cpp

259
src/Magnum/Trade/SceneData.cpp

@ -831,36 +831,154 @@ UnsignedShort SceneData::fieldArraySize(const UnsignedInt id) const {
return _fields[id]._fieldArraySize;
}
UnsignedInt SceneData::fieldFor(const SceneField name) const {
UnsignedInt SceneData::findFieldIdInternal(const SceneField name) const {
for(std::size_t i = 0; i != _fields.size(); ++i)
if(_fields[i]._name == name) return i;
return ~UnsignedInt{};
}
bool SceneData::hasField(const SceneField name) const {
return fieldFor(name) != ~UnsignedInt{};
Containers::Optional<UnsignedInt> SceneData::findFieldId(const SceneField name) const {
const UnsignedInt fieldId = findFieldIdInternal(name);
return fieldId == ~UnsignedInt{} ? Containers::Optional<UnsignedInt>{} : fieldId;
}
UnsignedInt SceneData::fieldId(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::fieldId(): field" << name << "not found", {});
return fieldId;
}
bool SceneData::hasField(const SceneField name) const {
return findFieldIdInternal(name) != ~UnsignedInt{};
}
namespace {
template<class T> std::size_t findObject(const Containers::StridedArrayView1D<const void>& objects, const UnsignedInt object) {
const Containers::StridedArrayView1D<const T> objectsT = Containers::arrayCast<const T>(objects);
const std::size_t max = objectsT.size();
/** @todo implement something faster than O(n) when field-specific flags
can annotate how the object mapping is done */
for(std::size_t i = 0; i != max; ++i)
if(objectsT[i] == object) return i;
return max;
}
}
std::size_t SceneData::findFieldObjectOffsetInternal(const SceneFieldData& field, const UnsignedInt object, const std::size_t offset) const {
const Containers::StridedArrayView1D<const void> objects = fieldDataObjectViewInternal(field, offset, field._size - offset);
if(field._objectType == SceneObjectType::UnsignedInt)
return offset + findObject<UnsignedInt>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedShort)
return offset + findObject<UnsignedShort>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedByte)
return offset + findObject<UnsignedByte>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedLong)
return offset + findObject<UnsignedLong>(objects, object);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Optional<std::size_t> SceneData::findFieldObjectOffset(const UnsignedInt fieldId, const UnsignedInt object, const std::size_t offset) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::findFieldObjectOffset(): object" << object << "out of bounds for" << _objectCount << "objects", {});
CORRADE_ASSERT(fieldId < _fields.size(),
"Trade::SceneData::findFieldObjectOffset(): index" << fieldId << "out of range for" << _fields.size() << "fields", {});
const SceneFieldData& field = _fields[fieldId];
CORRADE_ASSERT(offset <= field._size,
"Trade::SceneData::findFieldObjectOffset(): offset" << offset << "out of bounds for a field of size" << field._size, {});
const std::size_t found = findFieldObjectOffsetInternal(field, object, offset);
return found == field._size ? Containers::Optional<std::size_t>{} : found;
}
Containers::Optional<std::size_t> SceneData::findFieldObjectOffset(const SceneField fieldName, const UnsignedInt object, const std::size_t offset) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::findFieldObjectOffset(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = findFieldIdInternal(fieldName);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::findFieldObjectOffset(): field" << fieldName << "not found", {});
const SceneFieldData& field = _fields[fieldId];
CORRADE_ASSERT(offset <= field._size,
"Trade::SceneData::findFieldObjectOffset(): offset" << offset << "out of bounds for a field of size" << field._size, {});
const std::size_t found = findFieldObjectOffsetInternal(field, object, offset);
return found == field._size ? Containers::Optional<std::size_t>{} : found;
}
std::size_t SceneData::fieldObjectOffset(const UnsignedInt fieldId, const UnsignedInt object, const std::size_t offset) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::fieldObjectOffset(): object" << object << "out of bounds for" << _objectCount << "objects", {});
CORRADE_ASSERT(fieldId < _fields.size(),
"Trade::SceneData::fieldObjectOffset(): index" << fieldId << "out of range for" << _fields.size() << "fields", {});
const SceneFieldData& field = _fields[fieldId];
CORRADE_ASSERT(offset <= field._size,
"Trade::SceneData::fieldObjectOffset(): offset" << offset << "out of bounds for a field of size" << field._size, {});
const std::size_t found = findFieldObjectOffsetInternal(field, object, offset);
CORRADE_ASSERT(found != field._size,
"Trade::SceneData::fieldObjectOffset(): object" << object << "not found in field" << field._name << "starting at offset" << offset, {});
return found;
}
std::size_t SceneData::fieldObjectOffset(const SceneField fieldName, const UnsignedInt object, const std::size_t offset) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::fieldObjectOffset(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = findFieldIdInternal(fieldName);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::fieldObjectOffset(): field" << fieldName << "not found", {});
const SceneFieldData& field = _fields[fieldId];
CORRADE_ASSERT(offset <= field._size,
"Trade::SceneData::fieldObjectOffset(): offset" << offset << "out of bounds for a field of size" << field._size, {});
const std::size_t found = findFieldObjectOffsetInternal(field, object, offset);
CORRADE_ASSERT(found != field._size,
"Trade::SceneData::fieldObjectOffset(): object" << object << "not found in field" << field._name << "starting at offset" << offset, {});
return found;
}
bool SceneData::hasFieldObject(const UnsignedInt fieldId, const UnsignedInt object) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::hasFieldObject(): object" << object << "out of bounds for" << _objectCount << "objects", {});
CORRADE_ASSERT(fieldId < _fields.size(),
"Trade::SceneData::hasFieldObject(): index" << fieldId << "out of range for" << _fields.size() << "fields", {});
const SceneFieldData& field = _fields[fieldId];
return findFieldObjectOffsetInternal(field, object, 0) != field._size;
}
bool SceneData::hasFieldObject(const SceneField fieldName, const UnsignedInt object) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::hasFieldObject(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = findFieldIdInternal(fieldName);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::hasFieldObject(): field" << fieldName << "not found", {});
const SceneFieldData& field = _fields[fieldId];
return findFieldObjectOffsetInternal(field, object, 0) != field._size;
}
SceneFieldType SceneData::fieldType(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::fieldType(): field" << name << "not found", {});
return _fields[fieldId]._fieldType;
}
std::size_t SceneData::fieldSize(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::fieldSize(): field" << name << "not found", {});
return _fields[fieldId]._size;
}
UnsignedShort SceneData::fieldArraySize(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::fieldArraySize(): field" << name << "not found", {});
return _fields[fieldId]._fieldArraySize;
}
@ -894,7 +1012,7 @@ Containers::StridedArrayView2D<char> SceneData::mutableObjects(const UnsignedInt
}
Containers::StridedArrayView2D<const char> SceneData::objects(const SceneField fieldName) const {
const UnsignedInt fieldId = fieldFor(fieldName);
const UnsignedInt fieldId = findFieldIdInternal(fieldName);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::objects(): field" << fieldName << "not found", {});
return objects(fieldId);
}
@ -902,7 +1020,7 @@ Containers::StridedArrayView2D<const char> SceneData::objects(const SceneField f
Containers::StridedArrayView2D<char> SceneData::mutableObjects(const SceneField fieldName) {
CORRADE_ASSERT(_dataFlags & DataFlag::Mutable,
"Trade::SceneData::mutableObjects(): data not mutable", {});
const UnsignedInt fieldId = fieldFor(fieldName);
const UnsignedInt fieldId = findFieldIdInternal(fieldName);
CORRADE_ASSERT(fieldId != ~UnsignedInt{}, "Trade::SceneData::mutableObjects(): field" << fieldName << "not found", {});
return mutableObjects(fieldId);
}
@ -936,7 +1054,7 @@ Containers::StridedArrayView2D<char> SceneData::mutableField(const UnsignedInt i
}
Containers::StridedArrayView2D<const char> SceneData::field(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::field(): field" << name << "not found", {});
return field(fieldId);
@ -945,7 +1063,7 @@ Containers::StridedArrayView2D<const char> SceneData::field(const SceneField nam
Containers::StridedArrayView2D<char> SceneData::mutableField(const SceneField name) {
CORRADE_ASSERT(_dataFlags & DataFlag::Mutable,
"Trade::SceneData::mutableField(): data not mutable", {});
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::mutableField(): field" << name << "not found", {});
return mutableField(fieldId);
@ -1000,21 +1118,21 @@ Containers::Array<UnsignedInt> SceneData::objectsAsArray(const UnsignedInt field
}
void SceneData::objectsInto(const SceneField name, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::objectsInto(): field" << name << "not found", );
objectsInto(fieldId, destination);
}
std::size_t SceneData::objectsInto(const SceneField name, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::objectsInto(): field" << name << "not found", {});
return objectsInto(fieldId, offset, destination);
}
Containers::Array<UnsignedInt> SceneData::objectsAsArray(const SceneField name) const {
const UnsignedInt fieldId = fieldFor(name);
const UnsignedInt fieldId = findFieldIdInternal(name);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
@ -1043,7 +1161,7 @@ void SceneData::parentsIntoInternal(const UnsignedInt fieldId, const std::size_t
}
void SceneData::parentsInto(const Containers::StridedArrayView1D<Int>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Parent);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::parentsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
@ -1052,7 +1170,7 @@ void SceneData::parentsInto(const Containers::StridedArrayView1D<Int>& destinati
}
std::size_t SceneData::parentsInto(const std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Parent);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::parentsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1063,7 +1181,7 @@ std::size_t SceneData::parentsInto(const std::size_t offset, const Containers::S
}
Containers::Array<Int> SceneData::parentsAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::Parent);
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 */
@ -1664,7 +1782,7 @@ void SceneData::meshesMaterialsIntoInternal(const UnsignedInt fieldId, const std
/* Copy also the material, if desired. If no such field is present, output
-1 for all meshes. */
if(meshMaterialDestination) {
const UnsignedInt materialFieldId = fieldFor(SceneField::MeshMaterial);
const UnsignedInt materialFieldId = findFieldIdInternal(SceneField::MeshMaterial);
if(materialFieldId == ~UnsignedInt{}) {
constexpr Int invalid[]{-1};
Utility::copy(Containers::stridedArrayView(invalid).broadcasted<0>(meshMaterialDestination.size()), meshMaterialDestination);
@ -1673,7 +1791,7 @@ void SceneData::meshesMaterialsIntoInternal(const UnsignedInt fieldId, const std
}
void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", );
CORRADE_ASSERT(!meshDestination || meshDestination.size() == _fields[fieldId]._size,
@ -1684,7 +1802,7 @@ void SceneData::meshesMaterialsInto(const Containers::StridedArrayView1D<Unsigne
}
std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& meshDestination, const Containers::StridedArrayView1D<Int>& meshMaterialDestination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Mesh);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::meshesMaterialsInto(): field" << SceneField::Mesh << "not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1699,7 +1817,7 @@ std::size_t SceneData::meshesMaterialsInto(const std::size_t offset, const Conta
}
Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::meshesMaterialsAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::Mesh);
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 */
@ -1713,7 +1831,7 @@ Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::meshesMaterials
}
void SceneData::lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Light);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::lightsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
@ -1722,7 +1840,7 @@ void SceneData::lightsInto(const Containers::StridedArrayView1D<UnsignedInt>& de
}
std::size_t SceneData::lightsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Light);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::lightsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1733,7 +1851,7 @@ std::size_t SceneData::lightsInto(const std::size_t offset, const Containers::St
}
Containers::Array<UnsignedInt> SceneData::lightsAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::Light);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
@ -1742,7 +1860,7 @@ Containers::Array<UnsignedInt> SceneData::lightsAsArray() const {
}
void SceneData::camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Camera);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::camerasInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
@ -1751,7 +1869,7 @@ void SceneData::camerasInto(const Containers::StridedArrayView1D<UnsignedInt>& d
}
std::size_t SceneData::camerasInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Camera);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::camerasInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1762,7 +1880,7 @@ std::size_t SceneData::camerasInto(const std::size_t offset, const Containers::S
}
Containers::Array<UnsignedInt> SceneData::camerasAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::Camera);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
@ -1771,7 +1889,7 @@ Containers::Array<UnsignedInt> SceneData::camerasAsArray() const {
}
void SceneData::skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Skin);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::skinsInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
@ -1780,7 +1898,7 @@ void SceneData::skinsInto(const Containers::StridedArrayView1D<UnsignedInt>& des
}
std::size_t SceneData::skinsInto(const std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::Skin);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::skinsInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1791,7 +1909,7 @@ std::size_t SceneData::skinsInto(const std::size_t offset, const Containers::Str
}
Containers::Array<UnsignedInt> SceneData::skinsAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::Skin);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
/* Using the same message as in Into() to avoid too many redundant
strings in the binary */
@ -1810,7 +1928,7 @@ void SceneData::importerStateIntoInternal(const UnsignedInt fieldId, const std::
}
void SceneData::importerStateInto(const Containers::StridedArrayView1D<const void*>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::ImporterState);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::importerStateInto(): field not found", );
CORRADE_ASSERT(destination.size() == _fields[fieldId]._size,
@ -1819,7 +1937,7 @@ void SceneData::importerStateInto(const Containers::StridedArrayView1D<const voi
}
std::size_t SceneData::importerStateInto(const std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const {
const UnsignedInt fieldId = fieldFor(SceneField::ImporterState);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
CORRADE_ASSERT(fieldId != ~UnsignedInt{},
"Trade::SceneData::importerStateInto(): field not found", {});
CORRADE_ASSERT(offset <= _fields[fieldId]._size,
@ -1830,7 +1948,7 @@ std::size_t SceneData::importerStateInto(const std::size_t offset, const Contain
}
Containers::Array<const void*> SceneData::importerStateAsArray() const {
const UnsignedInt fieldId = fieldFor(SceneField::ImporterState);
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 */
@ -1840,42 +1958,15 @@ Containers::Array<const void*> SceneData::importerStateAsArray() const {
return out;
}
namespace {
template<class T> std::size_t findObject(const Containers::StridedArrayView1D<const void>& objects, const UnsignedInt object) {
const Containers::StridedArrayView1D<const T> objectsT = Containers::arrayCast<const T>(objects);
const std::size_t max = objectsT.size();
/** @todo implement something faster than O(n) when field-specific flags
can annotate how the object mapping is done */
for(std::size_t i = 0; i != max; ++i)
if(objectsT[i] == object) return i;
return max;
}
}
std::size_t SceneData::fieldFor(const SceneFieldData& field, const std::size_t offset, const UnsignedInt object) const {
const Containers::StridedArrayView1D<const void> objects = fieldDataObjectViewInternal(field, offset, field._size - offset);
if(field._objectType == SceneObjectType::UnsignedInt)
return offset + findObject<UnsignedInt>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedShort)
return offset + findObject<UnsignedShort>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedByte)
return offset + findObject<UnsignedByte>(objects, object);
else if(field._objectType == SceneObjectType::UnsignedLong)
return offset + findObject<UnsignedLong>(objects, object);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Optional<Int> SceneData::parentFor(const UnsignedInt object) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::parentFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::Parent);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Parent);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
const std::size_t offset = fieldFor(field, 0, object);
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
Int index[1];
@ -1891,7 +1982,7 @@ Containers::Array<UnsignedInt> SceneData::childrenFor(const Int object) const {
CORRADE_ASSERT(object >= -1 && object < Long(_objectCount),
"Trade::SceneData::childrenFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt parentFieldId = fieldFor(SceneField::Parent);
const UnsignedInt parentFieldId = findFieldIdInternal(SceneField::Parent);
if(parentFieldId == ~UnsignedInt{}) return {};
const SceneFieldData& parentField = _fields[parentFieldId];
@ -1901,7 +1992,7 @@ Containers::Array<UnsignedInt> SceneData::childrenFor(const Int object) const {
Int parentIndexToLookFor;
if(object == -1) parentIndexToLookFor = -1;
else {
const std::size_t parentObjectIndex = fieldFor(parentField, 0, object);
const std::size_t parentObjectIndex = findFieldObjectOffsetInternal(parentField, object, 0);
if(parentObjectIndex == parentField._size) return {};
parentIndexToLookFor = parentObjectIndex;
}
@ -1934,8 +2025,9 @@ Containers::Optional<Matrix3> SceneData::transformation2DFor(const UnsignedInt o
is handled above. */
CORRADE_ASSERT(!is3D(), "Trade::SceneData::transformation2DFor(): scene has a 3D transformation type", {});
const std::size_t offset = fieldFor(_fields[fieldWithObjectMapping], 0, object);
if(offset == _fields[fieldWithObjectMapping]._size) return {};
const SceneFieldData& field = _fields[fieldWithObjectMapping];
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
Matrix3 transformation[1];
transformations2DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, transformation);
@ -1953,8 +2045,9 @@ Containers::Optional<Containers::Triple<Vector2, Complex, Vector2>> SceneData::t
is handled above. */
CORRADE_ASSERT(!is3D(), "Trade::SceneData::translationRotationScaling2DFor(): scene has a 3D transformation type", {});
const std::size_t offset = fieldFor(_fields[fieldWithObjectMapping], 0, object);
if(offset == _fields[fieldWithObjectMapping]._size) return {};
const SceneFieldData& field = _fields[fieldWithObjectMapping];
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
Vector2 translation[1];
Complex rotation[1];
@ -1974,8 +2067,9 @@ Containers::Optional<Matrix4> SceneData::transformation3DFor(const UnsignedInt o
is handled above. */
CORRADE_ASSERT(!is2D(), "Trade::SceneData::transformation3DFor(): scene has a 2D transformation type", {});
const std::size_t offset = fieldFor(_fields[fieldWithObjectMapping], 0, object);
if(offset == _fields[fieldWithObjectMapping]._size) return {};
const SceneFieldData& field = _fields[fieldWithObjectMapping];
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
Matrix4 transformation[1];
transformations3DIntoInternal(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, offset, transformation);
@ -1993,8 +2087,9 @@ Containers::Optional<Containers::Triple<Vector3, Quaternion, Vector3>> SceneData
is handled above. */
CORRADE_ASSERT(!is2D(), "Trade::SceneData::translationRotationScaling3DFor(): scene has a 2D transformation type", {});
const std::size_t offset = fieldFor(_fields[fieldWithObjectMapping], 0, object);
if(offset == _fields[fieldWithObjectMapping]._size) return {};
const SceneFieldData& field = _fields[fieldWithObjectMapping];
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
Vector3 translation[1];
Quaternion rotation[1];
@ -2007,14 +2102,14 @@ Containers::Array<Containers::Pair<UnsignedInt, Int>> SceneData::meshesMaterials
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::meshesMaterialsFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt meshFieldId = fieldFor(SceneField::Mesh);
const UnsignedInt meshFieldId = findFieldIdInternal(SceneField::Mesh);
if(meshFieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[meshFieldId];
Containers::Array<Containers::Pair<UnsignedInt, Int>> out;
std::size_t offset = 0;
for(;;) {
offset = fieldFor(field, offset, object);
offset = findFieldObjectOffsetInternal(field, object, offset);
if(offset == field._size) break;
UnsignedInt mesh[1];
@ -2031,14 +2126,14 @@ Containers::Array<UnsignedInt> SceneData::lightsFor(const UnsignedInt object) co
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::lightsFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::Light);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Light);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
Containers::Array<UnsignedInt> out;
std::size_t offset = 0;
for(;;) {
offset = fieldFor(field, offset, object);
offset = findFieldObjectOffsetInternal(field, object, offset);
if(offset == field._size) break;
UnsignedInt index[1];
@ -2054,14 +2149,14 @@ Containers::Array<UnsignedInt> SceneData::camerasFor(const UnsignedInt object) c
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::camerasFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::Camera);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Camera);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
Containers::Array<UnsignedInt> out;
std::size_t offset = 0;
for(;;) {
offset = fieldFor(field, offset, object);
offset = findFieldObjectOffsetInternal(field, object, offset);
if(offset == field._size) break;
UnsignedInt index[1];
@ -2077,14 +2172,14 @@ Containers::Array<UnsignedInt> SceneData::skinsFor(const UnsignedInt object) con
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::skinsFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::Skin);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::Skin);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
Containers::Array<UnsignedInt> out;
std::size_t offset = 0;
for(;;) {
offset = fieldFor(field, offset, object);
offset = findFieldObjectOffsetInternal(field, object, offset);
if(offset == field._size) break;
UnsignedInt index[1];
@ -2100,11 +2195,11 @@ Containers::Optional<const void*> SceneData::importerStateFor(const UnsignedInt
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::importerStateFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::ImporterState);
const UnsignedInt fieldId = findFieldIdInternal(SceneField::ImporterState);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
const std::size_t offset = fieldFor(field, 0, object);
const std::size_t offset = findFieldObjectOffsetInternal(field, object, 0);
if(offset == field._size) return {};
const void* importerState[1];

299
src/Magnum/Trade/SceneData.h

@ -1080,22 +1080,112 @@ class MAGNUM_TRADE_EXPORT SceneData {
bool is3D() const { return _dimensions == 3; }
/**
* @brief Whether the scene has given field
* @brief Find an absolute ID of a named field
* @m_since_latest
*
* @see @ref is2D(), @ref is3D()
* If @p name doesn't exist, returns @ref Containers::NullOpt. The
* lookup is done in an @f$ \mathcal{O}(n) @f$ complexity with
* @f$ n @f$ being the field count.
* @see @ref hasField(), @ref fieldId()
*/
bool hasField(SceneField name) const;
Containers::Optional<UnsignedInt> findFieldId(SceneField name) const;
/**
* @brief Absolute ID of a named field
* @m_since_latest
*
* The @p name is expected to exist.
* Like @ref findFieldId(), but the @p name is expected to exist.
* @see @ref hasField(), @ref fieldName(UnsignedInt) const
*/
UnsignedInt fieldId(SceneField name) const;
/**
* @brief Whether the scene has given field
* @m_since_latest
*
* @see @ref is2D(), @ref is3D()
*/
bool hasField(SceneField name) const;
/**
* @brief Find offset of an object in given field
* @m_since_latest
*
* If @p object isn't present in @p fieldId starting at @p offset,
* returns @ref Containers::NullOpt. The @p fieldId is expected to be
* smaller than @ref fieldCount(), @p object smaller than
* @ref objectCount() and @p offset not larger than
* @ref fieldSize(UnsignedInt) const.
*
* The lookup is done in an @f$ \mathcal{O}(n) @f$ complexity with
* @f$ n @f$ being the size of the field.
*
* You can also use @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* to directly find offset of an object in given named field.
* @see @ref hasFieldObject(UnsignedInt, UnsignedInt) const,
* @ref fieldObjectOffset(UnsignedInt, UnsignedInt, std::size_t) const
*/
Containers::Optional<std::size_t> findFieldObjectOffset(UnsignedInt fieldId, UnsignedInt object, std::size_t offset = 0) const;
/**
* @brief Find offset of an object in given named field
* @m_since_latest
*
* If @p object isn't present in @p fieldName starting at @p offset,
* returns @ref Containers::NullOpt. The @p fieldName is expected to
* exist, @p object is expected to be smaller than @ref objectCount()
* and @p offset not be larger than @ref fieldSize(SceneField) const.
*
* The lookup is done in an @f$ \mathcal{O}(m + n) @f$ complexity with
* @f$ m @f$ being the field count and @f$ n @f$ the size of the field.
*
* @see @ref hasField(), @ref hasFieldObject(SceneField, UnsignedInt) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
Containers::Optional<std::size_t> findFieldObjectOffset(SceneField fieldName, UnsignedInt object, std::size_t offset = 0) const;
/**
* @brief Offset of an object in given field
* @m_since_latest
*
* Like @ref findFieldObjectOffset(UnsignedInt, UnsignedInt, std::size_t) const,
* but @p object is additionally expected to be present in @p fieldId
* starting at @p offset.
*
* You can also use @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* to directly get offset of an object in given named field.
*/
std::size_t fieldObjectOffset(UnsignedInt fieldId, UnsignedInt object, std::size_t offset = 0) const;
/**
* @brief Offset of an object in given named field
* @m_since_latest
*
* Like @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const,
* but @p object is additionally expected to be present in @p fieldName
* starting at @p offset.
*/
std::size_t fieldObjectOffset(SceneField fieldName, UnsignedInt object, std::size_t offset = 0) const;
/**
* @brief Whether a scene field has given object
* @m_since_latest
*
* The @p fieldId is expected to be smaller than @ref fieldCount() and
* @p object smaller than @ref objectCount().
*/
bool hasFieldObject(UnsignedInt fieldId, UnsignedInt object) const;
/**
* @brief Whether a named scene field has given object
* @m_since_latest
*
* The @p fieldName is expected to exist and @p object is expected to
* be smaller than @ref objectCount().
* @see @ref hasField()
*/
bool hasFieldObject(SceneField fieldName, UnsignedInt object) const;
/**
* @brief Type of a named field
* @m_since_latest
@ -1416,7 +1506,8 @@ 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.
* @see @ref fieldSize(UnsignedInt) const
* @see @ref fieldSize(UnsignedInt) const,
* @ref fieldObjectOffset(UnsignedInt, UnsignedInt, std::size_t) const
*/
std::size_t objectsInto(UnsignedInt fieldId, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1458,7 +1549,8 @@ 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.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t objectsInto(SceneField fieldName, std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1500,7 +1592,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t parentsInto(std::size_t offset, const Containers::StridedArrayView1D<Int>& destination) const;
@ -1543,7 +1636,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t transformations2DInto(std::size_t offset, const Containers::StridedArrayView1D<Matrix3>& destination) const;
@ -1592,7 +1686,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* 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
* @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;
@ -1635,7 +1730,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t transformations3DInto(std::size_t offset, const Containers::StridedArrayView1D<Matrix4>& destination) const;
@ -1684,7 +1780,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* 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
* @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;
@ -1725,7 +1822,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* 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
* @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;
@ -1761,7 +1859,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t lightsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1797,7 +1896,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t camerasInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1833,7 +1933,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t skinsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) const;
@ -1872,7 +1973,8 @@ class MAGNUM_TRADE_EXPORT SceneData {
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
* @see @ref fieldSize(SceneField) const,
* @ref fieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
*/
std::size_t importerStateInto(std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const;
@ -1880,12 +1982,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Parent for given object
* @m_since_latest
*
* Looks up the @ref SceneField::Parent field for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the parent field,
* thus for retrieving parent info for many objects it's recommended to
* access the field data directly with @ref parentsAsArray() and
* related APIs.
* Looks up the @ref SceneField::Parent field for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref parentsAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving parent
* info for many objects it's recommended to access the field data
* directly.
*
* If the @ref SceneField::Parent field is not present or if there's no
* parent for @p object, returns @ref Containers::NullOpt. If @p object
@ -1901,13 +2004,12 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @m_since_latest
*
* Looks up @p object in the object mapping array for
* @ref SceneField::Parent and returns a list of all object IDs that
* have it listed as the parent. The lookup is done in an
* @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$ being the field
* count and @f$ n @f$ the size of the parent field, thus for
* retrieving parent/child info for many objects it's recommended to
* access the field data directly with @ref parentsAsArray() and
* related APIs.
* @ref SceneField::Parent equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const,
* converts the fields from an arbitrary underlying type the same way
* as @ref parentsAsArray(), returning a list of all object IDs that
* have it listed as the parent. See the lookup function documentation
* for operation complexity --- for retrieving parent/child info for
* many objects it's recommended to access the field data directly.
*
* If the @ref SceneField::Parent field doesn't exist or there are no
* objects which would have @p object listed as their parent, returns
@ -1922,16 +2024,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief 2D transformation for given object
* @m_since_latest
*
* Looks up the @ref SceneField::Transformation field for @p object or
* combines it from a @ref SceneField::Translation,
* Looks up the @ref SceneField::Transformation field for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* or combines it from a @ref SceneField::Translation,
* @relativeref{SceneField,Rotation} and
* @relativeref{SceneField,Scaling} in the same way as
* @ref transformations2DAsArray(). The lookup is done in an
* @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$ being the field
* count and @f$ n @f$ the size of the transformation field, thus for
* retrieving transformation info for many objects it's recommended to
* access the field data directly with @ref transformations2DAsArray()
* and related APIs.
* @relativeref{SceneField,Scaling}, converting the fields from
* arbitrary underlying types the same way as
* @ref transformations2DAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving
* transformation info for many objects it's recommended to access the
* field data directly.
*
* If neither @ref SceneField::Transformation nor any of
* @ref SceneField::Translation, @relativeref{SceneField,Rotation} or
@ -1950,12 +2052,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
*
* Looks up the @ref SceneField::Translation,
* @relativeref{SceneField,Rotation} and
* @relativeref{SceneField,Scaling} fields for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the transformation
* field, thus for retrieving transformation info for many objects it's
* recommended to access the field data directly with
* @ref translationsRotationsScalings2DAsArray() and related APIs.
* @relativeref{SceneField,Scaling} fields for @p object equivalently
* to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the fields from arbitrary underlying types the
* same way as @ref translationsRotationsScalings2DAsArray(). See the
* lookup function documentation for operation complexity --- for
* retrieving transformation info for many objects it's recommended to
* access the field data directly.
*
* If the @ref SceneField::Translation field isn't present, the first
* returned value is a zero vector. If the
@ -1976,16 +2079,16 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief 3D transformation for given object
* @m_since_latest
*
* Looks up the @ref SceneField::Transformation field for @p object or
* combines it from a @ref SceneField::Translation,
* Looks up the @ref SceneField::Transformation field for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* or combines it from a @ref SceneField::Translation,
* @relativeref{SceneField,Rotation} and
* @relativeref{SceneField,Scaling} in the same way as
* @ref transformations3DAsArray(). The lookup is done in an
* @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$ being the field
* count and @f$ n @f$ the size of the transformation field, thus for
* retrieving transformation info for many objects it's recommended to
* access the field data directly with @ref transformations3DAsArray()
* and related APIs.
* @relativeref{SceneField,Scaling}, converting the fields from
* arbitrary underlying types the same way as
* @ref transformations3DAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving
* transformation info for many objects it's recommended to access the
* field data directly.
*
* If neither @ref SceneField::Transformation nor any of
* @ref SceneField::Translation, @relativeref{SceneField,Rotation} or
@ -2004,12 +2107,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
*
* Looks up the @ref SceneField::Translation,
* @relativeref{SceneField,Rotation} and
* @relativeref{SceneField,Scaling} fields for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the transformation
* field, thus for retrieving transformation info for many objects it's
* recommended to access the field data directly with
* @ref translationsRotationsScalings3DAsArray() and related APIs.
* @relativeref{SceneField,Scaling} fields for @p object equivalently
* to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the fields from arbitrary underlying types the
* same way as @ref translationsRotationsScalings2DAsArray(). See the
* lookup function documentation for operation complexity --- for
* retrieving transformation info for many objects it's recommended to
* access the field data directly.
*
* If the @ref SceneField::Translation field isn't present, the first
* returned value is a zero vector. If the
@ -2031,12 +2135,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @m_since_latest
*
* Looks up all @ref SceneField::Mesh and @ref SceneField::MeshMaterial
* @relativeref{SceneField,Scaling} fields for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the mesh field, thus
* for retrieving mesh info for many objects it's recommended to access
* the field data directly with @ref meshesMaterialsAsArray() and
* related APIs.
* @relativeref{SceneField,Scaling} fields for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref meshesMaterialsAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving mesh and
* material info for many objects it's recommended to access the field
* data directly.
*
* If the @ref SceneField::MeshMaterial field is not present, the
* second returned value is always @cpp -1 @ce. If
@ -2051,12 +2156,12 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Lights for given object
* @m_since_latest
*
* Looks up all @ref SceneField::Light fields for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the light field,
* thus for retrieving light info for many objects it's recommended to
* access the field data directly with @ref lightsAsArray() and related
* APIs.
* Looks up all @ref SceneField::Light fields for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref lightsAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving light info
* for many objects it's recommended to access the field data directly.
*
* If the @ref SceneField::Light field is not present or if there's no
* light for @p object, returns an empty array.
@ -2069,12 +2174,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Cameras for given object
* @m_since_latest
*
* Looks up all @ref SceneField::Camera fields for @p object. The
* lookup is done in an @f$ \mathcal{O}(m + n) @f$ complexity with
* @f$ m @f$ being the field count and @f$ n @f$ the size of the camera
* field, thus for retrieving camera info for many objects it's
* recommended to access the field data directly with
* @ref camerasAsArray() and related APIs.
* Looks up all @ref SceneField::Camera fields for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref camerasAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving camera
* info for many objects it's recommended to access the field data
* directly.
*
* If the @ref SceneField::Camera field is not present or if there's no
* camera for @p object, returns an empty array.
@ -2087,11 +2193,12 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Skins for given object
* @m_since_latest
*
* Looks up all @ref SceneField::Skin fields for @p object. The lookup
* is done in an @f$ \mathcal{O}(m + n) @f$ complexity with @f$ m @f$
* being the field count and @f$ n @f$ the size of the skin field, thus
* for retrieving skin info for many objects it's recommended to access
* the field data directly with @ref skinsAsArray() and related APIs.
* Looks up all @ref SceneField::Skin fields for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref skinsAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving skin info
* for many objects it's recommended to access the field data directly.
*
* If the @ref SceneField::Skin field is not present or if there's no
* skin for @p object, returns an empty array.
@ -2104,12 +2211,13 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @brief Importer state for given object
* @m_since_latest
*
* Looks up the @ref SceneField::ImporterState field for @p object. The
* lookup is done in a @f$ \mathcal{O}(m + n) @f$ complexity with
* @f$ m @f$ being the field count and @f$ n @f$ the size of the
* importer state field, thus for retrieving importer state info for
* many objects it's recommended to access the field data directly with
* @ref importerStateAsArray() and related APIs.
* Looks up the @ref SceneField::ImporterState field for @p object
* equivalently to @ref findFieldObjectOffset(SceneField, UnsignedInt, std::size_t) const
* and then converts the field from an arbitrary underlying type the
* same way as @ref importerStateAsArray(). See the lookup function
* documentation for operation complexity --- for retrieving importer
* state info for many objects it's recommended to access the field
* data directly.
*
* If the @ref SceneField::ImporterState field is not present or if
* there's no importer state for @p object, returns
@ -2187,13 +2295,14 @@ class MAGNUM_TRADE_EXPORT SceneData {
implementations. */
friend AbstractImporter;
/* Internal helper that doesn't assert, unlike fieldId() */
UnsignedInt fieldFor(SceneField name) const;
/* Internal helper without the extra overhead from Optional, returns
~UnsignedInt{} on failure */
UnsignedInt findFieldIdInternal(SceneField name) const;
/* Returns the offset at which `object` is for field at index `id`, or
the end offset if the object is not found. The returned offset can
be then passed to fieldData{Object,Field}ViewInternal(). */
std::size_t fieldFor(const SceneFieldData& field, std::size_t offset, UnsignedInt object) const;
std::size_t findFieldObjectOffsetInternal(const SceneFieldData& field, UnsignedInt object, std::size_t offset) const;
/* Like objects() / field(), but returning just a 1D view, sliced from
offset to offset + size. The parameterless overloads are equal to
@ -2566,7 +2675,7 @@ template<class T, class> Containers::StridedArrayView1D<const T> SceneData::fiel
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
if(!checkFieldTypeCompatibility<T>(_fields[fieldFor(name)], "Trade::SceneData::field():")) return {};
if(!checkFieldTypeCompatibility<T>(_fields[findFieldIdInternal(name)], "Trade::SceneData::field():")) return {};
#endif
return Containers::arrayCast<1, const T>(data);
}
@ -2577,7 +2686,7 @@ template<class T, class> Containers::StridedArrayView2D<const typename std::remo
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
if(!checkFieldTypeCompatibility<T>(_fields[fieldFor(name)], "Trade::SceneData::field():")) return {};
if(!checkFieldTypeCompatibility<T>(_fields[findFieldIdInternal(name)], "Trade::SceneData::field():")) return {};
#endif
return Containers::arrayCast<2, const typename std::remove_extent<T>::type>(data);
}
@ -2588,7 +2697,7 @@ template<class T, class> Containers::StridedArrayView1D<T> SceneData::mutableFie
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
if(!checkFieldTypeCompatibility<T>(_fields[fieldFor(name)], "Trade::SceneData::mutableField():")) return {};
if(!checkFieldTypeCompatibility<T>(_fields[findFieldIdInternal(name)], "Trade::SceneData::mutableField():")) return {};
#endif
return Containers::arrayCast<1, T>(data);
}
@ -2599,7 +2708,7 @@ template<class T, class> Containers::StridedArrayView2D<typename std::remove_ext
if(!data.stride()[1]) return {};
#endif
#ifndef CORRADE_NO_ASSERT
if(!checkFieldTypeCompatibility<T>(_fields[fieldFor(name)], "Trade::SceneData::mutableField():")) return {};
if(!checkFieldTypeCompatibility<T>(_fields[findFieldIdInternal(name)], "Trade::SceneData::mutableField():")) return {};
#endif
return Containers::arrayCast<2, typename std::remove_extent<T>::type>(data);
}

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

@ -111,6 +111,11 @@ struct SceneDataTest: TestSuite::Tester {
void constructCopy();
void constructMove();
void findFieldId();
template<class T> void findFieldObjectOffset();
void findFieldObjectOffsetInvalidOffset();
void fieldObjectOffsetNotFound();
template<class T> void objectsAsArrayByIndex();
template<class T> void objectsAsArrayByName();
void objectsAsArrayLongType();
@ -163,9 +168,7 @@ struct SceneDataTest: TestSuite::Tester {
void fieldWrongPointerType();
void fieldWrongArrayAccess();
/* Different object types checked just for the parentFor(), other APIs
use the same helper */
template<class T> void parentFor();
void parentFor();
void childrenFor();
void transformation2DFor();
void transformation2DForTRS();
@ -184,7 +187,7 @@ struct SceneDataTest: TestSuite::Tester {
#endif
void fieldForFieldMissing();
void fieldForInvalidObject();
void findFieldObjectOffsetInvalidObject();
void releaseFieldData();
void releaseData();
@ -290,6 +293,14 @@ SceneDataTest::SceneDataTest() {
&SceneDataTest::constructCopy,
&SceneDataTest::constructMove,
&SceneDataTest::findFieldId,
&SceneDataTest::findFieldObjectOffset<UnsignedByte>,
&SceneDataTest::findFieldObjectOffset<UnsignedShort>,
&SceneDataTest::findFieldObjectOffset<UnsignedInt>,
&SceneDataTest::findFieldObjectOffset<UnsignedLong>,
&SceneDataTest::findFieldObjectOffsetInvalidOffset,
&SceneDataTest::fieldObjectOffsetNotFound,
&SceneDataTest::objectsAsArrayByIndex<UnsignedByte>,
&SceneDataTest::objectsAsArrayByIndex<UnsignedShort>,
&SceneDataTest::objectsAsArrayByIndex<UnsignedInt>,
@ -396,10 +407,7 @@ SceneDataTest::SceneDataTest() {
&SceneDataTest::fieldWrongPointerType,
&SceneDataTest::fieldWrongArrayAccess,
&SceneDataTest::parentFor<UnsignedByte>,
&SceneDataTest::parentFor<UnsignedShort>,
&SceneDataTest::parentFor<UnsignedInt>,
&SceneDataTest::parentFor<UnsignedLong>,
&SceneDataTest::parentFor,
&SceneDataTest::childrenFor,
&SceneDataTest::transformation2DFor,
&SceneDataTest::transformation2DForTRS,
@ -419,7 +427,7 @@ SceneDataTest::SceneDataTest() {
#endif
addTests({&SceneDataTest::fieldForFieldMissing,
&SceneDataTest::fieldForInvalidObject,
&SceneDataTest::findFieldObjectOffsetInvalidObject,
&SceneDataTest::releaseFieldData,
&SceneDataTest::releaseData});
@ -1298,15 +1306,6 @@ void SceneDataTest::construct() {
CORRADE_COMPARE(scene.mutableField<Float[]>(3)[0][1], 1.5f);
/* Field property access by name */
CORRADE_COMPARE(scene.fieldId(SceneField::Transformation), 0);
CORRADE_COMPARE(scene.fieldId(SceneField::Parent), 1);
CORRADE_COMPARE(scene.fieldId(SceneField::Mesh), 2);
CORRADE_COMPARE(scene.fieldId(sceneFieldCustom(37)), 3);
CORRADE_VERIFY(scene.hasField(SceneField::Transformation));
CORRADE_VERIFY(scene.hasField(SceneField::Parent));
CORRADE_VERIFY(scene.hasField(SceneField::Mesh));
CORRADE_VERIFY(scene.hasField(sceneFieldCustom(37)));
CORRADE_VERIFY(!scene.hasField(SceneField::Skin));
CORRADE_COMPARE(scene.fieldType(SceneField::Transformation), SceneFieldType::Matrix4x4);
CORRADE_COMPARE(scene.fieldType(SceneField::Parent), SceneFieldType::Int);
CORRADE_COMPARE(scene.fieldType(SceneField::Mesh), SceneFieldType::UnsignedByte);
@ -1957,6 +1956,151 @@ void SceneDataTest::constructMove() {
CORRADE_VERIFY(std::is_nothrow_move_assignable<SceneData>::value);
}
void SceneDataTest::findFieldId() {
SceneData scene{SceneObjectType::UnsignedInt, 0, {}, nullptr, {
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::Mesh, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::UnsignedByte, nullptr}
}};
CORRADE_COMPARE(scene.findFieldId(SceneField::Parent), 0);
CORRADE_COMPARE(scene.findFieldId(SceneField::Mesh), 1);
CORRADE_COMPARE(scene.findFieldId(SceneField::MeshMaterial), Containers::NullOpt);
CORRADE_COMPARE(scene.fieldId(SceneField::Parent), 0);
CORRADE_COMPARE(scene.fieldId(SceneField::Mesh), 1);
CORRADE_VERIFY(scene.hasField(SceneField::Parent));
CORRADE_VERIFY(scene.hasField(SceneField::Mesh));
CORRADE_VERIFY(!scene.hasField(SceneField::MeshMaterial));
}
template<class T> void SceneDataTest::findFieldObjectOffset() {
setTestCaseTemplateName(NameTraits<T>::name());
/** @todo update once field flags describing object order are present */
struct Field {
T object;
UnsignedInt mesh;
} fields[]{
{4, 1},
{1, 3},
{2, 4},
{0, 5},
{2, 5}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{Implementation::sceneObjectTypeFor<T>(), 7, {}, fields, {
/* Test also with a completely empty field */
SceneFieldData{SceneField::Parent, Implementation::sceneObjectTypeFor<T>(), nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)}
}};
CORRADE_COMPARE(scene.findFieldObjectOffset(0, 4), Containers::NullOpt);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Parent, 4), Containers::NullOpt);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 4), 0);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 1), 1);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 2), 2);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 2, 3), 4);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 2, 5), Containers::NullOpt);
CORRADE_COMPARE(scene.findFieldObjectOffset(1, 3), Containers::NullOpt);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 4), 0);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 1), 1);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 2), 2);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 2, 3), 4);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 2, 5), Containers::NullOpt);
CORRADE_COMPARE(scene.findFieldObjectOffset(SceneField::Mesh, 3), Containers::NullOpt);
CORRADE_COMPARE(scene.fieldObjectOffset(1, 4), 0);
CORRADE_COMPARE(scene.fieldObjectOffset(1, 1), 1);
CORRADE_COMPARE(scene.fieldObjectOffset(1, 2), 2);
CORRADE_COMPARE(scene.fieldObjectOffset(1, 2, 3), 4);
CORRADE_COMPARE(scene.fieldObjectOffset(SceneField::Mesh, 4), 0);
CORRADE_COMPARE(scene.fieldObjectOffset(SceneField::Mesh, 1), 1);
CORRADE_COMPARE(scene.fieldObjectOffset(SceneField::Mesh, 2), 2);
CORRADE_COMPARE(scene.fieldObjectOffset(SceneField::Mesh, 2, 3), 4);
CORRADE_VERIFY(!scene.hasFieldObject(0, 4));
CORRADE_VERIFY(!scene.hasFieldObject(SceneField::Parent, 4));
CORRADE_VERIFY(scene.hasFieldObject(1, 4));
CORRADE_VERIFY(scene.hasFieldObject(1, 1));
CORRADE_VERIFY(scene.hasFieldObject(1, 2));
CORRADE_VERIFY(!scene.hasFieldObject(1, 3));
CORRADE_VERIFY(scene.hasFieldObject(SceneField::Mesh, 4));
CORRADE_VERIFY(scene.hasFieldObject(SceneField::Mesh, 1));
CORRADE_VERIFY(scene.hasFieldObject(SceneField::Mesh, 2));
CORRADE_VERIFY(!scene.hasFieldObject(SceneField::Mesh, 3));
}
void SceneDataTest::findFieldObjectOffsetInvalidOffset() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct Field {
UnsignedInt object;
UnsignedInt mesh;
} fields[]{
{4, 1},
{1, 3},
{2, 4}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 7, {}, fields, {
SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)}
}};
std::ostringstream out;
Error redirectError{&out};
scene.findFieldObjectOffset(0, 1, 4);
scene.findFieldObjectOffset(SceneField::Mesh, 1, 4);
scene.fieldObjectOffset(0, 1, 4);
scene.fieldObjectOffset(SceneField::Mesh, 1, 4);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::findFieldObjectOffset(): offset 4 out of bounds for a field of size 3\n"
"Trade::SceneData::findFieldObjectOffset(): offset 4 out of bounds for a field of size 3\n"
"Trade::SceneData::fieldObjectOffset(): offset 4 out of bounds for a field of size 3\n"
"Trade::SceneData::fieldObjectOffset(): offset 4 out of bounds for a field of size 3\n");
}
void SceneDataTest::fieldObjectOffsetNotFound() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct Field {
UnsignedInt object;
UnsignedInt mesh;
} fields[]{
{4, 1},
{1, 3},
{2, 4},
{0, 5},
{2, 5}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 7, {}, fields, {
/* Test also with a completely empty field */
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::Mesh, view.slice(&Field::object), view.slice(&Field::mesh)}
}};
std::ostringstream out;
Error redirectError{&out};
scene.fieldObjectOffset(0, 4);
scene.fieldObjectOffset(SceneField::Parent, 4);
scene.fieldObjectOffset(1, 1, 2);
scene.fieldObjectOffset(SceneField::Mesh, 1, 2);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::fieldObjectOffset(): object 4 not found in field Trade::SceneField::Parent starting at offset 0\n"
"Trade::SceneData::fieldObjectOffset(): object 4 not found in field Trade::SceneField::Parent starting at offset 0\n"
"Trade::SceneData::fieldObjectOffset(): object 1 not found in field Trade::SceneField::Mesh starting at offset 2\n"
"Trade::SceneData::fieldObjectOffset(): object 1 not found in field Trade::SceneField::Mesh starting at offset 2\n");
}
template<class T> void SceneDataTest::objectsAsArrayByIndex() {
setTestCaseTemplateName(NameTraits<T>::name());
@ -4108,6 +4252,9 @@ void SceneDataTest::fieldNotFound() {
std::ostringstream out;
Error redirectError{&out};
scene.findFieldObjectOffset(2, 0);
scene.fieldObjectOffset(2, 0);
scene.hasFieldObject(2, 0);
scene.fieldData(2);
scene.fieldName(2);
scene.fieldType(2);
@ -4121,6 +4268,9 @@ void SceneDataTest::fieldNotFound() {
scene.mutableField<UnsignedInt[]>(2);
scene.fieldId(sceneFieldCustom(666));
scene.findFieldObjectOffset(sceneFieldCustom(666), 0);
scene.fieldObjectOffset(sceneFieldCustom(666), 0);
scene.hasFieldObject(sceneFieldCustom(666), 0);
scene.fieldType(sceneFieldCustom(666));
scene.fieldSize(sceneFieldCustom(666));
scene.fieldArraySize(sceneFieldCustom(666));
@ -4162,6 +4312,9 @@ void SceneDataTest::fieldNotFound() {
scene.importerStateInto(nullptr);
scene.importerStateInto(0, nullptr);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::findFieldObjectOffset(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldObjectOffset(): index 2 out of range for 2 fields\n"
"Trade::SceneData::hasFieldObject(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldData(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldName(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldType(): index 2 out of range for 2 fields\n"
@ -4175,6 +4328,9 @@ void SceneDataTest::fieldNotFound() {
"Trade::SceneData::mutableField(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldId(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::findFieldObjectOffset(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::fieldObjectOffset(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::hasFieldObject(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::fieldType(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::fieldSize(): field Trade::SceneField::Custom(666) not found\n"
"Trade::SceneData::fieldArraySize(): field Trade::SceneField::Custom(666) not found\n"
@ -4370,11 +4526,9 @@ void SceneDataTest::fieldWrongArrayAccess() {
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is an array field, use T[] to access it\n");
}
template<class T> void SceneDataTest::parentFor() {
setTestCaseTemplateName(NameTraits<T>::name());
void SceneDataTest::parentFor() {
struct Field {
T object;
UnsignedInt object;
Int parent;
} fields[]{
{3, -1},
@ -4384,7 +4538,7 @@ template<class T> void SceneDataTest::parentFor() {
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{Implementation::sceneObjectTypeFor<T>(), 7, {}, fields, {
SceneData scene{SceneObjectType::UnsignedInt, 7, {}, fields, {
SceneFieldData{SceneField::Parent, view.slice(&Field::object), view.slice(&Field::parent)}
}};
@ -4867,15 +5021,23 @@ void SceneDataTest::fieldForFieldMissing() {
TestSuite::Compare::Container);
}
void SceneDataTest::fieldForInvalidObject() {
void SceneDataTest::findFieldObjectOffsetInvalidObject() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
SceneData scene{SceneObjectType::UnsignedInt, 7, nullptr, {}};
SceneData scene{SceneObjectType::UnsignedInt, 7, nullptr, {
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr},
}};
std::ostringstream out;
Error redirectError{&out};
scene.findFieldObjectOffset(0, 7);
scene.findFieldObjectOffset(SceneField::Parent, 7);
scene.fieldObjectOffset(0, 7);
scene.fieldObjectOffset(SceneField::Parent, 7);
scene.hasFieldObject(0, 7);
scene.hasFieldObject(SceneField::Parent, 7);
scene.parentFor(7);
scene.childrenFor(-2);
scene.childrenFor(7);
@ -4888,6 +5050,12 @@ void SceneDataTest::fieldForInvalidObject() {
scene.camerasFor(7);
scene.skinsFor(7);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::findFieldObjectOffset(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::findFieldObjectOffset(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::fieldObjectOffset(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::fieldObjectOffset(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::hasFieldObject(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::hasFieldObject(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::parentFor(): object 7 out of bounds for 7 objects\n"
"Trade::SceneData::childrenFor(): object -2 out of bounds for 7 objects\n"
"Trade::SceneData::childrenFor(): object 7 out of bounds for 7 objects\n"

Loading…
Cancel
Save