Browse Source

Trade: support storing pointers (and thus importer state) in SceneData.

pull/525/head
Vladimír Vondruš 5 years ago
parent
commit
f734094109
  1. 65
      src/Magnum/Trade/SceneData.cpp
  2. 120
      src/Magnum/Trade/SceneData.h
  3. 232
      src/Magnum/Trade/Test/SceneDataTest.cpp

65
src/Magnum/Trade/SceneData.cpp

@ -95,6 +95,7 @@ Debug& operator<<(Debug& debug, const SceneField value) {
_c(Light)
_c(Camera)
_c(Skin)
_c(ImporterState)
#undef _c
/* LCOV_EXCL_STOP */
@ -202,6 +203,8 @@ Debug& operator<<(Debug& debug, const SceneFieldType value) {
_c(Rad)
_c(Radh)
_c(Radd)
_c(Pointer)
_c(MutablePointer)
#undef _c
/* LCOV_EXCL_STOP */
}
@ -323,6 +326,9 @@ UnsignedInt sceneFieldTypeSize(const SceneFieldType type) {
return 96;
case SceneFieldType::Matrix4x4d:
return 128;
case SceneFieldType::Pointer:
case SceneFieldType::MutablePointer:
return sizeof(void*);
}
#ifdef CORRADE_TARGET_GCC
#pragma GCC diagnostic pop
@ -368,7 +374,7 @@ SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong object
#ifndef CORRADE_NO_ASSERT
/* Check various assumptions about field data */
Math::BoolVector<11> fieldsPresent; /** @todo some constant for this */
Math::BoolVector<12> fieldsPresent; /** @todo some constant for this */
const UnsignedInt objectTypeSize = sceneObjectTypeSize(_objectType);
UnsignedInt translationField = ~UnsignedInt{};
UnsignedInt rotationField = ~UnsignedInt{};
@ -1561,6 +1567,47 @@ Containers::Array<UnsignedInt> SceneData::skinsAsArray() const {
return unsignedIndexFieldAsArrayInternal(fieldId);
}
void SceneData::importerStateIntoInternal(const UnsignedInt fieldId, const std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const {
/* fieldId, offset and destination.size() is assumed to be in bounds,
checked by the callers */
const SceneFieldData& field = _fields[fieldId];
CORRADE_INTERNAL_ASSERT(field._fieldType == SceneFieldType::Pointer ||
field._fieldType == SceneFieldType::MutablePointer);
Utility::copy(Containers::arrayCast<const void* const>(fieldDataFieldViewInternal(field, offset, destination.size())), destination);
}
void SceneData::importerStateInto(const Containers::StridedArrayView1D<const void*>& destination) const {
const UnsignedInt fieldId = fieldFor(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);
}
std::size_t SceneData::importerStateInto(const std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const {
const UnsignedInt fieldId = fieldFor(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));
return size;
}
Containers::Array<const void*> SceneData::importerStateAsArray() const {
const UnsignedInt fieldId = fieldFor(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);
return out;
}
namespace {
template<class T> std::size_t findObject(const Containers::StridedArrayView1D<const void>& objects, const UnsignedInt object) {
@ -1917,6 +1964,22 @@ Containers::Array<UnsignedInt> SceneData::skinsFor(const UnsignedInt object) con
return out;
}
Containers::Optional<const void*> SceneData::importerStateFor(const UnsignedInt object) const {
CORRADE_ASSERT(object < _objectCount,
"Trade::SceneData::importerStateFor(): object" << object << "out of bounds for" << _objectCount << "objects", {});
const UnsignedInt fieldId = fieldFor(SceneField::ImporterState);
if(fieldId == ~UnsignedInt{}) return {};
const SceneFieldData& field = _fields[fieldId];
const std::size_t offset = fieldFor(field, 0, object);
if(offset == field._size) return {};
const void* importerState[1];
importerStateIntoInternal(fieldId, offset, importerState);
return *importerState;
}
Containers::Array<SceneFieldData> SceneData::releaseFieldData() {
Containers::Array<SceneFieldData> out = std::move(_fields);
_fields = {};

120
src/Magnum/Trade/SceneData.h

@ -273,6 +273,18 @@ enum class SceneField: UnsignedInt {
*/
Skin,
/**
* Importer state for given object, per-object counterpart to
* scene-specific @ref SceneData::importerState(). Type is usually
* @ref SceneFieldType::Pointer but can be also
* @ref SceneFieldType::MutablePointer. An object should have only one
* importer state, altough this isn't enforced in any way, and which of the
* duplicate fields gets used is not defined.
* @see @ref SceneData::importerStateAsArray(),
* @ref SceneData::importerStateFor()
*/
ImporterState,
/**
* This and all higher values are for importer-specific fields. Can be
* of any type. See documentation of a particular importer for details.
@ -455,7 +467,21 @@ enum class SceneFieldType: UnsignedShort {
Degd, /**< @relativeref{Magnum,Degh} */
Rad, /**< @relativeref{Magnum,Rad} */
Radh, /**< @relativeref{Magnum,Radh} */
Radd /**< @relativeref{Magnum,Radd} */
Radd, /**< @relativeref{Magnum,Radd} */
/**
* @cpp const void* @ce, type is not preserved. For convenience it's
* possible to retrieve the value by calling @cpp field<const T*>() @ce
* with an arbitrary `T` but the user has to ensure the type is correct.
*/
Pointer,
/**
* @cpp void* @ce, type is not preserved. For convenience it's possible to
* retrieve the value by calling @cpp field<T*>() @ce with an arbitrary `T`
* but the user has to ensure the type is correct.
*/
MutablePointer,
};
/**
@ -1142,9 +1168,10 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray() accessors to get common
* fields converted to usual types, but note that these operations
* involve extra allocation and data conversion.
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors to get common fields converted
* to usual types, but note that these operations involve extra
* allocation and data conversion.
* @see @ref field(SceneField) const, @ref mutableField(UnsignedInt),
* @ref fieldArraySize()
*/
@ -1222,9 +1249,10 @@ class MAGNUM_TRADE_EXPORT SceneData {
* @ref translationsRotationsScalings2DAsArray(),
* @ref translationsRotationsScalings3DAsArray(),
* @ref meshesMaterialsAsArray(), @ref lightsAsArray(),
* @ref camerasAsArray(), @ref skinsAsArray() accessors to get common
* fields converted to usual types, but note that these operations
* involve extra allocation and data conversion.
* @ref camerasAsArray(), @ref skinsAsArray(),
* @ref importerStateAsArray() accessors to get common fields converted
* to usual types, but note that these operations involve extra
* allocation and data conversion.
* @see @ref field(UnsignedInt) const, @ref mutableField(SceneField)
*/
template<class T, class = typename std::enable_if<!std::is_array<T>::value>::type> Containers::StridedArrayView1D<const T> field(SceneField name) const;
@ -1721,6 +1749,45 @@ class MAGNUM_TRADE_EXPORT SceneData {
*/
std::size_t skinsInto(std::size_t offset, const Containers::StridedArrayView1D<UnsignedInt>& destination) 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.
*
* 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;
/**
* @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.
* @see @ref fieldSize(SceneField) const
*/
void importerStateInto(const Containers::StridedArrayView1D<const void*>& destination) 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
* extracts only a subrange of the field defined by @p offset and size
* of the @p destination view, returning the count of items actually
* extracted. The @p offset is expected to not be larger than the field
* size.
* @see @ref fieldSize(SceneField) const
*/
std::size_t importerStateInto(std::size_t offset, const Containers::StridedArrayView1D<const void*>& destination) const;
/**
* @brief Parent for given object
* @m_since_latest
@ -1945,6 +2012,25 @@ class MAGNUM_TRADE_EXPORT SceneData {
*/
Containers::Array<UnsignedInt> skinsFor(UnsignedInt object) const;
/**
* @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.
*
* If the @ref SceneField::ImporterState field is not present or if
* there's no importer state for @p object, returns
* @ref Containers::NullOpt.
*
* The @p object is expected to be less than @ref objectCount().
*/
Containers::Optional<const void*> importerStateFor(UnsignedInt object) const;
/**
* @brief Release field data storage
* @m_since_latest
@ -1983,7 +2069,11 @@ class MAGNUM_TRADE_EXPORT SceneData {
/**
* @brief Importer-specific state
*
* See @ref AbstractImporter::importerState() for more information.
* Scene-specific importer state. For object-specific importer state
* look for the @ref SceneField::ImporterState field or access it via
* @ref importerStateAsArray(), @ref importerStateFor() and related
* convenience functions. See @ref AbstractImporter::importerState()
* for general information about importer state pointers.
*/
const void* importerState() const { return _importerState; }
@ -2020,6 +2110,7 @@ class MAGNUM_TRADE_EXPORT SceneData {
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 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;
DataFlags _dataFlags;
SceneObjectType _objectType;
@ -2142,6 +2233,16 @@ namespace Implementation {
template<class T> struct SceneFieldTypeFor<Math::Color4<T>>: SceneFieldTypeFor<Math::Vector4<T>> {};
template<class T> struct SceneFieldTypeFor<Math::Matrix3<T>>: SceneFieldTypeFor<Math::Matrix3x3<T>> {};
template<class T> struct SceneFieldTypeFor<Math::Matrix4<T>>: SceneFieldTypeFor<Math::Matrix4x4<T>> {};
template<class T> struct SceneFieldTypeFor<const T*> {
constexpr static SceneFieldType type() {
return SceneFieldType::Pointer;
}
};
template<class T> struct SceneFieldTypeFor<T*> {
constexpr static SceneFieldType type() {
return SceneFieldType::MutablePointer;
}
};
template<class T> constexpr SceneObjectType sceneObjectTypeFor() {
static_assert(sizeof(T) == 0, "unsupported object type");
@ -2196,6 +2297,9 @@ namespace Implementation {
(type == SceneFieldType::Byte ||
type == SceneFieldType::Short ||
type == SceneFieldType::Int)) ||
(name == SceneField::ImporterState &&
(type == SceneFieldType::Pointer ||
type == SceneFieldType::MutablePointer)) ||
/* Custom fields can be anything */
isSceneFieldCustom(name);
}

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

@ -141,6 +141,9 @@ struct SceneDataTest: TestSuite::Tester {
template<class T> void skinsAsArray();
void skinsIntoArray();
void skinsIntoArrayInvalidSizeOrOffset();
template<class T> void importerStateAsArray();
void importerStateIntoArray();
void importerStateIntoArrayInvalidSizeOrOffset();
void mutableAccessNotAllowed();
@ -149,6 +152,7 @@ struct SceneDataTest: TestSuite::Tester {
void fieldNotFound();
void fieldWrongType();
void fieldWrongPointerType();
void fieldWrongArrayAccess();
/* Different object types checked just for the parentFor(), other APIs
@ -167,6 +171,7 @@ struct SceneDataTest: TestSuite::Tester {
void lightsFor();
void camerasFor();
void skinsFor();
void importerStateFor();
void fieldForFieldMissing();
void fieldForInvalidObject();
@ -351,6 +356,13 @@ SceneDataTest::SceneDataTest() {
Containers::arraySize(IntoArrayOffsetData));
addTests({&SceneDataTest::skinsIntoArrayInvalidSizeOrOffset,
&SceneDataTest::importerStateAsArray<const void*>,
&SceneDataTest::importerStateAsArray<void*>});
addInstancedTests({&SceneDataTest::importerStateIntoArray},
Containers::arraySize(IntoArrayOffsetData));
addTests({&SceneDataTest::importerStateIntoArrayInvalidSizeOrOffset,
&SceneDataTest::mutableAccessNotAllowed,
@ -359,6 +371,7 @@ SceneDataTest::SceneDataTest() {
&SceneDataTest::fieldNotFound,
&SceneDataTest::fieldWrongType,
&SceneDataTest::fieldWrongPointerType,
&SceneDataTest::fieldWrongArrayAccess,
&SceneDataTest::parentFor<UnsignedByte>,
@ -386,6 +399,7 @@ SceneDataTest::SceneDataTest() {
&SceneDataTest::lightsFor,
&SceneDataTest::camerasFor,
&SceneDataTest::skinsFor,
&SceneDataTest::importerStateFor,
&SceneDataTest::fieldForFieldMissing,
&SceneDataTest::fieldForInvalidObject,
@ -494,6 +508,7 @@ void SceneDataTest::fieldTypeSize() {
CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Matrix3x3d), sizeof(Matrix3x3d));
CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Matrix3x4d), sizeof(Matrix3x4d));
CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Matrix4x4d), sizeof(Matrix4x4d));
CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Pointer), sizeof(const void*));
}
void SceneDataTest::fieldTypeSizeInvalid() {
@ -1763,6 +1778,12 @@ _c(DualComplex)
_c(DualComplexd)
_c(DualQuaternion)
_c(DualQuaterniond)
template<class T> struct NameTraits<const T*> {
static const char* name() { return "Pointer"; }
};
template<class T> struct NameTraits<T*> {
static const char* name() { return "MutablePointer"; }
};
#undef _c
template<class T> void SceneDataTest::objectsAsArrayByIndex() {
@ -3714,6 +3735,107 @@ void SceneDataTest::skinsIntoArrayInvalidSizeOrOffset() {
"Trade::SceneData::skinsInto(): offset 4 out of bounds for a field of size 3\n");
}
template<class T> void SceneDataTest::importerStateAsArray() {
setTestCaseTemplateName(NameTraits<T>::name());
int a, b;
struct Field {
UnsignedByte object;
T importerState;
} fields[]{
{0, &a},
{1, nullptr},
{15, &b}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedByte, 50, {}, fields, {
/* To verify it isn't just picking the first ever field */
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::ImporterState, view.slice(&Field::object), view.slice(&Field::importerState)}
}};
CORRADE_COMPARE_AS(scene.importerStateAsArray(),
Containers::arrayView<const void*>({&a, nullptr, &b}),
TestSuite::Compare::Container);
}
void SceneDataTest::importerStateIntoArray() {
auto&& data = IntoArrayOffsetData[testCaseInstanceId()];
setTestCaseDescription(data.name);
/* Both AsArray() and Into() share a common helper. The AsArray() test
above verified handling of various data types and this checks the
offset/size parameters of the Into() variant. */
int a, b;
struct Field {
UnsignedInt object;
const void* importerState;
} fields[]{
{1, &a},
{0, nullptr},
{4, &b}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, {
/* To verify it isn't just picking the first ever field */
SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr},
SceneFieldData{SceneField::ImporterState,
view.slice(&Field::object),
view.slice(&Field::importerState)},
}};
/* The offset-less overload should give back all data */
{
const void* out[3];
scene.importerStateInto(out);
CORRADE_COMPARE_AS(Containers::stridedArrayView(out),
view.slice(&Field::importerState),
TestSuite::Compare::Container);
/* The offset variant only a subset */
} {
Containers::Array<const void*> out{data.size};
CORRADE_COMPARE(scene.importerStateInto(data.offset, out), data.expectedSize);
CORRADE_COMPARE_AS(out.prefix(data.expectedSize),
view.slice(&Field::importerState)
.slice(data.offset, data.offset + data.expectedSize),
TestSuite::Compare::Container);
}
}
void SceneDataTest::importerStateIntoArrayInvalidSizeOrOffset() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct Field {
UnsignedInt object;
const void* importerState;
} fields[3]{};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 5, {}, fields, {
SceneFieldData{SceneField::ImporterState, view.slice(&Field::object), view.slice(&Field::importerState)}
}};
std::ostringstream out;
Error redirectError{&out};
const void* destination[2];
scene.importerStateInto(destination);
scene.importerStateInto(4, destination);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::importerStateInto(): expected a view with 3 elements but got 2\n"
"Trade::SceneData::importerStateInto(): offset 4 out of bounds for a field of size 3\n");
}
void SceneDataTest::mutableAccessNotAllowed() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
@ -3908,6 +4030,9 @@ void SceneDataTest::fieldNotFound() {
scene.skinsAsArray();
scene.skinsInto(nullptr);
scene.skinsInto(0, nullptr);
scene.importerStateAsArray();
scene.importerStateInto(nullptr);
scene.importerStateInto(0, nullptr);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::fieldData(): index 2 out of range for 2 fields\n"
"Trade::SceneData::fieldName(): index 2 out of range for 2 fields\n"
@ -3961,7 +4086,10 @@ void SceneDataTest::fieldNotFound() {
"Trade::SceneData::camerasInto(): field not found\n"
"Trade::SceneData::skinsInto(): field not found\n"
"Trade::SceneData::skinsInto(): field not found\n"
"Trade::SceneData::skinsInto(): field not found\n");
"Trade::SceneData::skinsInto(): field not found\n"
"Trade::SceneData::importerStateInto(): field not found\n"
"Trade::SceneData::importerStateInto(): field not found\n"
"Trade::SceneData::importerStateInto(): field not found\n");
}
void SceneDataTest::fieldWrongType() {
@ -4003,6 +4131,78 @@ void SceneDataTest::fieldWrongType() {
"Trade::SceneData::mutableField(): Trade::SceneField::Mesh is Trade::SceneFieldType::UnsignedShort but requested a type equivalent to Trade::SceneFieldType::UnsignedByte\n");
}
void SceneDataTest::fieldWrongPointerType() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
struct Thing {
UnsignedInt object;
Int* foobar;
const Int* importerState;
} things[2];
Containers::StridedArrayView1D<Thing> view = things;
SceneData scene{SceneObjectType::UnsignedInt, 5, DataFlag::Mutable, things, {
SceneFieldData{sceneFieldCustom(35), view.slice(&Thing::object), Containers::arrayCast<2, Int*>(view.slice(&Thing::foobar))},
SceneFieldData{SceneField::ImporterState, view.slice(&Thing::object), view.slice(&Thing::importerState)},
}};
/* These are fine (type is not checked) */
scene.field<Float*[]>(0);
scene.field<const Float*>(1);
scene.mutableField<Float*[]>(0);
scene.mutableField<const Float*>(1);
scene.field<Float*[]>(sceneFieldCustom(35));
scene.field<const Float*>(SceneField::ImporterState);
scene.mutableField<Float*[]>(sceneFieldCustom(35));
scene.mutableField<const Float*>(SceneField::ImporterState);
std::ostringstream out;
Error redirectError{&out};
scene.field<Int>(0);
scene.field<const Int*>(0);
scene.field<const Int*[]>(0);
scene.field<Int*>(1);
scene.field<Int*[]>(1);
scene.mutableField<Int>(0);
scene.mutableField<const Int*>(0);
scene.mutableField<const Int*[]>(0);
scene.mutableField<Int*>(1);
scene.mutableField<Int*[]>(1);
scene.field<Int>(sceneFieldCustom(35));
scene.field<const Int*>(sceneFieldCustom(35));
scene.field<const Int*[]>(sceneFieldCustom(35));
scene.field<Int*>(SceneField::ImporterState);
scene.field<Int*>(SceneField::ImporterState);
scene.mutableField<Int>(sceneFieldCustom(35));
scene.mutableField<const Int*>(sceneFieldCustom(35));
scene.mutableField<const Int*[]>(sceneFieldCustom(35));
scene.mutableField<Int*>(SceneField::ImporterState);
scene.mutableField<Int*[]>(SceneField::ImporterState);
CORRADE_COMPARE(out.str(),
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Int\n"
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::field(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::field(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Int\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Int\n"
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::field(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::field(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::field(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Int\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::Custom(35) is Trade::SceneFieldType::MutablePointer but requested a type equivalent to Trade::SceneFieldType::Pointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n"
"Trade::SceneData::mutableField(): Trade::SceneField::ImporterState is Trade::SceneFieldType::Pointer but requested a type equivalent to Trade::SceneFieldType::MutablePointer\n");
}
void SceneDataTest::fieldWrongArrayAccess() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
@ -4512,6 +4712,36 @@ void SceneDataTest::skinsFor() {
TestSuite::Compare::Container);
}
void SceneDataTest::importerStateFor() {
int a, b, c;
struct Field {
UnsignedInt object;
const void* importerState;
} fields[]{
{3, &a},
{4, &b},
{2, nullptr},
{4, &c}
};
Containers::StridedArrayView1D<Field> view = fields;
SceneData scene{SceneObjectType::UnsignedInt, 7, {}, fields, {
SceneFieldData{SceneField::ImporterState, view.slice(&Field::object), view.slice(&Field::importerState)}
}};
CORRADE_COMPARE(scene.importerStateFor(2), nullptr);
CORRADE_COMPARE(scene.importerStateFor(3), &a);
/* Duplicate entries -- only the first one gets used, it doesn't traverse
further */
CORRADE_COMPARE(scene.importerStateFor(4), &b);
/* Object that's not in the array at all */
CORRADE_COMPARE(scene.importerStateFor(1), Containers::NullOpt);
}
void SceneDataTest::fieldForFieldMissing() {
SceneData scene{SceneObjectType::UnsignedInt, 7, nullptr, {}};

Loading…
Cancel
Save