diff --git a/src/Magnum/Trade/SceneData.cpp b/src/Magnum/Trade/SceneData.cpp index 56029e269..d22c78a2b 100644 --- a/src/Magnum/Trade/SceneData.cpp +++ b/src/Magnum/Trade/SceneData.cpp @@ -363,7 +363,7 @@ Containers::Array sceneFieldDataNonOwningArray(const Containers: return Containers::Array{const_cast(view.data()), view.size(), reinterpret_cast(Implementation::nonOwnedArrayDeleter)}; } -SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong objectCount, Containers::Array&& data, Containers::Array&& fields, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _objectType{objectType}, _objectCount{objectCount}, _importerState{importerState}, _fields{std::move(fields)}, _data{std::move(data)} { +SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong objectCount, Containers::Array&& data, Containers::Array&& fields, const void* const importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _objectType{objectType}, _dimensions{}, _objectCount{objectCount}, _importerState{importerState}, _fields{std::move(fields)}, _data{std::move(data)} { /* Check that object type is large enough */ CORRADE_ASSERT( (objectType == SceneObjectType::UnsignedByte && objectCount <= 0xffull) || @@ -376,14 +376,19 @@ SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong object /* Check various assumptions about field data */ Math::BoolVector<12> fieldsPresent; /** @todo some constant for this */ const UnsignedInt objectTypeSize = sceneObjectTypeSize(_objectType); + #endif + UnsignedInt transformationField = ~UnsignedInt{}; UnsignedInt translationField = ~UnsignedInt{}; UnsignedInt rotationField = ~UnsignedInt{}; UnsignedInt scalingField = ~UnsignedInt{}; + #ifndef CORRADE_NO_ASSERT UnsignedInt meshField = ~UnsignedInt{}; UnsignedInt meshMaterialField = ~UnsignedInt{}; + #endif for(std::size_t i = 0; i != _fields.size(); ++i) { const SceneFieldData& field = _fields[i]; + #ifndef CORRADE_NO_ASSERT /* The object type has to be the same among all fields. Technically it wouldn't need to be, but if there's 60k objects then using a 8bit type for certain fields would mean only the first 256 objects can be @@ -441,22 +446,30 @@ SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong object "Trade::SceneData: field data [" << Debug::nospace << fieldBegin << Debug::nospace << ":" << Debug::nospace << fieldEnd << Debug::nospace << "] of field" << i << "are not contained in passed data array [" << Debug::nospace << static_cast(_data.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast(_data.end()) << Debug::nospace << "]", ); } } + #endif - /* Remember TRS and mesh/material fields to check their object mapping - consistency outside of the loop below */ - if(_fields[i]._name == SceneField::Translation) { + /* Remember TRS and mesh/material fields to figure out whether the + scene is 2D or 3D and check their object mapping consistency outside + of the loop below */ + if(_fields[i]._name == SceneField::Transformation) { + transformationField = i; + } else if(_fields[i]._name == SceneField::Translation) { translationField = i; } else if(_fields[i]._name == SceneField::Rotation) { rotationField = i; } else if(_fields[i]._name == SceneField::Scaling) { scalingField = i; - } else if(_fields[i]._name == SceneField::Mesh) { + } + #ifndef CORRADE_NO_ASSERT + else if(_fields[i]._name == SceneField::Mesh) { meshField = i; } else if(_fields[i]._name == SceneField::MeshMaterial) { meshMaterialField = i; } + #endif } + #ifndef CORRADE_NO_ASSERT /* Check that certain fields share the same object mapping. Printing as if all would be pointers (and not offset-only), it's not worth the extra effort just for an assert message. Also, compared to above, where @@ -486,6 +499,67 @@ SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong object if(meshField != ~UnsignedInt{} && meshMaterialField != ~UnsignedInt{}) checkFieldObjectDataMatch(_fields[meshField], _fields[meshMaterialField]); #endif + + /* Decide about dimensionality based on transformation type, if present */ + if(transformationField != ~UnsignedInt{}) { + const SceneFieldType fieldType = _fields[transformationField]._fieldType; + if(fieldType == SceneFieldType::Matrix3x3 || + fieldType == SceneFieldType::Matrix3x3d || + fieldType == SceneFieldType::DualComplex || + fieldType == SceneFieldType::DualComplexd) + _dimensions = 2; + else if(fieldType == SceneFieldType::Matrix4x4 || + fieldType == SceneFieldType::Matrix4x4d || + fieldType == SceneFieldType::DualQuaternion || + fieldType == SceneFieldType::DualQuaterniond) + _dimensions = 3; + else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + } + + /* Use TRS fields to decide about dimensionality, if the transformation + field is not present. If it is, verify that they match it. */ + if(translationField != ~UnsignedInt{}) { + const SceneFieldType fieldType = _fields[translationField]._fieldType; + if(fieldType == SceneFieldType::Vector2 || + fieldType == SceneFieldType::Vector2d) { + CORRADE_ASSERT(!_dimensions || _dimensions == 2, + "Trade::SceneData: expected a 3D translation field but got" << fieldType, ); + _dimensions = 2; + } else if(fieldType == SceneFieldType::Vector3 || + fieldType == SceneFieldType::Vector3d) { + CORRADE_ASSERT(!_dimensions || _dimensions == 3, + "Trade::SceneData: expected a 2D translation field but got" << fieldType, ); + _dimensions = 3; + } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + } + if(rotationField != ~UnsignedInt{}) { + const SceneFieldType fieldType = _fields[rotationField]._fieldType; + if(fieldType == SceneFieldType::Complex || + fieldType == SceneFieldType::Complexd) { + CORRADE_ASSERT(!_dimensions || _dimensions == 2, + "Trade::SceneData: expected a 3D rotation field but got" << fieldType, ); + _dimensions = 2; + } else if(fieldType == SceneFieldType::Quaternion || + fieldType == SceneFieldType::Quaterniond) { + CORRADE_ASSERT(!_dimensions || _dimensions == 3, + "Trade::SceneData: expected a 2D rotation field but got" << fieldType, ); + _dimensions = 3; + } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + } + if(scalingField != ~UnsignedInt{}) { + const SceneFieldType fieldType = _fields[scalingField]._fieldType; + if(fieldType == SceneFieldType::Vector2 || + fieldType == SceneFieldType::Vector2d) { + CORRADE_ASSERT(!_dimensions || _dimensions == 2, + "Trade::SceneData: expected a 3D scaling field but got" << fieldType, ); + _dimensions = 2; + } else if(fieldType == SceneFieldType::Vector3 || + fieldType == SceneFieldType::Vector3d) { + CORRADE_ASSERT(!_dimensions || _dimensions == 3, + "Trade::SceneData: expected a 2D scaling field but got" << fieldType, ); + _dimensions = 3; + } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + } } SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong objectCount, Containers::Array&& data, const std::initializer_list fields, const void* const importerState): SceneData{objectType, objectCount, std::move(data), Implementation::initializerListToArrayWithDefaultDeleter(fields), importerState} {} @@ -903,6 +977,10 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi /* *FieldId, offset and destination.size() is assumed to be in bounds (or an invalid field ID), checked by the callers */ + /* If is2D() returned false as well, all *FieldId would be invalid, which + the caller is assumed to check. */ + CORRADE_ASSERT(!is3D(), "Trade::SceneData::transformations2DInto(): scene has a 3D transformation type", ); + /** @todo apply scalings as well if dual complex? */ /* Prefer the transformation field, if present */ @@ -919,11 +997,6 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi convertTransformation(fieldData, destination); } else if(field._fieldType == SceneFieldType::DualComplexd) { convertTransformation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Matrix4x4 || - field._fieldType == SceneFieldType::Matrix4x4d || - field._fieldType == SceneFieldType::DualQuaternion || - field._fieldType == SceneFieldType::DualQuaterniond) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations2DInto(): field has a 3D transformation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ /* If not, combine from TRS components */ @@ -941,9 +1014,6 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi applyScaling(fieldData, destination); } else if(field._fieldType == SceneFieldType::Vector2d) { applyScaling(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Vector3 || - field._fieldType == SceneFieldType::Vector3d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations2DInto(): field has a 3D scaling type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -956,9 +1026,6 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi applyRotation(fieldData, destination); } else if(field._fieldType == SceneFieldType::Complexd) { applyRotation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Quaternion || - field._fieldType == SceneFieldType::Quaterniond) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations2DInto(): field has a 3D rotation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -971,9 +1038,6 @@ void SceneData::transformations2DIntoInternal(const UnsignedInt transformationFi applyTranslation(fieldData, destination); } else if(field._fieldType == SceneFieldType::Vector2d) { applyTranslation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Vector3 || - field._fieldType == SceneFieldType::Vector3d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations2DInto(): field has a 3D translation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -1022,6 +1086,10 @@ void SceneData::translationsRotationsScalings2DIntoInternal(const UnsignedInt tr /* *FieldId, offset and *Destination.size() is assumed to be in bounds (or an invalid field ID), checked by the callers */ + /* If is2D() returned false as well, all *FieldId would be invalid, which + the caller is assumed to check. */ + CORRADE_ASSERT(!is3D(), "Trade::SceneData::translationsRotationsScalings2DInto(): scene has a 3D transformation type", ); + /* Retrieve translation, if desired. If no field is present, output a zero vector for all objects. */ if(translationDestination) { @@ -1036,9 +1104,6 @@ void SceneData::translationsRotationsScalings2DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), translationDestination); } else if(field._fieldType == SceneFieldType::Vector2d) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 2), Containers::arrayCast<2, Float>(translationDestination)); - } else if(field._fieldType == SceneFieldType::Vector3 || - field._fieldType == SceneFieldType::Vector3d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D translation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1057,9 +1122,6 @@ void SceneData::translationsRotationsScalings2DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), rotationDestination); } else if(field._fieldType == SceneFieldType::Complexd) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 2), Containers::arrayCast<2, Float>(rotationDestination)); - } else if(field._fieldType == SceneFieldType::Quaternion || - field._fieldType == SceneFieldType::Quaterniond) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D rotation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1078,9 +1140,6 @@ void SceneData::translationsRotationsScalings2DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), scalingDestination); } else if(field._fieldType == SceneFieldType::Vector2d) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 2), Containers::arrayCast<2, Float>(scalingDestination)); - } else if(field._fieldType == SceneFieldType::Vector3 || - field._fieldType == SceneFieldType::Vector3d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D scaling type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1144,6 +1203,10 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi /* *FieldId, offset and destination.size() is assumed to be in bounds (or an invalid field ID), checked by the callers */ + /* If is3D() returned false as well, all *FieldId would be invalid, which + the caller is assumed to check. */ + CORRADE_ASSERT(!is2D(), "Trade::SceneData::transformations3DInto(): scene has a 2D transformation type", ); + /** @todo apply scalings as well if dual quat? */ /* Prefer the transformation field, if present */ @@ -1160,11 +1223,6 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi convertTransformation(fieldData, destination); } else if(field._fieldType == SceneFieldType::DualQuaterniond) { convertTransformation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Matrix3x3 || - field._fieldType == SceneFieldType::Matrix3x3d || - field._fieldType == SceneFieldType::DualComplex || - field._fieldType == SceneFieldType::DualComplexd) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations3DInto(): field has a 2D transformation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ /* If not, combine from TRS components */ @@ -1182,9 +1240,6 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi applyScaling(fieldData, destination); } else if(field._fieldType == SceneFieldType::Vector3d) { applyScaling(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Vector2 || - field._fieldType == SceneFieldType::Vector2d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations3DInto(): field has a 2D scaling type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -1197,9 +1252,6 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi applyRotation(fieldData, destination); } else if(field._fieldType == SceneFieldType::Quaterniond) { applyRotation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Complex || - field._fieldType == SceneFieldType::Complexd) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations3DInto(): field has a 2D rotation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -1212,9 +1264,6 @@ void SceneData::transformations3DIntoInternal(const UnsignedInt transformationFi applyTranslation(fieldData, destination); } else if(field._fieldType == SceneFieldType::Vector3d) { applyTranslation(fieldData, destination); - } else if(field._fieldType == SceneFieldType::Vector2 || - field._fieldType == SceneFieldType::Vector2d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::transformations3DInto(): field has a 2D translation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } @@ -1263,6 +1312,10 @@ void SceneData::translationsRotationsScalings3DIntoInternal(const UnsignedInt tr /* *FieldId, offset and *Destination.size() is assumed to be in bounds (or an invalid field ID), checked by the callers */ + /* If is3D() returned false as well, all *FieldId would be invalid, which + the caller is assumed to check. */ + CORRADE_ASSERT(!is2D(), "Trade::SceneData::translationsRotationsScalings3DInto(): scene has a 2D transformation type", ); + /* Retrieve translation, if desired. If no field is present, output a zero vector for all objects. */ if(translationDestination) { @@ -1277,9 +1330,6 @@ void SceneData::translationsRotationsScalings3DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), translationDestination); } else if(field._fieldType == SceneFieldType::Vector3d) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 3), Containers::arrayCast<2, Float>(translationDestination)); - } else if(field._fieldType == SceneFieldType::Vector2 || - field._fieldType == SceneFieldType::Vector2d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D translation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1298,9 +1348,6 @@ void SceneData::translationsRotationsScalings3DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), rotationDestination); } else if(field._fieldType == SceneFieldType::Quaterniond) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 4), Containers::arrayCast<2, Float>(rotationDestination)); - } else if(field._fieldType == SceneFieldType::Complex || - field._fieldType == SceneFieldType::Complexd) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D rotation type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1319,9 +1366,6 @@ void SceneData::translationsRotationsScalings3DIntoInternal(const UnsignedInt tr Utility::copy(Containers::arrayCast(fieldData), scalingDestination); } else if(field._fieldType == SceneFieldType::Vector3d) { Math::castInto(Containers::arrayCast<2, const Double>(fieldData, 3), Containers::arrayCast<2, Float>(scalingDestination)); - } else if(field._fieldType == SceneFieldType::Vector2 || - field._fieldType == SceneFieldType::Vector2d) { - CORRADE_ASSERT_UNREACHABLE("Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D scaling type" << field._fieldType, ); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } } @@ -1698,39 +1742,9 @@ Containers::Optional SceneData::transformation2DFor(const UnsignedInt o UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping; if(findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {}; - #ifndef CORRADE_NO_ASSERT - if(transformationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[transformationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Matrix3x3 || - type == SceneFieldType::Matrix3x3d || - type == SceneFieldType::DualComplex || - type == SceneFieldType::DualComplexd, - "Trade::SceneData::transformation2DFor(): field has a 3D transformation type" << type, {}); - } else { - if(translationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[translationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector2 || - type == SceneFieldType::Vector2d, - "Trade::SceneData::transformation2DFor(): field has a 3D translation type" << type, {}); - } - if(rotationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[rotationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Complex || - type == SceneFieldType::Complexd, - "Trade::SceneData::transformation2DFor(): field has a 3D rotation type" << type, {}); - } - if(scalingFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[scalingFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector2 || - type == SceneFieldType::Vector2d, - "Trade::SceneData::transformation2DFor(): field has a 3D scaling type" << type, {}); - } - } - #endif + /* If is2D() returned false as well, all *FieldId would be invalid, which + 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 {}; @@ -1747,29 +1761,9 @@ Containers::Optional> SceneData::t UnsignedInt translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping; if(findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {}; - #ifndef CORRADE_NO_ASSERT - if(translationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[translationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector2 || - type == SceneFieldType::Vector2d, - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D translation type" << type, {}); - } - if(rotationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[rotationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Complex || - type == SceneFieldType::Complexd, - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D rotation type" << type, {}); - } - if(scalingFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[scalingFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector2 || - type == SceneFieldType::Vector2d, - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D scaling type" << type, {}); - } - #endif + /* If is2D() returned false as well, all *FieldId would be invalid, which + 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 {}; @@ -1788,39 +1782,9 @@ Containers::Optional SceneData::transformation3DFor(const UnsignedInt o UnsignedInt transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping; if(findTransformFields(transformationFieldId, translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {}; - #ifndef CORRADE_NO_ASSERT - if(transformationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[transformationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Matrix4x4 || - type == SceneFieldType::Matrix4x4d || - type == SceneFieldType::DualQuaternion || - type == SceneFieldType::DualQuaterniond, - "Trade::SceneData::transformation3DFor(): field has a 2D transformation type" << type, {}); - } else { - if(translationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[translationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector3 || - type == SceneFieldType::Vector3d, - "Trade::SceneData::transformation3DFor(): field has a 2D translation type" << type, {}); - } - if(rotationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[rotationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Quaternion || - type == SceneFieldType::Quaterniond, - "Trade::SceneData::transformation3DFor(): field has a 2D rotation type" << type, {}); - } - if(scalingFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[scalingFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector3 || - type == SceneFieldType::Vector3d, - "Trade::SceneData::transformation3DFor(): field has a 2D scaling type" << type, {}); - } - } - #endif + /* If is3D() returned false as well, all *FieldId would be invalid, which + 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 {}; @@ -1837,29 +1801,9 @@ Containers::Optional> SceneData UnsignedInt translationFieldId, rotationFieldId, scalingFieldId, fieldWithObjectMapping; if(findTranslationRotationScalingFields(translationFieldId, rotationFieldId, scalingFieldId, &fieldWithObjectMapping) == ~std::size_t{}) return {}; - #ifndef CORRADE_NO_ASSERT - if(translationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[translationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector3 || - type == SceneFieldType::Vector3d, - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D translation type" << type, {}); - } - if(rotationFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[rotationFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Quaternion || - type == SceneFieldType::Quaterniond, - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D rotation type" << type, {}); - } - if(scalingFieldId != ~UnsignedInt{}) { - const SceneFieldType type = _fields[scalingFieldId]._fieldType; - CORRADE_ASSERT( - type == SceneFieldType::Vector3 || - type == SceneFieldType::Vector3d, - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D scaling type" << type, {}); - } - #endif + /* If is3D() returned false as well, all *FieldId would be invalid, which + 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 {}; diff --git a/src/Magnum/Trade/SceneData.h b/src/Magnum/Trade/SceneData.h index 27b86899e..8a9a5b9b1 100644 --- a/src/Magnum/Trade/SceneData.h +++ b/src/Magnum/Trade/SceneData.h @@ -121,15 +121,18 @@ enum class SceneField: UnsignedInt { * * The transformation can be also represented by separate * @ref SceneField::Translation, @ref SceneField::Rotation and - * @ref SceneField::Scaling fields. If both @ref SceneField::Transformation - * and TRS fields are specified, it's expected that all objects that have - * TRS fields have a combined transformation field as well, and + * @ref SceneField::Scaling fields. All present transformation-related + * fields are expected to have the same dimensionality --- either all 2D or + * all 3D. If both @ref SceneField::Transformation and TRS fields are + * specified, it's expected that all objects that have TRS fields have a + * combined transformation field as well, and * @ref SceneData::transformations2DAsArray() / * @ref SceneData::transformations3DAsArray() then takes into account only * the combined transformation field. TRS fields can however be specified * only for a subset of transformed objects, useful for example when only * certain objects have these properties animated. - * @see @ref SceneData::transformations2DAsArray(), + * @see @ref SceneData::is2D(), @ref SceneData::is3D(), + * @ref SceneData::transformations2DAsArray(), * @ref SceneData::transformations3DAsArray(), * @ref SceneData::transformation2DFor(), * @ref SceneData::transformation3DFor() @@ -146,11 +149,13 @@ enum class SceneField: UnsignedInt { * * The translation field usually is (but doesn't have to be) complemented * by a @ref SceneField::Rotation and @ref SceneField::Scaling, which, if - * present, are expected to all share the same object mapping view. The TRS + * present, are expected to all share the same object mapping view and have + * the same dimensionality, either all 2D or all 3D. The TRS * components can either completely replace @ref SceneField::Transformation * or be provided just for a subset of it --- see its documentation for * details. - * @see @ref SceneData::transformations2DAsArray(), + * @see @ref SceneData::is2D(), @ref SceneData::is3D(), + * @ref SceneData::transformations2DAsArray(), * @ref SceneData::transformations3DAsArray(), * @ref SceneData::transformation2DFor(), * @ref SceneData::transformation3DFor(), @@ -171,11 +176,13 @@ enum class SceneField: UnsignedInt { * * The rotation field usually is (but doesn't have to be) complemented by a * @ref SceneField::Translation and @ref SceneField::Scaling, which, if - * present, are expected to all share the same object mapping view. The TRS + * present, are expected to all share the same object mapping view and have + * the same dimensionality, either all 2D or all 3D. The TRS * components can either completely replace @ref SceneField::Transformation * or be provided just for a subset of it --- see its documentation for * details. - * @see @ref SceneData::transformations2DAsArray(), + * @see @ref SceneData::is2D(), @ref SceneData::is3D(), + * @ref SceneData::transformations2DAsArray(), * @ref SceneData::transformations3DAsArray(), * @ref SceneData::transformation2DFor(), * @ref SceneData::transformation3DFor(), @@ -196,11 +203,13 @@ enum class SceneField: UnsignedInt { * * The scaling field usually is (but doesn't have to be) complemented by a * @ref SceneField::Translation and @ref SceneField::Rotation, which, if - * present, are expected to all share the same object mapping view. The TRS + * present, are expected to all share the same object mapping view and have + * the same dimensionality, either all 2D or all 3D. The TRS * components can either completely replace @ref SceneField::Transformation * or be provided just for a subset of it --- see its documentation for * details. - * @see @ref SceneData::transformations2DAsArray(), + * @see @ref SceneData::is2D(), @ref SceneData::is3D(), + * @ref SceneData::transformations2DAsArray(), * @ref SceneData::transformations3DAsArray(), * @ref SceneData::transformation2DFor(), * @ref SceneData::transformation3DFor(), @@ -993,9 +1002,47 @@ class MAGNUM_TRADE_EXPORT SceneData { */ UnsignedShort fieldArraySize(UnsignedInt id) const; + /** + * @brief Whether the scene is two-dimensional + * @m_since_latest + * + * Returns @cpp true @ce if the present + * @ref SceneField::Transformation, + * @relativeref{SceneField,Translation}, + * @relativeref{SceneField,Rotation} and + * @relativeref{SceneField,Scaling} fields have a 2D type, + * @cpp false @ce otherwise. + * + * If there's no transformation-related field, the scene is treated as + * neither 2D nor 3D and both @ref is2D() and @ref is3D() return + * @cpp false @ce. On the other hand, a scene can't be both 2D and 3D. + * @see @ref hasField() + */ + bool is2D() const { return _dimensions == 2; } + + /** + * @brief Whether the scene is three-dimensional + * @m_since_latest + * + * Returns @cpp true @ce if the present + * @ref SceneField::Transformation, + * @relativeref{SceneField,Translation}, + * @relativeref{SceneField,Rotation} and + * @relativeref{SceneField,Scaling} fields have a 3D type, + * @cpp false @ce otherwise. + * + * If there's no transformation-related field, the scene is treated as + * neither 2D nor 3D and both @ref is2D() and @ref is3D() return + * @cpp false @ce. On the other hand, a scene can't be both 2D and 3D. + * @see @ref hasField() + */ + bool is3D() const { return _dimensions == 3; } + /** * @brief Whether the scene has given field * @m_since_latest + * + * @see @ref is2D(), @ref is3D() */ bool hasField(SceneField name) const; @@ -1430,7 +1477,7 @@ class MAGNUM_TRADE_EXPORT SceneData { * expected to exist and they are expected to have a type corresponding * to 2D, otherwise you're supposed to use * @ref transformations3DAsArray(). - * @see @ref transformations2DInto(), @ref hasField(), + * @see @ref is2D(), @ref transformations2DInto(), @ref hasField(), * @ref fieldType(SceneField) const, @ref transformation2DFor() */ Containers::Array transformations2DAsArray() const; @@ -1476,8 +1523,8 @@ class MAGNUM_TRADE_EXPORT SceneData { * field isn't present, the second value is an identity rotation. If * the @relativeref{SceneField,Scaling} field isn't present, the third * value is an identity scaling (@cpp 1.0f @ce in both dimensions). - * @see @ref translationsRotationsScalings2DInto(), @ref hasField(), - * @ref fieldType(SceneField) const, + * @see @ref is2D(), @ref translationsRotationsScalings2DInto(), + * @ref hasField(), @ref fieldType(SceneField) const, * @ref translationRotationScaling2DFor() */ Containers::Array> translationsRotationsScalings2DAsArray() const; @@ -1522,7 +1569,7 @@ class MAGNUM_TRADE_EXPORT SceneData { * expected to exist and they are expected to have a type corresponding * to 3D, otherwise you're supposed to use * @ref transformations2DAsArray(). - * @see @ref transformations3DInto(), @ref hasField(), + * @see @ref is3D(), @ref transformations3DInto(), @ref hasField(), * @ref fieldType(SceneField) const, @ref transformation3DFor() */ Containers::Array transformations3DAsArray() const; @@ -1568,8 +1615,8 @@ class MAGNUM_TRADE_EXPORT SceneData { * field isn't present, the second value is an identity rotation. If * the @relativeref{SceneField,Scaling} field isn't present, the third * value is an identity scaling (@cpp 1.0f @ce in all dimensions). - * @see @ref translationsRotationsScalings3DInto(), @ref hasField(), - * @ref fieldType(SceneField) const, + * @see @ref is3D(), @ref translationsRotationsScalings3DInto(), + * @ref hasField(), @ref fieldType(SceneField) const, * @ref translationRotationScaling3DFor() */ Containers::Array> translationsRotationsScalings3DAsArray() const; @@ -2114,7 +2161,8 @@ class MAGNUM_TRADE_EXPORT SceneData { DataFlags _dataFlags; SceneObjectType _objectType; - /* 2/6 bytes free */ + UnsignedByte _dimensions; + /* 1/5 bytes free */ UnsignedLong _objectCount; const void* _importerState; Containers::Array _fields; diff --git a/src/Magnum/Trade/Test/SceneDataTest.cpp b/src/Magnum/Trade/Test/SceneDataTest.cpp index 82dbb87f4..306bdfc0a 100644 --- a/src/Magnum/Trade/Test/SceneDataTest.cpp +++ b/src/Magnum/Trade/Test/SceneDataTest.cpp @@ -96,6 +96,7 @@ struct SceneDataTest: TestSuite::Tester { void constructObjectTypeTooSmall(); void constructNotOwnedFlagOwned(); void constructMismatchedTRSViews(); + template void constructMismatchedTRSDimensionality(); void constructMismatchedMeshMaterialView(); void constructCopy(); @@ -115,16 +116,14 @@ struct SceneDataTest: TestSuite::Tester { void parentsIntoArrayInvalidSizeOrOffset(); template void transformations2DAsArray(); template void transformations2DAsArrayTRS(); - template void transformations2DAsArrayBut3DType(); - template void transformations2DAsArrayBut3DTypeTRS(); + void transformations2DAsArrayBut3DType(); void transformations2DIntoArray(); void transformations2DIntoArrayTRS(); void transformations2DIntoArrayInvalidSizeOrOffset(); void transformations2DIntoArrayInvalidSizeOrOffsetTRS(); template void transformations3DAsArray(); template void transformations3DAsArrayTRS(); - template void transformations3DAsArrayBut2DType(); - template void transformations3DAsArrayBut2DTypeTRS(); + void transformations3DAsArrayBut2DType(); void transformations3DIntoArray(); void transformations3DIntoArrayTRS(); void transformations3DIntoArrayInvalidSizeOrOffset(); @@ -161,12 +160,10 @@ struct SceneDataTest: TestSuite::Tester { void childrenFor(); void transformation2DFor(); void transformation2DForTRS(); - template void transformation2DForBut3DType(); - template void transformation2DForBut3DTypeTRS(); + void transformation2DForBut3DType(); void transformation3DFor(); void transformation3DForTRS(); - template void transformation3DForBut2DType(); - template void transformation3DForBut2DTypeTRS(); + void transformation3DForBut2DType(); void meshesMaterialsFor(); void lightsFor(); void camerasFor(); @@ -253,6 +250,8 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::constructObjectTypeTooSmall, &SceneDataTest::constructNotOwnedFlagOwned, &SceneDataTest::constructMismatchedTRSViews, + &SceneDataTest::constructMismatchedTRSDimensionality, + &SceneDataTest::constructMismatchedTRSDimensionality, &SceneDataTest::constructMismatchedMeshMaterialView, &SceneDataTest::constructCopy, @@ -292,12 +291,7 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::transformations2DAsArray, &SceneDataTest::transformations2DAsArrayTRS, &SceneDataTest::transformations2DAsArrayTRS, - &SceneDataTest::transformations2DAsArrayBut3DType, - &SceneDataTest::transformations2DAsArrayBut3DType, - &SceneDataTest::transformations2DAsArrayBut3DType, - &SceneDataTest::transformations2DAsArrayBut3DType, - &SceneDataTest::transformations2DAsArrayBut3DTypeTRS, - &SceneDataTest::transformations2DAsArrayBut3DTypeTRS}); + &SceneDataTest::transformations2DAsArrayBut3DType}); addInstancedTests({&SceneDataTest::transformations2DIntoArray, &SceneDataTest::transformations2DIntoArrayTRS}, @@ -311,12 +305,7 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::transformations3DAsArray, &SceneDataTest::transformations3DAsArrayTRS, &SceneDataTest::transformations3DAsArrayTRS, - &SceneDataTest::transformations3DAsArrayBut2DType, - &SceneDataTest::transformations3DAsArrayBut2DType, - &SceneDataTest::transformations3DAsArrayBut2DType, - &SceneDataTest::transformations3DAsArrayBut2DType, - &SceneDataTest::transformations3DAsArrayBut2DTypeTRS, - &SceneDataTest::transformations3DAsArrayBut2DTypeTRS}); + &SceneDataTest::transformations3DAsArrayBut2DType}); addInstancedTests({&SceneDataTest::transformations3DIntoArray, &SceneDataTest::transformations3DIntoArrayTRS}, @@ -381,20 +370,10 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::childrenFor, &SceneDataTest::transformation2DFor, &SceneDataTest::transformation2DForTRS, - &SceneDataTest::transformation2DForBut3DType, - &SceneDataTest::transformation2DForBut3DType, - &SceneDataTest::transformation2DForBut3DType, - &SceneDataTest::transformation2DForBut3DType, - &SceneDataTest::transformation2DForBut3DTypeTRS, - &SceneDataTest::transformation2DForBut3DTypeTRS, + &SceneDataTest::transformation2DForBut3DType, &SceneDataTest::transformation3DFor, &SceneDataTest::transformation3DForTRS, - &SceneDataTest::transformation3DForBut2DType, - &SceneDataTest::transformation3DForBut2DType, - &SceneDataTest::transformation3DForBut2DType, - &SceneDataTest::transformation3DForBut2DType, - &SceneDataTest::transformation3DForBut2DTypeTRS, - &SceneDataTest::transformation3DForBut2DTypeTRS, + &SceneDataTest::transformation3DForBut2DType, &SceneDataTest::meshesMaterialsFor, &SceneDataTest::lightsFor, &SceneDataTest::camerasFor, @@ -1136,6 +1115,9 @@ void SceneDataTest::construct() { CORRADE_COMPARE(scene.fieldCount(), 4); CORRADE_COMPARE(scene.importerState(), &importerState); + /* is2D() / is3D() exhaustively tested in transformations*DAsArray[TRS]() + and constructZeroFields() */ + /* Field property access by ID */ CORRADE_COMPARE(scene.fieldName(0), SceneField::Transformation); CORRADE_COMPARE(scene.fieldName(1), SceneField::Parent); @@ -1369,6 +1351,8 @@ void SceneDataTest::constructZeroFields() { CORRADE_COMPARE(scene.objectCount(), 37563); CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedShort); CORRADE_COMPARE(scene.fieldCount(), 0); + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); } void SceneDataTest::constructZeroObjects() { @@ -1660,6 +1644,110 @@ void SceneDataTest::constructMismatchedTRSViews() { "Trade::SceneData: Trade::SceneField::Scaling object data [0xcafe0000:0xcafe0004] is different from Trade::SceneField::Rotation object data [0xcafe0000:0xcafe0008]\n"); } +template struct NameTraits; +#define _c(format) template<> struct NameTraits { \ + static const char* name() { return #format; } \ + }; +_c(UnsignedByte) +_c(Byte) +_c(UnsignedShort) +_c(Short) +_c(UnsignedInt) +_c(Int) +_c(UnsignedLong) +_c(Long) +_c(Float) +_c(Double) +_c(Vector2) +_c(Vector2d) +_c(Vector3) +_c(Vector3d) +_c(Matrix3) +_c(Matrix3d) +_c(Matrix4) +_c(Matrix4d) +_c(Complex) +_c(Complexd) +_c(Quaternion) +_c(Quaterniond) +_c(DualComplex) +_c(DualComplexd) +_c(DualQuaternion) +_c(DualQuaterniond) +template struct NameTraits { + static const char* name() { return "Pointer"; } +}; +template struct NameTraits { + static const char* name() { return "MutablePointer"; } +}; +#undef _c + +template void SceneDataTest::constructMismatchedTRSDimensionality() { + setTestCaseTemplateName(NameTraits::name()); + + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + SceneFieldData transformationMatrices2D{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData transformations2D{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData transformationMatrices3D{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData transformations3D{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData translations2D{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData translations3D{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData rotations2D{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData rotations3D{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData scalings2D{SceneField::Scaling, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + SceneFieldData scalings3D{SceneField::Scaling, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr}; + + /* Test that all pairs get checked */ + std::ostringstream out; + Error redirectError{&out}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices2D, translations3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices2D, rotations3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices2D, scalings3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations2D, translations3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations2D, rotations3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations2D, scalings3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {translations2D, rotations3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {translations2D, scalings3D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {rotations2D, scalings3D}}; + + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices3D, translations2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices3D, rotations2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformationMatrices3D, scalings2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations3D, translations2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations3D, rotations2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {transformations3D, scalings2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {translations3D, rotations2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {translations3D, scalings2D}}; + SceneData{SceneObjectType::UnsignedInt, 0, nullptr, {rotations3D, scalings2D}}; + CORRADE_COMPARE(out.str(), Utility::formatString( + "Trade::SceneData: expected a 2D translation field but got Trade::SceneFieldType::{0}\n" + "Trade::SceneData: expected a 2D rotation field but got Trade::SceneFieldType::{1}\n" + "Trade::SceneData: expected a 2D scaling field but got Trade::SceneFieldType::{0}\n" + "Trade::SceneData: expected a 2D translation field but got Trade::SceneFieldType::{0}\n" + "Trade::SceneData: expected a 2D rotation field but got Trade::SceneFieldType::{1}\n" + "Trade::SceneData: expected a 2D scaling field but got Trade::SceneFieldType::{0}\n" + "Trade::SceneData: expected a 2D rotation field but got Trade::SceneFieldType::{1}\n" + "Trade::SceneData: expected a 2D scaling field but got Trade::SceneFieldType::{0}\n" + "Trade::SceneData: expected a 2D scaling field but got Trade::SceneFieldType::{0}\n" + + "Trade::SceneData: expected a 3D translation field but got Trade::SceneFieldType::{2}\n" + "Trade::SceneData: expected a 3D rotation field but got Trade::SceneFieldType::{3}\n" + "Trade::SceneData: expected a 3D scaling field but got Trade::SceneFieldType::{2}\n" + "Trade::SceneData: expected a 3D translation field but got Trade::SceneFieldType::{2}\n" + "Trade::SceneData: expected a 3D rotation field but got Trade::SceneFieldType::{3}\n" + "Trade::SceneData: expected a 3D scaling field but got Trade::SceneFieldType::{2}\n" + "Trade::SceneData: expected a 3D rotation field but got Trade::SceneFieldType::{3}\n" + "Trade::SceneData: expected a 3D scaling field but got Trade::SceneFieldType::{2}\n" + "Trade::SceneData: expected a 3D scaling field but got Trade::SceneFieldType::{2}\n", + NameTraits>::name(), + NameTraits>::name(), + NameTraits>::name(), + NameTraits>::name())); +} + void SceneDataTest::constructMismatchedMeshMaterialView() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -1744,48 +1832,6 @@ void SceneDataTest::constructMove() { CORRADE_VERIFY(std::is_nothrow_move_assignable::value); } -template struct NameTraits; -#define _c(format) template<> struct NameTraits { \ - static const char* name() { return #format; } \ - }; -_c(UnsignedByte) -_c(Byte) -_c(UnsignedShort) -_c(Short) -_c(UnsignedInt) -_c(Int) -_c(UnsignedLong) -_c(Long) -_c(Float) -_c(Double) -_c(Vector2) -_c(Vector2d) -_c(Vector3) -_c(Vector3d) -_c(Matrix3) -_c(Matrix3x3) -_c(Matrix3d) -_c(Matrix3x3d) -_c(Matrix4) -_c(Matrix4x4) -_c(Matrix4d) -_c(Matrix4x4d) -_c(Complex) -_c(Complexd) -_c(Quaternion) -_c(Quaterniond) -_c(DualComplex) -_c(DualComplexd) -_c(DualQuaternion) -_c(DualQuaterniond) -template struct NameTraits { - static const char* name() { return "Pointer"; } -}; -template struct NameTraits { - static const char* name() { return "MutablePointer"; } -}; -#undef _c - template void SceneDataTest::objectsAsArrayByIndex() { setTestCaseTemplateName(NameTraits::name()); @@ -2165,6 +2211,8 @@ template void SceneDataTest::transformations2DAsArray() { components.slice(&Component::scaling)}, }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3::translation({3.0f, 2.0f}), Matrix3::rotation(35.0_degf), @@ -2216,6 +2264,8 @@ template void SceneDataTest::transformations2DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { translation }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3::translation({3.0f, 2.0f}), Matrix3{Math::IdentityInit}, @@ -2234,6 +2284,8 @@ template void SceneDataTest::transformations2DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { rotation }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3{Math::IdentityInit}, Matrix3::rotation(35.0_degf), @@ -2252,6 +2304,8 @@ template void SceneDataTest::transformations2DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { scaling }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3{Math::IdentityInit}, Matrix3{Math::IdentityInit}, @@ -2274,6 +2328,8 @@ template void SceneDataTest::transformations2DAsArray translation, rotation }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3::translation({3.0f, 2.0f}), Matrix3::rotation(35.0_degf), @@ -2293,6 +2349,8 @@ template void SceneDataTest::transformations2DAsArray translation, scaling }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3::translation({3.0f, 2.0f}), Matrix3{Math::IdentityInit}, @@ -2312,6 +2370,8 @@ template void SceneDataTest::transformations2DAsArray rotation, scaling }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3{Math::IdentityInit}, Matrix3::rotation(35.0_degf), @@ -2335,6 +2395,8 @@ template void SceneDataTest::transformations2DAsArray rotation, scaling }}; + CORRADE_VERIFY(scene.is2D()); + CORRADE_VERIFY(!scene.is3D()); CORRADE_COMPARE_AS(scene.transformations2DAsArray(), Containers::arrayView({ Matrix3::translation({3.0f, 2.0f}), Matrix3::rotation(35.0_degf), @@ -2352,27 +2414,7 @@ template void SceneDataTest::transformations2DAsArray } } -template void SceneDataTest::transformations2DAsArrayBut3DType() { - setTestCaseTemplateName(NameTraits::name()); - - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - SceneData scene{SceneObjectType::UnsignedInt, 0, nullptr, { - SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor::type(), nullptr} - }}; - - std::ostringstream out; - Error redirectError{&out}; - scene.transformations2DAsArray(); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformations2DInto(): field has a 3D transformation type Trade::SceneFieldType::{}\n", NameTraits::name())); -} - -template void SceneDataTest::transformations2DAsArrayBut3DTypeTRS() { - setTestCaseTemplateName(NameTraits::name()); - +void SceneDataTest::transformations2DAsArrayBut3DType() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -2380,40 +2422,19 @@ template void SceneDataTest::transformations2DAsArrayBut3DTypeTRS() { /* Because TRSAsArray() allocates an Array and then calls TRSInto(), which skips views that are nullptr, we wouldn't get the assertion for translations, as those are at offset 0, which would be - interpreted as an empty view if there were no elements. So we have to - supply at least one element to make all assertions trigger. */ - struct Field { - UnsignedInt object; - Math::Vector3 translation; - Math::Quaternion rotation; - Math::Vector3 scaling; - } data[1]; - Containers::StridedArrayView1D view = data; - SceneData translation{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Translation, view.slice(&Field::object), view.slice(&Field::translation)} - }}; - SceneData rotation{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Rotation, view.slice(&Field::object), view.slice(&Field::rotation)} - }}; - SceneData scaling{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Scaling, view.slice(&Field::object), view.slice(&Field::scaling)} + interpreted as an empty view if there were no elements. Thus using + rotations instead. */ + SceneData scene{SceneObjectType::UnsignedInt, 0, nullptr, { + SceneFieldData{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Quaternion, nullptr} }}; std::ostringstream out; Error redirectError{&out}; - translation.transformations2DAsArray(); - translation.translationsRotationsScalings2DAsArray(); - rotation.transformations2DAsArray(); - rotation.translationsRotationsScalings2DAsArray(); - scaling.transformations2DAsArray(); - scaling.translationsRotationsScalings2DAsArray(); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformations2DInto(): field has a 3D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::transformations2DInto(): field has a 3D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::transformations2DInto(): field has a 3D scaling type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationsRotationsScalings2DInto(): field has a 3D scaling type Trade::SceneFieldType::{0}\n", NameTraits>::name(), NameTraits>::name())); + scene.transformations2DAsArray(); + scene.translationsRotationsScalings2DAsArray(); + CORRADE_COMPARE(out.str(), + "Trade::SceneData::transformations2DInto(): scene has a 3D transformation type\n" + "Trade::SceneData::translationsRotationsScalings2DInto(): scene has a 3D transformation type\n"); } void SceneDataTest::transformations2DIntoArray() { @@ -2740,6 +2761,8 @@ template void SceneDataTest::transformations3DAsArray() { components.slice(&Component::scaling)}, }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4::translation({3.0f, 2.0f, -0.5f}), Matrix4::rotationY(35.0_degf), @@ -2791,6 +2814,8 @@ template void SceneDataTest::transformations3DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { translation }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4::translation({3.0f, 2.0, 1.0f}), Matrix4{Math::IdentityInit}, @@ -2809,6 +2834,8 @@ template void SceneDataTest::transformations3DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { rotation }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4{Math::IdentityInit}, Matrix4::rotationY(35.0_degf), @@ -2827,6 +2854,8 @@ template void SceneDataTest::transformations3DAsArray SceneData scene{SceneObjectType::UnsignedInt, 8, {}, fields, { scaling }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4{Math::IdentityInit}, Matrix4{Math::IdentityInit}, @@ -2849,6 +2878,8 @@ template void SceneDataTest::transformations3DAsArray translation, rotation }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4::translation({3.0f, 2.0, 1.0f}), Matrix4::rotationY(35.0_degf), @@ -2868,6 +2899,8 @@ template void SceneDataTest::transformations3DAsArray translation, scaling }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4::translation({3.0f, 2.0, 1.0f}), Matrix4{Math::IdentityInit}, @@ -2887,6 +2920,8 @@ template void SceneDataTest::transformations3DAsArray rotation, scaling }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4{Math::IdentityInit}, Matrix4::rotationY(35.0_degf), @@ -2910,6 +2945,8 @@ template void SceneDataTest::transformations3DAsArray rotation, scaling }}; + CORRADE_VERIFY(!scene.is2D()); + CORRADE_VERIFY(scene.is3D()); CORRADE_COMPARE_AS(scene.transformations3DAsArray(), Containers::arrayView({ Matrix4::translation({3.0f, 2.0, 1.0f}), Matrix4::rotationY(35.0_degf), @@ -2927,27 +2964,7 @@ template void SceneDataTest::transformations3DAsArray } } -template void SceneDataTest::transformations3DAsArrayBut2DType() { - setTestCaseTemplateName(NameTraits::name()); - - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - SceneData scene{SceneObjectType::UnsignedInt, 0, nullptr, { - SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor::type(), nullptr} - }}; - - std::ostringstream out; - Error redirectError{&out}; - scene.transformations3DAsArray(); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformations3DInto(): field has a 2D transformation type Trade::SceneFieldType::{}\n", NameTraits::name())); -} - -template void SceneDataTest::transformations3DAsArrayBut2DTypeTRS() { - setTestCaseTemplateName(NameTraits::name()); - +void SceneDataTest::transformations3DAsArrayBut2DType() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -2955,40 +2972,19 @@ template void SceneDataTest::transformations3DAsArrayBut2DTypeTRS() { /* Because TRSAsArray() allocates an Array and then calls TRSInto(), which skips views that are nullptr, we wouldn't get the assertion for translations, as those are at offset 0, which would be - interpreted as an empty view if there were no elements. So we have to - supply at least one element to make all assertions trigger. */ - struct Field { - UnsignedInt object; - Math::Vector2 translation; - Math::Complex rotation; - Math::Vector2 scaling; - } data[1]; - Containers::StridedArrayView1D view = data; - SceneData translation{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Translation, view.slice(&Field::object), view.slice(&Field::translation)} - }}; - SceneData rotation{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Rotation, view.slice(&Field::object), view.slice(&Field::rotation)} - }}; - SceneData scaling{SceneObjectType::UnsignedInt, 1, {}, data, { - SceneFieldData{SceneField::Scaling, view.slice(&Field::object), view.slice(&Field::scaling)} + interpreted as an empty view if there were no elements. Thus using + rotations instead. */ + SceneData scene{SceneObjectType::UnsignedInt, 0, nullptr, { + SceneFieldData{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Complex, nullptr} }}; std::ostringstream out; Error redirectError{&out}; - translation.transformations3DAsArray(); - translation.translationsRotationsScalings3DAsArray(); - rotation.transformations3DAsArray(); - rotation.translationsRotationsScalings3DAsArray(); - scaling.transformations3DAsArray(); - scaling.translationsRotationsScalings3DAsArray(); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformations3DInto(): field has a 2D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::transformations3DInto(): field has a 2D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::transformations3DInto(): field has a 2D scaling type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationsRotationsScalings3DInto(): field has a 2D scaling type Trade::SceneFieldType::{0}\n", NameTraits>::name(), NameTraits>::name())); + scene.transformations3DAsArray(); + scene.translationsRotationsScalings3DAsArray(); + CORRADE_COMPARE(out.str(), + "Trade::SceneData::transformations3DInto(): scene has a 2D transformation type\n" + "Trade::SceneData::translationsRotationsScalings3DInto(): scene has a 2D transformation type\n"); } void SceneDataTest::transformations3DIntoArray() { @@ -4387,56 +4383,22 @@ void SceneDataTest::transformation2DForTRS() { Containers::NullOpt); } -template void SceneDataTest::transformation2DForBut3DType() { - setTestCaseTemplateName(NameTraits::name()); - +void SceneDataTest::transformation2DForBut3DType() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif SceneData scene{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor::type(), nullptr} + SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Vector3, nullptr} }}; std::ostringstream out; Error redirectError{&out}; scene.transformation2DFor(0); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformation2DFor(): field has a 3D transformation type Trade::SceneFieldType::{}\n", NameTraits::name())); -} - -template void SceneDataTest::transformation2DForBut3DTypeTRS() { - setTestCaseTemplateName(NameTraits::name()); - - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - SceneData translation{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - SceneData rotation{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - SceneData scaling{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Scaling, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - - std::ostringstream out; - Error redirectError{&out}; - translation.transformation2DFor(0); - translation.translationRotationScaling2DFor(0); - rotation.transformation2DFor(0); - rotation.translationRotationScaling2DFor(0); - scaling.transformation2DFor(0); - scaling.translationRotationScaling2DFor(0); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformation2DFor(): field has a 3D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::transformation2DFor(): field has a 3D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::transformation2DFor(): field has a 3D scaling type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationRotationScaling2DFor(): field has a 3D scaling type Trade::SceneFieldType::{0}\n", NameTraits>::name(), NameTraits>::name())); + scene.translationRotationScaling2DFor(0); + CORRADE_COMPARE(out.str(), + "Trade::SceneData::transformation2DFor(): scene has a 3D transformation type\n" + "Trade::SceneData::translationRotationScaling2DFor(): scene has a 3D transformation type\n"); } void SceneDataTest::transformation3DFor() { @@ -4513,56 +4475,22 @@ void SceneDataTest::transformation3DForTRS() { Containers::NullOpt); } -template void SceneDataTest::transformation3DForBut2DType() { - setTestCaseTemplateName(NameTraits::name()); - +void SceneDataTest::transformation3DForBut2DType() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif SceneData scene{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor::type(), nullptr} + SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Vector2, nullptr} }}; std::ostringstream out; Error redirectError{&out}; scene.transformation3DFor(0); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformation3DFor(): field has a 2D transformation type Trade::SceneFieldType::{}\n", NameTraits::name())); -} - -template void SceneDataTest::transformation3DForBut2DTypeTRS() { - setTestCaseTemplateName(NameTraits::name()); - - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - SceneData translation{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - SceneData rotation{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Rotation, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - SceneData scaling{SceneObjectType::UnsignedInt, 1, nullptr, { - SceneFieldData{SceneField::Scaling, SceneObjectType::UnsignedInt, nullptr, Implementation::SceneFieldTypeFor>::type(), nullptr} - }}; - - std::ostringstream out; - Error redirectError{&out}; - translation.transformation3DFor(0); - translation.translationRotationScaling3DFor(0); - rotation.transformation3DFor(0); - rotation.translationRotationScaling3DFor(0); - scaling.transformation3DFor(0); - scaling.translationRotationScaling3DFor(0); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Trade::SceneData::transformation3DFor(): field has a 2D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D translation type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::transformation3DFor(): field has a 2D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D rotation type Trade::SceneFieldType::{1}\n" - "Trade::SceneData::transformation3DFor(): field has a 2D scaling type Trade::SceneFieldType::{0}\n" - "Trade::SceneData::translationRotationScaling3DFor(): field has a 2D scaling type Trade::SceneFieldType::{0}\n", NameTraits>::name(), NameTraits>::name())); + scene.translationRotationScaling3DFor(0); + CORRADE_COMPARE(out.str(), + "Trade::SceneData::transformation3DFor(): scene has a 2D transformation type\n" + "Trade::SceneData::translationRotationScaling3DFor(): scene has a 2D transformation type\n"); } void SceneDataTest::meshesMaterialsFor() {