/*
This file is part of Magnum .
Copyright © 2010 , 2011 , 2012 , 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 ,
2020 , 2021 , 2022 , 2023 Vladimír Vondruš < mosra @ centrum . cz >
Permission is hereby granted , free of charge , to any person obtaining a
copy of this software and associated documentation files ( the " Software " ) ,
to deal in the Software without restriction , including without limitation
the rights to use , copy , modify , merge , publish , distribute , sublicense ,
and / or sell copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE .
*/
# include <sstream>
# include <Corrade/Containers/GrowableArray.h>
# include <Corrade/Containers/Optional.h>
# include <Corrade/Containers/Pair.h>
# include <Corrade/Containers/StridedBitArrayView.h>
# include <Corrade/Containers/StringView.h>
# include <Corrade/Containers/StringIterable.h>
# include <Corrade/TestSuite/Tester.h>
# include <Corrade/TestSuite/Compare/Container.h>
# include <Corrade/TestSuite/Compare/Numeric.h>
# include <Corrade/Utility/DebugStl.h>
# include "Magnum/Math/Complex.h"
# include "Magnum/Math/Vector2.h"
# include "Magnum/SceneTools/Combine.h"
# include "Magnum/Trade/SceneData.h"
namespace Magnum { namespace SceneTools { namespace Test { namespace {
struct CombineTest : TestSuite : : Tester {
explicit CombineTest ( ) ;
void fields ( ) ;
template < class T > void fieldsStrings ( ) ;
void fieldsAlignment ( ) ;
void fieldsMappingShared ( ) ;
void fieldsMappingSharedPartial ( ) ;
void fieldsMappingPlaceholderFieldPlaceholder ( ) ;
void fieldsMappingSharedFieldPlaceholder ( ) ;
void fieldsMappingSharedTRSPlaceholder ( ) ;
void fieldsMappingSharedMeshMaterialPlaceholder ( ) ;
void fieldsSharedMappingExpected ( ) ;
void fieldsStringPlaceholder ( ) ;
void fieldsOffsetOnly ( ) ;
void fieldsFromDataOffsetOnly ( ) ;
} ;
using namespace Containers : : Literals ;
const struct {
const char * name ;
Trade : : SceneMappingType objectType ;
} FieldsData [ ] {
{ " UnsignedByte output " , Trade : : SceneMappingType : : UnsignedByte } ,
{ " UnsignedShort output " , Trade : : SceneMappingType : : UnsignedShort } ,
{ " UnsignedInt output " , Trade : : SceneMappingType : : UnsignedInt } ,
{ " UnsignedLong output " , Trade : : SceneMappingType : : UnsignedLong } ,
} ;
const struct {
const char * name ;
bool translationPresent , rotationPresent , scalingPresent ;
/* Either all or none can be placeholders */
bool placeholders ;
} FieldsMappingSharedTRSPlaceholderData [ ] {
{ " all " ,
true , true , true ,
false } ,
{ " all, placeholders " ,
true , true , true ,
true } ,
{ " rotation & scaling " ,
false , true , true ,
false } ,
{ " rotation & scaling, placeholders " ,
false , true , true ,
true } ,
{ " translation & scaling " ,
true , false , true ,
false } ,
{ " translation & scaling, placeholders " ,
true , false , true ,
true } ,
{ " translation & rotation " ,
true , true , false ,
false } ,
{ " translation & rotation, placeholders " ,
true , true , false ,
true } ,
{ " translation " ,
true , false , false ,
false } ,
{ " translation, placeholder " ,
true , false , false ,
true } ,
{ " rotation " ,
false , true , false ,
false } ,
{ " rotation, placeholder " ,
false , true , false ,
true } ,
{ " scaling " ,
false , false , true ,
false } ,
{ " scaling, placeholder " ,
false , false , true ,
true } ,
} ;
const struct {
const char * name ;
bool meshPresent , meshMaterialPresent ;
/* Either all or none can be placeholders */
bool placeholders ;
} FieldsMappingSharedMeshMaterialPlaceholderData [ ] {
{ " both placeholders " ,
true , true ,
false } ,
{ " no placeholders " ,
true , true ,
true } ,
{ " just mesh present, placeholder " ,
true , false ,
false } ,
{ " just mesh present, not a placeholder " ,
true , false ,
true } ,
{ " just mesh material present, placeholder " ,
false , true ,
false } ,
{ " just mesh material present, not a placeholder " ,
false , true ,
true } ,
} ;
CombineTest : : CombineTest ( ) {
addInstancedTests ( { & CombineTest : : fields } ,
Containers : : arraySize ( FieldsData ) ) ;
addTests ( { & CombineTest : : fieldsStrings < UnsignedByte > ,
& CombineTest : : fieldsStrings < UnsignedShort > ,
& CombineTest : : fieldsStrings < UnsignedInt > ,
& CombineTest : : fieldsStrings < UnsignedLong > ,
& CombineTest : : fieldsAlignment ,
& CombineTest : : fieldsMappingShared ,
& CombineTest : : fieldsMappingSharedPartial ,
& CombineTest : : fieldsMappingPlaceholderFieldPlaceholder ,
& CombineTest : : fieldsMappingSharedFieldPlaceholder } ) ;
addInstancedTests ( { & CombineTest : : fieldsMappingSharedTRSPlaceholder } ,
Containers : : arraySize ( FieldsMappingSharedTRSPlaceholderData ) ) ;
addInstancedTests ( { & CombineTest : : fieldsMappingSharedMeshMaterialPlaceholder } ,
Containers : : arraySize ( FieldsMappingSharedMeshMaterialPlaceholderData ) ) ;
addTests ( { & CombineTest : : fieldsSharedMappingExpected ,
& CombineTest : : fieldsStringPlaceholder ,
& CombineTest : : fieldsOffsetOnly ,
& CombineTest : : fieldsFromDataOffsetOnly } ) ;
}
using namespace Math : : Literals ;
void CombineTest : : fields ( ) {
auto & & data = FieldsData [ testCaseInstanceId ( ) ] ;
setTestCaseDescription ( data . name ) ;
/* Testing the four possible object types, it should be possible to combine
them . Make them all non - contiguous to catch accidents in the internal
casting / copying code . */
const struct Mesh {
UnsignedInt mapping ;
UnsignedByte mesh ;
} meshData [ ] {
{ 45 , 3 } ,
{ 78 , 5 } ,
{ 23 , 17 }
} ;
auto meshes = Containers : : stridedArrayView ( meshData ) ;
const struct Parent {
UnsignedShort mapping ;
Short parent ;
} parentData [ ] {
{ 0 , - 1 } ,
{ 1 , 0 }
} ;
auto parents = Containers : : stridedArrayView ( parentData ) ;
const struct Translation {
UnsignedByte mapping ;
Vector2d translation ;
} translationData [ ] {
{ 16 , { 1.5 , - 0.5 } }
} ;
auto translations = Containers : : stridedArrayView ( translationData ) ;
const struct Foo {
UnsignedLong mapping ;
Int foo [ 2 ] ;
} fooData [ ] {
{ 15 , { 0 , 1 } } ,
{ 23 , { 2 , 3 } }
} ;
auto foos = Containers : : stridedArrayView ( fooData ) ;
const struct Bool {
UnsignedShort mapping ;
bool bit ;
} boolData [ ] {
{ 23 , false } ,
{ 24 , true } ,
{ 25 , false } ,
{ 26 , true }
} ;
auto bools = Containers : : stridedArrayView ( boolData ) ;
const struct Bits {
UnsignedByte mapping ;
UnsignedByte bits ;
} bitsData [ ] {
{ 13 , 1 < < 3 | 1 < < 4 } ,
{ 25 , 1 < < 4 } ,
{ 77 , 1 < < 1 | 1 < < 2 | 1 < < 3 } ,
} ;
auto bits = Containers : : stridedArrayView ( bitsData ) ;
Trade : : SceneData scene = combineFields ( data . objectType , 167 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
meshes . slice ( & Mesh : : mapping ) ,
meshes . slice ( & Mesh : : mesh ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Parent ,
parents . slice ( & Parent : : mapping ) ,
parents . slice ( & Parent : : parent ) ,
Trade : : SceneFieldFlag : : ImplicitMapping } ,
Trade : : SceneFieldData { Trade : : SceneField : : Translation ,
translations . slice ( & Translation : : mapping ) ,
translations . slice ( & Translation : : translation ) } ,
/* Array field */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 15 ) ,
foos . slice ( & Foo : : mapping ) ,
Containers : : arrayCast < 2 , const Int > ( foos . slice ( & Foo : : foo ) ) ,
Trade : : SceneFieldFlag : : OrderedMapping } ,
/* Empty field */
Trade : : SceneFieldData { Trade : : SceneField : : Camera , Containers : : ArrayView < const UnsignedByte > { } , Containers : : ArrayView < const UnsignedShort > { } } ,
/* Bit field */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 16 ) ,
bools . slice ( & Bool : : mapping ) ,
bools . slice ( & Bool : : bit ) . sliceBit ( 0 ) ,
Trade : : SceneFieldFlag : : ImplicitMapping } ,
/* Bit array field */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 17 ) ,
bits . slice ( & Bits : : mapping ) ,
Containers : : StridedBitArrayView2D { Containers : : BitArrayView { bitsData } , & bitsData [ 0 ] . bits , 1 , { 3 , 4 } , { sizeof ( Bits ) * 8 , 1 } } ,
Trade : : SceneFieldFlag : : OrderedMapping } ,
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , data . objectType ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 167 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 7 ) ;
CORRADE_COMPARE ( scene . fieldName ( 0 ) , Trade : : SceneField : : Mesh ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 0 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 0 ) , Trade : : SceneFieldType : : UnsignedByte ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 0 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 0 ) , Containers : : arrayView < UnsignedInt > ( {
45 , 78 , 23
} ) , TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( 0 ) ,
meshes . slice ( & Mesh : : mesh ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 1 ) , Trade : : SceneField : : Parent ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 1 ) , Trade : : SceneFieldFlag : : ImplicitMapping ) ;
CORRADE_COMPARE ( scene . fieldType ( 1 ) , Trade : : SceneFieldType : : Short ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 1 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 1 ) , Containers : : arrayView < UnsignedInt > ( {
0 , 1
} ) , TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < Short > ( 1 ) ,
parents . slice ( & Parent : : parent ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 2 ) , Trade : : SceneField : : Translation ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 2 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 2 ) , Trade : : SceneFieldType : : Vector2d ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 2 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 2 ) ,
Containers : : arrayView < UnsignedInt > ( { 16 } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < Vector2d > ( 2 ) ,
translations . slice ( & Translation : : translation ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 3 ) , Trade : : sceneFieldCustom ( 15 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 3 ) , Trade : : SceneFieldFlag : : OrderedMapping ) ;
CORRADE_COMPARE ( scene . fieldType ( 3 ) , Trade : : SceneFieldType : : Int ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 3 ) , 2 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 3 ) ,
Containers : : arrayView < UnsignedInt > ( { 15 , 23 } ) ,
TestSuite : : Compare : : Container ) ;
/** @todo clean up once it's possible to compare multidimensional
containers */
CORRADE_COMPARE_AS ( scene . field < Int [ ] > ( 3 ) [ 0 ] ,
( Containers : : arrayCast < 2 , const Int > ( foos . slice ( & Foo : : foo ) ) ) [ 0 ] ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < Int [ ] > ( 3 ) [ 1 ] ,
( Containers : : arrayCast < 2 , const Int > ( foos . slice ( & Foo : : foo ) ) ) [ 1 ] ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 4 ) , Trade : : SceneField : : Camera ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 4 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 4 ) , Trade : : SceneFieldType : : UnsignedShort ) ;
CORRADE_COMPARE ( scene . fieldSize ( 4 ) , 0 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 4 ) , 0 ) ;
CORRADE_COMPARE ( scene . fieldName ( 5 ) , Trade : : sceneFieldCustom ( 16 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 5 ) , Trade : : SceneFieldFlag : : ImplicitMapping ) ;
CORRADE_COMPARE ( scene . fieldType ( 5 ) , Trade : : SceneFieldType : : Bit ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 5 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 5 ) ,
Containers : : arrayView ( { 23u , 24u , 25u , 26u } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldBits ( 5 ) ,
Containers : : stridedArrayView ( { false , true , false , true } ) . sliceBit ( 0 ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 6 ) , Trade : : sceneFieldCustom ( 17 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 6 ) , Trade : : SceneFieldFlag : : OrderedMapping ) ;
CORRADE_COMPARE ( scene . fieldType ( 6 ) , Trade : : SceneFieldType : : Bit ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 6 ) , 4 ) ;
CORRADE_COMPARE_AS ( scene . mappingAsArray ( 6 ) ,
Containers : : arrayView ( { 13u , 25u , 77u } ) ,
TestSuite : : Compare : : Container ) ;
/** @todo clean up once it's possible to compare multidimensional
containers */
CORRADE_COMPARE_AS ( scene . fieldBitArrays ( 6 ) [ 0 ] ,
Containers : : stridedArrayView ( { false , false , true , true } ) . sliceBit ( 0 ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldBitArrays ( 6 ) [ 1 ] ,
Containers : : stridedArrayView ( { false , false , false , true } ) . sliceBit ( 0 ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldBitArrays ( 6 ) [ 2 ] ,
Containers : : stridedArrayView ( { true , true , true , false } ) . sliceBit ( 0 ) ,
TestSuite : : Compare : : Container ) ;
}
/* Taken from SceneDataTest */
template < class T > struct StringFieldTraits ;
template < > struct StringFieldTraits < UnsignedByte > {
static const char * name ( ) { return " 8 " ; }
static Trade : : SceneFieldType offsetType ( ) { return Trade : : SceneFieldType : : StringOffset8 ; }
static Trade : : SceneFieldType rangeType ( ) { return Trade : : SceneFieldType : : StringRange8 ; }
static Trade : : SceneFieldType rangeNullTerminatedType ( ) {
return Trade : : SceneFieldType : : StringRangeNullTerminated8 ;
}
} ;
template < > struct StringFieldTraits < UnsignedShort > {
static const char * name ( ) { return " 16 " ; }
static Trade : : SceneFieldType offsetType ( ) { return Trade : : SceneFieldType : : StringOffset16 ; }
static Trade : : SceneFieldType rangeType ( ) { return Trade : : SceneFieldType : : StringRange16 ; }
static Trade : : SceneFieldType rangeNullTerminatedType ( ) {
return Trade : : SceneFieldType : : StringRangeNullTerminated16 ;
}
} ;
template < > struct StringFieldTraits < UnsignedInt > {
static const char * name ( ) { return " 32 " ; }
static Trade : : SceneFieldType offsetType ( ) { return Trade : : SceneFieldType : : StringOffset32 ; }
static Trade : : SceneFieldType rangeType ( ) { return Trade : : SceneFieldType : : StringRange32 ; }
static Trade : : SceneFieldType rangeNullTerminatedType ( ) {
return Trade : : SceneFieldType : : StringRangeNullTerminated32 ;
}
} ;
template < > struct StringFieldTraits < UnsignedLong > {
static const char * name ( ) { return " 64 " ; }
static Trade : : SceneFieldType offsetType ( ) { return Trade : : SceneFieldType : : StringOffset64 ; }
static Trade : : SceneFieldType rangeType ( ) { return Trade : : SceneFieldType : : StringRange64 ; }
static Trade : : SceneFieldType rangeNullTerminatedType ( ) {
return Trade : : SceneFieldType : : StringRangeNullTerminated64 ;
}
} ;
template < class T > void CombineTest : : fieldsStrings ( ) {
setTestCaseTemplateName ( StringFieldTraits < T > : : name ( ) ) ;
/* Null-terminated ranges */
Containers : : StringView tagStrings =
" SOFT \0 " /* 0 */
" mouldy! " _s ; /* 5, assumes it's stored null-terminated */
/* With null termination it's 13 bytes. If only 12 would be copied, the
next ArrayTuple item ( likely Name : : mapping ) would get aligned right
after , failing the null terminator check */
CORRADE_COMPARE ( tagStrings . size ( ) , 12 ) ;
const struct Tag {
UnsignedByte mapping ;
T rangeNullTerminated ;
} tagsData [ ] {
{ 3 , 0 } ,
{ 7 , 5 } ,
{ 7 , 0 } ,
{ 1 , 0 }
} ;
auto tags = Containers : : stridedArrayView ( tagsData ) ;
/* Non-null-terminated offsets */
Containers : : StringView nameStrings =
" Chair " /* 5 */
" Lampshade " /* 14 */
" Sofa37 " _s ; /* 20 */
CORRADE_COMPARE ( nameStrings . size ( ) , 20 ) ;
const struct Name {
UnsignedByte mapping ;
T offset ;
} namesData [ ] {
{ 3 , 5 } ,
{ 7 , 14 } ,
{ 1 , 20 }
} ;
auto names = Containers : : stridedArrayView ( namesData ) ;
/* Null-terminated offsets */
Containers : : StringView keyStrings =
" color \0 " /* 6 */
" age \0 " /* 10 */
" age " _s ; /* 14, assumes it's stored null-terminated */
const struct Key {
UnsignedByte mapping ;
T offsetNullTerminated ;
} keysData [ ] {
{ 11 , 6 } ,
{ 3 , 10 } ,
{ 12 , 14 }
} ;
auto keys = Containers : : stridedArrayView ( keysData ) ;
Containers : : StringView valueStrings =
" light \0 brown " /* 0, 11 */
" ancient " /* 11, 7 */
" new " _s ; /* 18, 3 */
/* Non-null-terminated ranges */
const struct Value {
UnsignedByte mapping ;
Containers : : Pair < T , T > range ;
} valuesData [ ] {
{ 3 , { 18 , 3 } } ,
{ 12 , { 11 , 7 } } ,
{ 7 , { 18 , 3 } } ,
{ 11 , { 0 , 11 } }
} ;
auto values = Containers : : stridedArrayView ( valuesData ) ;
/* Using just 8-bit mapping to not have any extra padding between things
and thus better catch accidentally forgotten null termination and
such */
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedByte , 167 , {
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 0 ) ,
tags . slice ( & Tag : : mapping ) ,
tagStrings . data ( ) , StringFieldTraits < T > : : rangeNullTerminatedType ( ) ,
tags . slice ( & Tag : : rangeNullTerminated ) } ,
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 1 ) ,
names . slice ( & Name : : mapping ) ,
nameStrings . data ( ) , StringFieldTraits < T > : : offsetType ( ) ,
names . slice ( & Name : : offset ) } ,
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 2 ) ,
keys . slice ( & Key : : mapping ) ,
keyStrings . data ( ) , StringFieldTraits < T > : : offsetType ( ) ,
keys . slice ( & Key : : offsetNullTerminated ) ,
Trade : : SceneFieldFlag : : NullTerminatedString } ,
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 3 ) ,
values . slice ( & Value : : mapping ) ,
valueStrings . data ( ) , StringFieldTraits < T > : : rangeType ( ) ,
values . slice ( & Value : : range ) } ,
/* Empty string field, shouldn't crash or anything */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 4 ) ,
Containers : : ArrayView < const UnsignedByte > { } ,
nullptr , StringFieldTraits < T > : : offsetType ( ) ,
Containers : : ArrayView < const T > { } } ,
} ) ;
CORRADE_COMPARE ( scene . fieldName ( 0 ) , Trade : : sceneFieldCustom ( 0 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 0 ) , Trade : : SceneFieldFlag : : NullTerminatedString ) ;
CORRADE_COMPARE ( scene . fieldType ( 0 ) , StringFieldTraits < T > : : rangeNullTerminatedType ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedByte > ( 0 ) ,
tags . slice ( & Tag : : mapping ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < T > ( 0 ) ,
tags . slice ( & Tag : : rangeNullTerminated ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldStrings ( 0 ) ,
( Containers : : StringIterable { " SOFT " , " mouldy! " , " SOFT " , " SOFT " } ) ,
TestSuite : : Compare : : Container ) ;
/* All should stay null-terminated -- i.e., the null terminator included in
the size calculation when the string gets copied */
for ( Containers : : StringView i : scene . fieldStrings ( 0 ) ) {
CORRADE_COMPARE ( i . flags ( ) , Containers : : StringViewFlag : : NullTerminated ) ;
CORRADE_COMPARE ( i [ i . size ( ) ] , ' \0 ' ) ;
}
CORRADE_COMPARE ( scene . fieldName ( 1 ) , Trade : : sceneFieldCustom ( 1 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 1 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 1 ) , StringFieldTraits < T > : : offsetType ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedByte > ( 1 ) ,
names . slice ( & Name : : mapping ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < T > ( 1 ) ,
names . slice ( & Name : : offset ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldStrings ( 1 ) ,
( Containers : : StringIterable { " Chair " , " Lampshade " , " Sofa37 " } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 2 ) , Trade : : sceneFieldCustom ( 2 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 2 ) , Trade : : SceneFieldFlag : : NullTerminatedString ) ;
CORRADE_COMPARE ( scene . fieldType ( 2 ) , StringFieldTraits < T > : : offsetType ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedByte > ( 2 ) ,
keys . slice ( & Key : : mapping ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < T > ( 2 ) ,
keys . slice ( & Key : : offsetNullTerminated ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldStrings ( 2 ) ,
( Containers : : StringIterable { " color " , " age " , " age " } ) ,
TestSuite : : Compare : : Container ) ;
/* All should stay null-terminated -- i.e., the null terminator included in
the size calculation when the string gets copied */
for ( Containers : : StringView i : scene . fieldStrings ( 2 ) ) {
CORRADE_COMPARE ( i . flags ( ) , Containers : : StringViewFlag : : NullTerminated ) ;
CORRADE_COMPARE ( i [ i . size ( ) ] , ' \0 ' ) ;
}
CORRADE_COMPARE ( scene . fieldName ( 3 ) , Trade : : sceneFieldCustom ( 3 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 3 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 3 ) , StringFieldTraits < T > : : rangeType ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedByte > ( 3 ) ,
values . slice ( & Value : : mapping ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( ( scene . field < Containers : : Pair < T , T > > ( 3 ) ) ,
values . slice ( & Value : : range ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldStrings ( 3 ) ,
( Containers : : StringIterable { " new " , " ancient " , " new " , " light \0 brown " _s } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldName ( 4 ) , Trade : : sceneFieldCustom ( 4 ) ) ;
CORRADE_COMPARE ( scene . fieldFlags ( 4 ) , Trade : : SceneFieldFlags { } ) ;
CORRADE_COMPARE ( scene . fieldType ( 4 ) , StringFieldTraits < T > : : offsetType ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedByte > ( 4 ) ,
Containers : : ArrayView < const UnsignedByte > { } ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( ( scene . field < T > ( 4 ) ) ,
Containers : : ArrayView < const T > { } ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . fieldStrings ( 4 ) ,
Containers : : StringIterable { } ,
TestSuite : : Compare : : Container ) ;
}
void CombineTest : : fieldsAlignment ( ) {
const UnsignedShort meshMappingData [ ] { 15 , 23 , 47 } ;
const UnsignedByte meshFieldData [ ] { 0 , 1 , 2 } ;
const UnsignedShort translationMappingData [ ] { 5 } ; /* 1 byte padding before */
const Vector2d translationFieldData [ ] { { 1.5 , 3.0 } } ; /* 4 byte padding before */
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedShort , 167 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : arrayView ( meshFieldData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Translation ,
Containers : : arrayView ( translationMappingData ) ,
Containers : : arrayView ( translationFieldData ) }
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , Trade : : SceneMappingType : : UnsignedShort ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 167 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 2 ) ;
CORRADE_COMPARE ( scene . fieldName ( 0 ) , Trade : : SceneField : : Mesh ) ;
CORRADE_COMPARE ( scene . fieldType ( 0 ) , Trade : : SceneFieldType : : UnsignedByte ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 0 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedShort > ( 0 ) ,
Containers : : arrayView ( meshMappingData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( 0 ) ,
Containers : : arrayView ( meshFieldData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( reinterpret_cast < std : : ptrdiff_t > ( scene . mapping ( 0 ) . data ( ) ) , 2 , TestSuite : : Compare : : Divisible ) ;
CORRADE_COMPARE ( scene . mapping ( 0 ) . data ( ) , scene . data ( ) ) ;
CORRADE_COMPARE ( scene . mapping ( 0 ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE_AS ( reinterpret_cast < std : : ptrdiff_t > ( scene . field ( 0 ) . data ( ) ) , 1 , TestSuite : : Compare : : Divisible ) ;
CORRADE_COMPARE ( scene . field ( 0 ) . data ( ) , scene . data ( ) + 3 * 2 ) ;
CORRADE_COMPARE ( scene . field ( 0 ) . stride ( ) [ 0 ] , 1 ) ;
CORRADE_COMPARE ( scene . fieldName ( 1 ) , Trade : : SceneField : : Translation ) ;
CORRADE_COMPARE ( scene . fieldType ( 1 ) , Trade : : SceneFieldType : : Vector2d ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( 1 ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedShort > ( 1 ) ,
Containers : : arrayView ( translationMappingData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < Vector2d > ( 1 ) ,
Containers : : arrayView ( translationFieldData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( reinterpret_cast < std : : ptrdiff_t > ( scene . mapping ( 1 ) . data ( ) ) , 2 , TestSuite : : Compare : : Divisible ) ;
CORRADE_COMPARE ( scene . mapping ( 1 ) . data ( ) , scene . data ( ) + 3 * 2 + 3 + 1 ) ;
CORRADE_COMPARE ( scene . mapping ( 1 ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE_AS ( reinterpret_cast < std : : ptrdiff_t > ( scene . field ( 1 ) . data ( ) ) , 8 , TestSuite : : Compare : : Divisible ) ;
CORRADE_COMPARE ( scene . field ( 1 ) . data ( ) , scene . data ( ) + 3 * 2 + 3 + 1 + 2 + 4 ) ;
CORRADE_COMPARE ( scene . field ( 1 ) . stride ( ) [ 0 ] , 16 ) ;
}
void CombineTest : : fieldsMappingShared ( ) {
const UnsignedShort meshMappingData [ 3 ] { } ;
const UnsignedByte meshFieldData [ 3 ] { } ;
const Int meshMaterialFieldData [ 3 ] { } ;
const UnsignedShort translationRotationMappingData [ 2 ] { } ;
const Vector2 translationFieldData [ 2 ] { } ;
const Complex rotationFieldData [ 2 ] { } ;
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , {
/* Deliberately in an arbitrary order to avoid false assumptions like
fields sharing the same object mapping always being after each
other */
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : arrayView ( meshFieldData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Translation ,
Containers : : arrayView ( translationRotationMappingData ) ,
Containers : : arrayView ( translationFieldData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : MeshMaterial ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : arrayView ( meshMaterialFieldData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Rotation ,
Containers : : arrayView ( translationRotationMappingData ) ,
Containers : : arrayView ( rotationFieldData ) }
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , Trade : : SceneMappingType : : UnsignedInt ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 173 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 4 ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : Mesh ) , 3 ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : MeshMaterial ) , 3 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Mesh ) . data ( ) , scene . mapping ( Trade : : SceneField : : MeshMaterial ) . data ( ) ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : Translation ) , 2 ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : Rotation ) , 2 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Translation ) . data ( ) , scene . mapping ( Trade : : SceneField : : Rotation ) . data ( ) ) ;
}
void CombineTest : : fieldsMappingSharedPartial ( ) {
const UnsignedShort mappingData [ ] { 15 , 23 , 47 , 26 , 3 } ;
/* Field data don't have any special treatment so their values aren't
tested */
const UnsignedByte meshData [ 3 ] { } ;
const UnsignedShort lightData [ 2 ] { } ;
const Int parentData [ 3 ] { } ;
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : arrayView ( mappingData ) . prefix ( 3 ) ,
Containers : : arrayView ( meshData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Light ,
Containers : : arrayView ( mappingData ) . prefix ( 2 ) ,
Containers : : arrayView ( lightData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Parent ,
Containers : : stridedArrayView ( mappingData ) . every ( 2 ) ,
Containers : : arrayView ( parentData ) } ,
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , Trade : : SceneMappingType : : UnsignedInt ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 173 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 3 ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedInt > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( { 15u , 23u , 47u } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedInt > ( Trade : : SceneField : : Light ) ,
Containers : : arrayView ( { 15u , 23u } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedInt > ( Trade : : SceneField : : Parent ) ,
Containers : : arrayView ( { 15u , 47u , 3u } ) ,
TestSuite : : Compare : : Container ) ;
/* All mappings should be deinterleaved */
for ( UnsignedInt i = 0 ; i ! = scene . fieldCount ( ) ; + + i ) {
CORRADE_ITERATION ( scene . fieldName ( i ) ) ;
CORRADE_COMPARE ( scene . mapping < UnsignedInt > ( i ) . stride ( ) , sizeof ( UnsignedInt ) ) ;
}
}
void CombineTest : : fieldsMappingPlaceholderFieldPlaceholder ( ) {
const UnsignedShort meshMappingData [ ] { 15 , 23 , 47 } ;
const UnsignedByte meshFieldData [ ] { 0 , 1 , 2 } ;
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedShort , 173 , {
Trade : : SceneFieldData { Trade : : SceneField : : Camera ,
Containers : : ArrayView < UnsignedByte > { nullptr , 1 } ,
Containers : : ArrayView < UnsignedShort > { nullptr , 1 } } ,
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : arrayView ( meshFieldData ) } ,
/* Looks like sharing object mapping with the Camera field, but
actually both are placeholders */
Trade : : SceneFieldData { Trade : : SceneField : : Light ,
Containers : : ArrayView < UnsignedShort > { nullptr , 2 } ,
Containers : : ArrayView < UnsignedInt > { nullptr , 2 } } ,
/* Array field */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 15 ) ,
Containers : : ArrayView < UnsignedShort > { nullptr , 2 } ,
Containers : : StridedArrayView2D < Short > { { nullptr , 16 } , { 2 , 4 } } } ,
/* Bit array field */
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 16 ) ,
Containers : : ArrayView < UnsignedLong > { nullptr , 3 } ,
Containers : : StridedBitArrayView2D { { nullptr , 1 , 8 } , { 3 , 2 } } } ,
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , Trade : : SceneMappingType : : UnsignedShort ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 173 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 5 ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : SceneField : : Camera ) , Trade : : SceneFieldType : : UnsignedShort ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : Camera ) , 1 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : SceneField : : Camera ) , 0 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Camera ) . data ( ) , scene . data ( ) ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Camera ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : Camera ) . data ( ) , scene . data ( ) + 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : Camera ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : SceneField : : Mesh ) , Trade : : SceneFieldType : : UnsignedByte ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : SceneField : : Mesh ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedShort > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( meshMappingData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( meshFieldData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : SceneField : : Light ) , Trade : : SceneFieldType : : UnsignedInt ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : Light ) , 2 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : SceneField : : Light ) , 0 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Light ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : Light ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : Light ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 + 2 * 2 + 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : Light ) . stride ( ) [ 0 ] , 4 ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : sceneFieldCustom ( 15 ) ) , Trade : : SceneFieldType : : Short ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : sceneFieldCustom ( 15 ) ) , 2 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : sceneFieldCustom ( 15 ) ) , 4 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : sceneFieldCustom ( 15 ) ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 + 2 * 2 + 2 + 2 * 4 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : sceneFieldCustom ( 15 ) ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : sceneFieldCustom ( 15 ) ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 + 2 * 2 + 2 + 2 * 4 + 2 * 2 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : sceneFieldCustom ( 15 ) ) . stride ( ) [ 0 ] , 4 * 2 ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : sceneFieldCustom ( 16 ) ) , Trade : : SceneFieldType : : Bit ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : sceneFieldCustom ( 16 ) ) , 3 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : sceneFieldCustom ( 16 ) ) , 2 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : sceneFieldCustom ( 16 ) ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 + 2 * 2 + 2 + 2 * 4 + 2 * 2 + 2 * 8 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : sceneFieldCustom ( 16 ) ) . stride ( ) [ 0 ] , 2 ) ;
CORRADE_COMPARE ( scene . fieldBitArrays ( Trade : : sceneFieldCustom ( 16 ) ) . data ( ) ,
scene . data ( ) + 2 + 2 + 3 * 2 + 3 + 1 + 2 * 2 + 2 + 2 * 4 + 2 * 2 + 2 * 8 + 3 * 2 ) ;
CORRADE_COMPARE ( scene . fieldBitArrays ( Trade : : sceneFieldCustom ( 16 ) ) . offset ( ) , 0 ) ;
CORRADE_COMPARE ( scene . fieldBitArrays ( Trade : : sceneFieldCustom ( 16 ) ) . stride ( ) [ 0 ] , 2 ) ;
}
void CombineTest : : fieldsMappingSharedFieldPlaceholder ( ) {
const UnsignedInt meshMappingData [ ] { 15 , 23 , 47 } ;
const UnsignedByte meshFieldData [ ] { 0 , 1 , 2 } ;
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : arrayView ( meshFieldData ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : MeshMaterial ,
Containers : : arrayView ( meshMappingData ) ,
Containers : : ArrayView < Int > { nullptr , 3 } } ,
} ) ;
CORRADE_COMPARE ( scene . dataFlags ( ) , Trade : : DataFlag : : Owned | Trade : : DataFlag : : Mutable ) ;
CORRADE_COMPARE ( scene . mappingType ( ) , Trade : : SceneMappingType : : UnsignedInt ) ;
CORRADE_COMPARE ( scene . mappingBound ( ) , 173 ) ;
CORRADE_COMPARE ( scene . fieldCount ( ) , 2 ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : SceneField : : Mesh ) , Trade : : SceneFieldType : : UnsignedByte ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : SceneField : : Mesh ) , 0 ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedInt > ( 0 ) ,
Containers : : arrayView ( meshMappingData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( 0 ) ,
Containers : : arrayView ( meshFieldData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . fieldType ( Trade : : SceneField : : MeshMaterial ) , Trade : : SceneFieldType : : Int ) ;
CORRADE_COMPARE ( scene . fieldSize ( Trade : : SceneField : : MeshMaterial ) , 3 ) ;
CORRADE_COMPARE ( scene . fieldArraySize ( Trade : : SceneField : : MeshMaterial ) , 0 ) ;
CORRADE_COMPARE ( scene . mapping ( Trade : : SceneField : : MeshMaterial ) . data ( ) , scene . mapping ( Trade : : SceneField : : Mesh ) . data ( ) ) ;
CORRADE_COMPARE_AS ( scene . mapping < UnsignedInt > ( Trade : : SceneField : : MeshMaterial ) ,
Containers : : arrayView ( meshMappingData ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : MeshMaterial ) . data ( ) , scene . data ( ) + 3 * 4 + 3 + 1 ) ;
CORRADE_COMPARE ( scene . field ( Trade : : SceneField : : MeshMaterial ) . stride ( ) [ 0 ] , 4 ) ;
}
void CombineTest : : fieldsMappingSharedTRSPlaceholder ( ) {
auto & & data = FieldsMappingSharedTRSPlaceholderData [ testCaseInstanceId ( ) ] ;
setTestCaseDescription ( data . name ) ;
const UnsignedShort mapping [ ] { 13 , 31 , 67 } ;
const Vector2 translationData [ ] { { 1.0f , 2.0f } , { 3.0f , 4.0f } , { 5.0f , 6.0f } } ;
const Complex rotationData [ ] { Complex : : rotation ( 30.0 _degf ) , Complex : : rotation ( 60.0 _degf ) , Complex : : rotation ( 90.0 _degf ) } ;
const Vector2 scalingData [ ] { { 7.0f , - 1.0f } , { 8.0f , - 2.0f } , { 9.0f , - 3.0f } } ;
const UnsignedByte meshData [ ] { 5 , 7 , 119 } ;
Containers : : Array < Trade : : SceneFieldData > fields ;
if ( data . translationPresent ) arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Translation ,
data . placeholders ?
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } :
Containers : : arrayView ( mapping ) ,
Containers : : arrayView ( translationData ) ) ;
if ( data . rotationPresent ) arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Rotation ,
data . placeholders ?
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } :
Containers : : arrayView ( mapping ) ,
Containers : : arrayView ( rotationData ) ) ;
/* Add a placeholder mapping field from another share group with the same
pointer / size / stride to verify they don ' t get shared by accident ; add it
among the other fields to avoid them accidentally being treated as always
together */
arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Mesh ,
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } ,
Containers : : arrayView ( meshData ) ) ;
if ( data . scalingPresent ) arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Scaling ,
data . placeholders ?
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } :
Containers : : arrayView ( mapping ) ,
Containers : : arrayView ( scalingData ) ) ;
/* The assertions inside SceneData will verify that the mapping is
shared */
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , fields ) ;
Containers : : StridedArrayView1D < const UnsignedInt > mappingData ;
if ( data . translationPresent ) {
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Translation ) ) ;
CORRADE_COMPARE_AS ( scene . field < Vector2 > ( Trade : : SceneField : : Translation ) ,
Containers : : arrayView ( translationData ) ,
TestSuite : : Compare : : Container ) ;
mappingData = scene . mapping < UnsignedInt > ( Trade : : SceneField : : Translation ) ;
}
if ( data . rotationPresent ) {
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Rotation ) ) ;
CORRADE_COMPARE_AS ( scene . field < Complex > ( Trade : : SceneField : : Rotation ) ,
Containers : : arrayView ( rotationData ) ,
TestSuite : : Compare : : Container ) ;
mappingData = scene . mapping < UnsignedInt > ( Trade : : SceneField : : Rotation ) ;
}
if ( data . scalingPresent ) {
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Scaling ) ) ;
CORRADE_COMPARE_AS ( scene . field < Vector2 > ( Trade : : SceneField : : Scaling ) ,
Containers : : arrayView ( scalingData ) ,
TestSuite : : Compare : : Container ) ;
mappingData = scene . mapping < UnsignedInt > ( Trade : : SceneField : : Scaling ) ;
}
if ( ! data . placeholders )
CORRADE_COMPARE_AS ( mappingData ,
Containers : : arrayView ( { 13u , 31u , 67u } ) ,
TestSuite : : Compare : : Container ) ;
/* The other field should be copied as well, but with its own mapping
data */
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Mesh ) ) ;
CORRADE_VERIFY ( scene . mapping ( Trade : : SceneField : : Mesh ) . data ( ) ! = mappingData . data ( ) ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( meshData ) ,
TestSuite : : Compare : : Container ) ;
}
void CombineTest : : fieldsMappingSharedMeshMaterialPlaceholder ( ) {
auto & & data = FieldsMappingSharedMeshMaterialPlaceholderData [ testCaseInstanceId ( ) ] ;
setTestCaseDescription ( data . name ) ;
const UnsignedShort mapping [ ] { 13 , 31 , 67 } ;
const UnsignedByte meshData [ ] { 5 , 7 , 119 } ;
const Int meshMaterialData [ ] { 25 , - 1 , 23 } ;
const Vector2 translationData [ ] { { 1.0f , 2.0f } , { 3.0f , 4.0f } , { 5.0f , 6.0f } } ;
Containers : : Array < Trade : : SceneFieldData > fields ;
if ( data . meshPresent ) arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Mesh ,
data . placeholders ?
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } :
Containers : : arrayView ( mapping ) ,
Containers : : arrayView ( meshData ) ) ;
/* Add a placeholder mapping field from another share group to verify
they ' re not shared by accident ; add it among the other fields to avoid
them accidentally being treated as always together */
arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : Translation ,
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } ,
Containers : : arrayView ( translationData ) ) ;
if ( data . meshMaterialPresent ) arrayAppend ( fields , InPlaceInit ,
Trade : : SceneField : : MeshMaterial ,
data . placeholders ?
Containers : : ArrayView < UnsignedShort > { nullptr , 3 } :
Containers : : arrayView ( mapping ) ,
Containers : : arrayView ( meshMaterialData ) ) ;
/* The assertions inside SceneData will verify that the mapping is
shared */
Trade : : SceneData scene = combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , fields ) ;
Containers : : StridedArrayView1D < const UnsignedInt > mappingData ;
if ( data . meshPresent ) {
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Mesh ) ) ;
CORRADE_COMPARE_AS ( scene . field < UnsignedByte > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( meshData ) ,
TestSuite : : Compare : : Container ) ;
mappingData = scene . mapping < UnsignedInt > ( Trade : : SceneField : : Mesh ) ;
}
if ( data . meshMaterialPresent ) {
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : MeshMaterial ) ) ;
CORRADE_COMPARE_AS ( scene . field < Int > ( Trade : : SceneField : : MeshMaterial ) ,
Containers : : arrayView ( meshMaterialData ) ,
TestSuite : : Compare : : Container ) ;
mappingData = scene . mapping < UnsignedInt > ( Trade : : SceneField : : MeshMaterial ) ;
}
if ( ! data . placeholders )
CORRADE_COMPARE_AS ( mappingData ,
Containers : : arrayView ( { 13u , 31u , 67u } ) ,
TestSuite : : Compare : : Container ) ;
/* The other field should be copied as well, but with its own mapping
data */
CORRADE_VERIFY ( scene . hasField ( Trade : : SceneField : : Translation ) ) ;
CORRADE_VERIFY ( scene . mapping ( Trade : : SceneField : : Translation ) . data ( ) ! = mappingData . data ( ) ) ;
CORRADE_COMPARE_AS ( scene . field < Vector2 > ( Trade : : SceneField : : Translation ) ,
Containers : : arrayView ( translationData ) ,
TestSuite : : Compare : : Container ) ;
}
void CombineTest : : fieldsSharedMappingExpected ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
/* Tested thoroughly in SceneDataTest::constructMismatchedTRSViews() and
constructMismatchedMeshMaterialViews ( ) , here it uses the same internal
utility so test just that it ' s correctly called */
UnsignedInt meshes [ 3 ] { } ;
Int materials [ 3 ] { } ;
std : : ostringstream out ;
Error redirectError { & out } ;
combineFields ( Trade : : SceneMappingType : : UnsignedInt , 3 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : ArrayView < UnsignedInt > { reinterpret_cast < UnsignedInt * > ( 0xdead ) , 3 } ,
Containers : : arrayView ( meshes ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : MeshMaterial ,
Containers : : ArrayView < UnsignedInt > { reinterpret_cast < UnsignedInt * > ( 0xbeef ) , 2 } ,
Containers : : arrayView ( materials ) . prefix ( 2 ) } ,
} ) ;
combineFields ( Trade : : SceneMappingType : : UnsignedInt , 3 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
Containers : : ArrayView < UnsignedInt > { reinterpret_cast < UnsignedInt * > ( 0xdead ) , 3 } ,
Containers : : arrayView ( meshes ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : MeshMaterial ,
Containers : : ArrayView < UnsignedInt > { nullptr , 3 } ,
Containers : : arrayView ( materials ) } ,
} ) ;
CORRADE_COMPARE ( out . str ( ) ,
" SceneTools::combineFields(): Trade::SceneField::MeshMaterial mapping data {0xbeef, 2, 4} is different from Trade::SceneField::Mesh mapping data {0xdead, 3, 4} \n "
/* Placeholder mapping is also disallowed right now -- it has to be
either all placeholders or none */
" SceneTools::combineFields(): Trade::SceneField::MeshMaterial mapping data {0x0, 3, 4} is different from Trade::SceneField::Mesh mapping data {0xdead, 3, 4} \n " ) ;
}
void CombineTest : : fieldsStringPlaceholder ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
const struct Data {
UnsignedByte mapping ;
UnsignedByte mesh ;
} data [ 3 ] { } ;
auto view = Containers : : stridedArrayView ( data ) ;
std : : ostringstream out ;
Error redirectError { & out } ;
/* A null string data pointer could work in this case (because it doesn't
need to be accessed ) , but disallowing it always for consistency */
combineFields ( Trade : : SceneMappingType : : UnsignedByte , 167 , {
/* Just to verify it prints correct field IDs */
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
view . slice ( & Data : : mapping ) ,
view . slice ( & Data : : mesh ) } ,
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 16 ) ,
view . slice ( & Data : : mapping ) ,
nullptr , Trade : : SceneFieldType : : StringOffset8 ,
/* Have to fake a pointer because in some cases (ARM64 Linux) the
distance between nullptr and stack - allocated memory ( such as
` data ` ) * may * be larger than what can fit into 48 bits ,
triggering an assert */
Containers : : arrayView ( reinterpret_cast < UnsignedByte * > ( 0xfece5 ) , 3 ) } ,
} ) ;
/* With placeholder field data it's impossible to know the actual string
size */
combineFields ( Trade : : SceneMappingType : : UnsignedByte , 167 , {
Trade : : SceneFieldData { Trade : : sceneFieldCustom ( 16 ) ,
view . slice ( & Data : : mapping ) ,
/* Have to fake a pointer because in some cases (ARM64 Linux) the
distance between nullptr and stack - allocated memory ( such as
` data ` ) * may * be larger than what can fit into 48 bits ,
triggering an assert */
reinterpret_cast < char * > ( 0xfece5 ) , Trade : : SceneFieldType : : StringRangeNullTerminated16 ,
Containers : : StridedArrayView1D < const UnsignedShort > { { nullptr , 6 } , 3 } } ,
} ) ;
CORRADE_COMPARE ( out . str ( ) ,
" SceneTools::combineFields(): string field 1 has a placeholder string data \n "
" SceneTools::combineFields(): string field 0 has a placeholder data \n " ) ;
}
void CombineTest : : fieldsOffsetOnly ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
const struct Field {
UnsignedInt mapping ;
UnsignedByte mesh ;
UnsignedShort light ;
} data [ ] {
{ 1 , 3 , 5 } ,
{ 4 , 6 , 8 } ,
} ;
auto view = Containers : : stridedArrayView ( data ) ;
std : : ostringstream out ;
Error redirectError { & out } ;
combineFields ( Trade : : SceneMappingType : : UnsignedInt , 173 , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
view . slice ( & Field : : mapping ) ,
view . slice ( & Field : : mesh ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Light , 2 ,
Trade : : SceneMappingType : : UnsignedInt , offsetof ( Field , mapping ) , sizeof ( Field ) ,
Trade : : SceneFieldType : : UnsignedShort , offsetof ( Field , light ) , sizeof ( Field ) }
} ) ;
CORRADE_COMPARE ( out . str ( ) , " SceneTools::combineFields(): field 1 is offset-only \n " ) ;
}
void CombineTest : : fieldsFromDataOffsetOnly ( ) {
/* Same as fieldFromData(), but wrapped in a Scene first, which makes it
work */
const struct Field {
UnsignedInt mapping ;
UnsignedByte mesh ;
UnsignedShort light ;
} data [ ] {
{ 1 , 3 , 5 } ,
{ 4 , 6 , 8 } ,
} ;
auto view = Containers : : stridedArrayView ( data ) ;
Trade : : SceneData scene { Trade : : SceneMappingType : : UnsignedInt , 22 , { } , data , {
Trade : : SceneFieldData { Trade : : SceneField : : Mesh ,
view . slice ( & Field : : mapping ) ,
view . slice ( & Field : : mesh ) } ,
Trade : : SceneFieldData { Trade : : SceneField : : Light , 2 ,
Trade : : SceneMappingType : : UnsignedInt , offsetof ( Field , mapping ) , sizeof ( Field ) ,
Trade : : SceneFieldType : : UnsignedShort , offsetof ( Field , light ) , sizeof ( Field ) }
} } ;
Trade : : SceneData combined = combineFields ( scene ) ;
/* Since it's tightly packed, it's less data now */
CORRADE_COMPARE ( combined . data ( ) . size ( ) , 2 * 4 + 2 * 1 + 2 * 2 ) ;
CORRADE_COMPARE_AS ( combined . data ( ) . size ( ) , sizeof ( data ) ,
TestSuite : : Compare : : Less ) ;
/* The two mappings are shared */
CORRADE_COMPARE_AS ( combined . mapping < UnsignedInt > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView ( { 1u , 4u } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( combined . mapping < UnsignedInt > ( Trade : : SceneField : : Light ) ,
Containers : : arrayView ( { 1u , 4u } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE ( combined . mapping ( Trade : : SceneField : : Light ) . data ( ) , combined . mapping ( Trade : : SceneField : : Mesh ) . data ( ) ) ;
CORRADE_COMPARE_AS ( combined . field < UnsignedByte > ( Trade : : SceneField : : Mesh ) ,
Containers : : arrayView < UnsignedByte > ( { 3 , 6 } ) ,
TestSuite : : Compare : : Container ) ;
CORRADE_COMPARE_AS ( combined . field < UnsignedShort > ( Trade : : SceneField : : Light ) ,
Containers : : arrayView < UnsignedShort > ( { 5 , 8 } ) ,
TestSuite : : Compare : : Container ) ;
}
} } } }
CORRADE_TEST_MAIN ( Magnum : : SceneTools : : Test : : CombineTest )