Browse Source

Trade: add SceneFieldFlag::MultiEntry.

Allows me to parse array properties in glTF scene node extras and ensure
they're preserved as arrays on export as well even if they would all
have a single item.
pull/620/head
Vladimír Vondruš 3 years ago
parent
commit
7aec058ba4
  1. 4
      src/Magnum/Trade/SceneData.cpp
  2. 45
      src/Magnum/Trade/SceneData.h
  3. 41
      src/Magnum/Trade/Test/SceneDataTest.cpp

4
src/Magnum/Trade/SceneData.cpp

@ -539,6 +539,7 @@ Debug& operator<<(Debug& debug, const SceneFieldFlag value) {
_c(OffsetOnly)
_c(ImplicitMapping)
_c(OrderedMapping)
_c(MultiEntry)
_c(NullTerminatedString)
#undef _c
/* LCOV_EXCL_STOP */
@ -553,6 +554,7 @@ Debug& operator<<(Debug& debug, const SceneFieldFlags value) {
SceneFieldFlag::ImplicitMapping,
/* This one is implied by ImplicitMapping, so has to be after */
SceneFieldFlag::OrderedMapping,
SceneFieldFlag::MultiEntry,
SceneFieldFlag::NullTerminatedString
});
}
@ -624,6 +626,8 @@ SceneFieldData::SceneFieldData(const SceneField name, const Containers::StridedA
SceneFieldData::SceneFieldData(const SceneField name, const SceneMappingType mappingType, const Containers::StridedArrayView1D<const void>& mappingData, const char* const stringData, const SceneFieldType fieldType, const Containers::StridedArrayView1D<const void>& fieldData, const SceneFieldFlags flags) noexcept:
_size{mappingData.size()},
_name{name},
/** @todo check allowed flags once disallowedSceneFieldFlagsFor() includes
string fields too */
_flags{flags|Implementation::implicitSceneFieldFlagsFor(fieldType)},
_mappingTypeStringType{UnsignedByte(UnsignedByte(mappingType)|(UnsignedShort(fieldType) << 3))},
_mappingStride{Short(mappingData.stride())},

45
src/Magnum/Trade/SceneData.h

@ -758,6 +758,23 @@ enum class SceneFieldFlag: UnsignedByte {
*/
ImplicitMapping = (1 << 2)|OrderedMapping,
/**
* The field may have multiple entries for the same object. Meant to be
* used as a hint to distinguish between fields that are expected to have
* at most one entry for an object and fields that can have multiple
* entries for an object but sometimes have just one.
*
* Note that presence of this flag isn't enforced in any way, fields
* without this flag may still have multiple entries for the same object.
*
* Can't be set for @ref SceneField::Parent,
* @relativeref{SceneField,Transformation},
* @relativeref{SceneField,Translation}, @relativeref{SceneField,Rotation}
* or @relativeref{SceneField,Scaling}; however mapping uniqueness for
* those fields isn't enforced in any way either.
*/
MultiEntry = 1 << 4,
/**
* The string field is null-terminated, i.e. string views returned from
* @ref SceneData::fieldStrings() will always have
@ -4021,6 +4038,16 @@ namespace Implementation {
type == SceneFieldType::StringRangeNullTerminated64 ?
SceneFieldFlag::NullTerminatedString : SceneFieldFlags{};
}
constexpr SceneFieldFlags disallowedSceneFieldFlagsFor(SceneField name) {
return
name == SceneField::Parent ||
name == SceneField::Transformation ||
name == SceneField::Translation ||
name == SceneField::Rotation ||
name == SceneField::Scaling ?
SceneFieldFlag::MultiEntry : SceneFieldFlags{};
}
}
constexpr SceneFieldData::SceneFieldData(const SceneField name, const SceneMappingType mappingType, const Containers::StridedArrayView1D<const void>& mappingData, const SceneFieldType fieldType, const Containers::StridedArrayView1D<const void>& fieldData, const UnsignedShort fieldArraySize, const SceneFieldFlags flags) noexcept:
@ -4028,8 +4055,8 @@ constexpr SceneFieldData::SceneFieldData(const SceneField name, const SceneMappi
"Trade::SceneFieldData: expected" << name << "mapping and field view to have the same size but got" << mappingData.size() << "and" << fieldData.size()), mappingData.size())},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeCompatibleWithField(name, fieldType),
"Trade::SceneFieldData:" << fieldType << "is not a valid type for" << name), name)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString)),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString)) << "for a view of" << fieldType), flags)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))) << "for a" << name << "view of" << fieldType), flags)},
/* Can't use {} because GCC 4.8 then says "warning: parameter 'mappingType'
set but not used" */
_mappingTypeStringType(UnsignedByte(mappingType)),
@ -4068,8 +4095,8 @@ constexpr SceneFieldData::SceneFieldData(const SceneField name, const SceneMappi
"Trade::SceneFieldData: expected" << name << "mapping and field view to have the same size but got" << mappingData.size() << "and" << fieldSize), mappingData.size())},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeCompatibleWithField(name, SceneFieldType::Bit),
"Trade::SceneFieldData:" << SceneFieldType::Bit << "is not a valid type for" << name), name)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString)),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString)) << "for a view of" << SceneFieldType::Bit), flags)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))) << "for a" << name << "view of" << SceneFieldType::Bit), flags)},
/* Can't use {} because GCC 4.8 then says "warning: parameter 'mappingType'
set but not used" */
_mappingTypeStringType(UnsignedByte(mappingType)),
@ -4105,8 +4132,8 @@ constexpr SceneFieldData::SceneFieldData(const SceneField name, const std::size_
_size{size},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeCompatibleWithField(name, fieldType),
"Trade::SceneFieldData:" << fieldType << "is not a valid type for" << name), name)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & SceneFieldFlag::NullTerminatedString),
"Trade::SceneFieldData: can't pass" << (flags & SceneFieldFlag::NullTerminatedString) << "for" << fieldType), flags|SceneFieldFlag::OffsetOnly)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))) << "for" << name << "of" << fieldType), flags|SceneFieldFlag::OffsetOnly)},
/* Can't use {} because GCC 4.8 then says "warning: parameter 'mappingType'
set but not used" */
_mappingTypeStringType(UnsignedByte(mappingType)),
@ -4129,8 +4156,8 @@ constexpr SceneFieldData::SceneFieldData(const SceneField name, const std::size_
"Trade::SceneFieldData: size expected to be smaller than 2^" << Debug::nospace << (sizeof(std::size_t)*8 - 3) << "bits, got" << size), size)},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeCompatibleWithField(name, SceneFieldType::Bit),
"Trade::SceneFieldData:" << SceneFieldType::Bit << "is not a valid type for" << name), name)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & SceneFieldFlag::NullTerminatedString),
"Trade::SceneFieldData: can't pass" << (flags & SceneFieldFlag::NullTerminatedString) << "for" << SceneFieldType::Bit), flags|SceneFieldFlag::OffsetOnly)},
_flags{(CORRADE_CONSTEXPR_ASSERT(!(flags & (SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))),
"Trade::SceneFieldData: can't pass" << (flags & (SceneFieldFlag::NullTerminatedString|Implementation::disallowedSceneFieldFlagsFor(name))) << "for" << name << "of" << SceneFieldType::Bit), flags|SceneFieldFlag::OffsetOnly)},
/* Can't use {} because GCC 4.8 then says "warning: parameter 'mappingType'
set but not used" */
_mappingTypeStringType(UnsignedByte(mappingType)),
@ -4149,6 +4176,8 @@ constexpr SceneFieldData::SceneFieldData(const SceneField name, const std::size_
_size{size},
_name{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeCompatibleWithField(name, fieldType),
"Trade::SceneFieldData:" << fieldType << "is not a valid type for" << name), name)},
/** @todo check allowed flags once disallowedSceneFieldFlagsFor() includes
string fields too */
_flags{flags|SceneFieldFlag::OffsetOnly|Implementation::implicitSceneFieldFlagsFor(fieldType)},
_mappingTypeStringType{(CORRADE_CONSTEXPR_ASSERT(Implementation::isSceneFieldTypeString(fieldType),
"Trade::SceneFieldData: can't use a string constructor for" << fieldType), UnsignedByte(UnsignedByte(mappingType)|(UnsignedShort(fieldType) << 3)))},

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

@ -2097,16 +2097,21 @@ void SceneDataTest::constructFieldFlagNotAllowed() {
/* These are fine */
SceneFieldData{SceneField::Rotation, 3, SceneMappingType::UnsignedShort, 0, sizeof(UnsignedShort), SceneFieldType::Quaternion, 0, sizeof(Quaternion), SceneFieldFlag::OffsetOnly};
SceneFieldData{sceneFieldCustom(773), 3, SceneMappingType::UnsignedShort, 0, sizeof(UnsignedShort), 0, 0, sizeof(Quaternion), SceneFieldFlag::OffsetOnly};
SceneFieldData{sceneFieldCustom(24), Containers::arrayView(mappingData), helloStringData, SceneFieldType::StringOffset32, helloFieldData, SceneFieldFlag::NullTerminatedString};
SceneFieldData{sceneFieldCustom(24), 3, SceneMappingType::UnsignedShort, 0, 2, 0, SceneFieldType::StringOffset32, 0, 4, SceneFieldFlag::NullTerminatedString};
SceneFieldData{SceneField::Mesh, Containers::arrayView(mappingData), Containers::arrayView(helloFieldData), SceneFieldFlag::MultiEntry};
SceneFieldData{sceneFieldCustom(773), 3, SceneMappingType::UnsignedShort, 0, sizeof(UnsignedShort), 0, 0, sizeof(Quaternion), SceneFieldFlag::OffsetOnly|SceneFieldFlag::MultiEntry};
SceneFieldData{sceneFieldCustom(773), Containers::arrayView(mappingData), Containers::BitArrayView{hiddenFieldData, 0, 3}, SceneFieldFlag::MultiEntry};
SceneFieldData{sceneFieldCustom(24), Containers::arrayView(mappingData), helloStringData, SceneFieldType::StringOffset32, helloFieldData, SceneFieldFlag::NullTerminatedString|SceneFieldFlag::MultiEntry};
SceneFieldData{sceneFieldCustom(24), 3, SceneMappingType::UnsignedShort, 0, 2, 0, SceneFieldType::StringOffset32, 0, 4, SceneFieldFlag::NullTerminatedString|SceneFieldFlag::MultiEntry};
std::ostringstream out;
Error redirectError{&out};
SceneFieldData{SceneField::Rotation, Containers::arrayView(mappingData), Containers::arrayView(rotationFieldData), SceneFieldFlag::OffsetOnly};
SceneFieldData{SceneField::Rotation, Containers::arrayView(mappingData), Containers::arrayView(rotationFieldData), SceneFieldFlag::MultiEntry};
SceneFieldData{SceneField::Rotation, Containers::arrayView(mappingData), Containers::arrayView(rotationFieldData), SceneFieldFlag::NullTerminatedString};
SceneFieldData{SceneField::Rotation, Containers::arrayView(mappingData), Containers::arrayView(rotationFieldData), SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString};
SceneFieldData{SceneField::Rotation, Containers::arrayView(mappingData), Containers::arrayView(rotationFieldData), SceneFieldFlag::OffsetOnly|SceneFieldFlag::NullTerminatedString|SceneFieldFlag::MultiEntry};
SceneFieldData{SceneField::Rotation, 3, SceneMappingType::UnsignedShort, 0, 2, SceneFieldType::Quaternion, 0, 16, SceneFieldFlag::MultiEntry};
SceneFieldData{SceneField::Rotation, 3, SceneMappingType::UnsignedShort, 0, 2, SceneFieldType::Quaternion, 0, 16, SceneFieldFlag::NullTerminatedString};
SceneFieldData{SceneField::Rotation, 3, SceneMappingType::UnsignedShort, 0, 2, SceneFieldType::Quaternion, 0, 16, SceneFieldFlag::MultiEntry|SceneFieldFlag::NullTerminatedString};
SceneFieldData{sceneFieldCustom(773), Containers::arrayView(mappingData), Containers::BitArrayView{hiddenFieldData, 0, 3}, SceneFieldFlag::OffsetOnly};
SceneFieldData{sceneFieldCustom(773), Containers::arrayView(mappingData), Containers::BitArrayView{hiddenFieldData, 0, 3}, SceneFieldFlag::NullTerminatedString};
@ -2114,18 +2119,22 @@ void SceneDataTest::constructFieldFlagNotAllowed() {
SceneFieldData{sceneFieldCustom(773), 3, SceneMappingType::UnsignedShort, 0, 2, 0, 0, 16, SceneFieldFlag::NullTerminatedString};
SceneFieldData{sceneFieldCustom(24), Containers::arrayView(mappingData), helloStringData, SceneFieldType::StringOffset32, helloFieldData, SceneFieldFlag::OffsetOnly};
CORRADE_COMPARE(out.str(),
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for a view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly|Trade::SceneFieldFlag::NullTerminatedString for a view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for a view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly|Trade::SceneFieldFlag::NullTerminatedString for a view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a view\n");
CORRADE_COMPARE_AS(out.str(),
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a Trade::SceneField::Rotation view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::MultiEntry for a Trade::SceneField::Rotation view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for a Trade::SceneField::Rotation view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly|Trade::SceneFieldFlag::MultiEntry|Trade::SceneFieldFlag::NullTerminatedString for a Trade::SceneField::Rotation view of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::MultiEntry for Trade::SceneField::Rotation of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for Trade::SceneField::Rotation of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::MultiEntry|Trade::SceneFieldFlag::NullTerminatedString for Trade::SceneField::Rotation of Trade::SceneFieldType::Quaternion\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a Trade::SceneField::Custom(773) view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for a Trade::SceneField::Custom(773) view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly|Trade::SceneFieldFlag::NullTerminatedString for a Trade::SceneField::Custom(773) view of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::NullTerminatedString for Trade::SceneField::Custom(773) of Trade::SceneFieldType::Bit\n"
"Trade::SceneFieldData: can't pass Trade::SceneFieldFlag::OffsetOnly for a view\n",
TestSuite::Compare::String);
}
void SceneDataTest::constructFieldWrongOffsetOnlyDataAccess() {

Loading…
Cancel
Save