mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1224 lines
42 KiB
1224 lines
42 KiB
/* |
|
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 <vector> |
|
#include <Corrade/Containers/Array.h> |
|
#include <Corrade/Containers/StridedBitArrayView.h> |
|
#include <Corrade/Containers/Pair.h> |
|
#include <Corrade/Containers/StridedArrayView.h> |
|
#include <Corrade/Containers/StringStl.h> /** @todo remove once Debug is stream-free */ |
|
#include <Corrade/TestSuite/Tester.h> |
|
#include <Corrade/TestSuite/Compare/Container.h> |
|
#include <Corrade/TestSuite/Compare/String.h> |
|
#include <Corrade/Utility/DebugStl.h> |
|
#include <Corrade/Utility/FormatStl.h> |
|
|
|
#include "Magnum/Math/Range.h" |
|
#include "Magnum/TextureTools/Atlas.h" |
|
|
|
namespace Magnum { namespace TextureTools { namespace Test { namespace { |
|
|
|
struct AtlasTest: TestSuite::Tester { |
|
explicit AtlasTest(); |
|
|
|
void debugLandfillFlag(); |
|
void debugLandfillFlags(); |
|
|
|
void landfillFullFit(); |
|
void landfill(); |
|
void landfillIncremental(); |
|
void landfillNoFit(); |
|
void landfillCopy(); |
|
void landfillMove(); |
|
|
|
void landfillArrayFullFit(); |
|
void landfillArray(); |
|
void landfillArrayIncremental(); |
|
void landfillArrayNoFit(); |
|
void landfillArrayCopy(); |
|
void landfillArrayMove(); |
|
|
|
void landfillInvalidSize(); |
|
void landfillSetFlagsInvalid(); |
|
void landfillAddMissingRotations(); |
|
void landfillAddInvalidViewSizes(); |
|
void landfillAddTooLargeElement(); |
|
|
|
void basic(); |
|
void padding(); |
|
void empty(); |
|
void tooSmall(); |
|
|
|
void arrayPowerOfTwoEmpty(); |
|
void arrayPowerOfTwoSingleElement(); |
|
void arrayPowerOfTwoAllSameElements(); |
|
void arrayPowerOfTwoOneLayer(); |
|
void arrayPowerOfTwoMoreLayers(); |
|
void arrayPowerOfTwoInvalidViewSizes(); |
|
void arrayPowerOfTwoWrongLayerSize(); |
|
void arrayPowerOfTwoWrongSize(); |
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void arrayPowerOfTwoDeprecated(); |
|
#endif |
|
}; |
|
|
|
const Vector2i LandfillSizes[]{ |
|
{3, 6}, /* 0 */ |
|
{2, 5}, /* 1 */ |
|
{4, 2}, /* 2 */ |
|
{3, 3}, /* 3 */ |
|
{2, 3}, /* 4 */ |
|
{3, 3}, /* 5 */ |
|
{2, 2}, /* 6 */ |
|
{2, 1}, /* 7 */ |
|
{2, 2}, /* 8 */ |
|
{2, 2}, /* 9 */ |
|
{2, 1}, /* a */ |
|
{1, 2}, /* b */ |
|
{1, 1}, /* c */ |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
AtlasLandfillFlags flags; |
|
Vector2i size; |
|
Vector2i filledSize; |
|
Containers::Pair<Vector2i, bool> offsetsFlips[Containers::arraySize(LandfillSizes)]; |
|
} LandfillData[]{ |
|
/* In all of these, rectangles with the same size should keep their order. |
|
5 after 3, 9 after 8 after 6 (and b after a after 7 if they're rotated |
|
to the same orientation) */ |
|
{"no rotation, no width sorting", {}, {11, 12}, {11, 10}, { |
|
/* 99b |
|
99b77 |
|
8866 aac |
|
88662222 |
|
000 2222555 |
|
00011 555 |
|
00011 555 |
|
0001133344 |
|
0001133344 |
|
0001133344 */ |
|
{{0, 0}, false}, /* 0 */ |
|
{{3, 0}, false}, /* 1 */ |
|
{{4, 5}, false}, /* 2 */ |
|
{{5, 0}, false}, /* 3 */ |
|
{{8, 0}, false}, /* 4 */ |
|
{{8, 3}, false}, /* 5 */ |
|
{{2, 6}, false}, /* 6 */ |
|
{{3, 8}, false}, /* 7 */ |
|
{{0, 6}, false}, /* 8 */ |
|
{{0, 8}, false}, /* 9 */ |
|
{{5, 7}, false}, /* a */ |
|
{{2, 8}, false}, /* b */ |
|
{{7, 7}, false}}}, /* c */ |
|
/* No rotation with width sorting omitted, not interesting */ |
|
{"portrait, no width sorting", AtlasLandfillFlag::RotatePortrait, {11, 12}, {11, 10}, { |
|
/* 99a |
|
99ab |
|
88bc |
|
88766555 |
|
00076655544 |
|
00011 55544 |
|
0001122 44 |
|
0001122333 |
|
0001122333 |
|
0001122333 */ |
|
{{0, 0}, false}, /* 0 */ |
|
{{3, 0}, false}, /* 1 */ |
|
{{5, 0}, true}, /* 2 */ |
|
{{7, 0}, false}, /* 3 */ |
|
{{9, 3}, false}, /* 4 */ |
|
{{6, 4}, false}, /* 5 */ |
|
{{4, 5}, false}, /* 6 */ |
|
{{3, 5}, true}, /* 7 */ |
|
{{1, 6}, false}, /* 8 */ |
|
{{0, 8}, false}, /* 9 */ |
|
{{2, 8}, true}, /* a */ |
|
{{3, 7}, false}, /* b */ |
|
{{4, 7}, false}}}, /* c */ |
|
{"portrait, widest first", AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst, {11, 12}, {11, 10}, { |
|
/* 7ab |
|
7abc |
|
9988 |
|
99886644 |
|
000 6644555 |
|
00011 44555 |
|
0001122 555 |
|
0001122333 |
|
0001122333 |
|
0001122333 */ |
|
{{0, 0}, false}, /* 0 */ |
|
{{3, 0}, false}, /* 1 */ |
|
{{5, 0}, true}, /* 2 */ |
|
{{7, 0}, false}, /* 3 */ |
|
{{6, 4}, false}, /* 4 */ |
|
{{8, 3}, false}, /* 5 */ |
|
{{4, 5}, false}, /* 6 */ |
|
{{0, 8}, true}, /* 7 */ |
|
{{2, 6}, false}, /* 8 */ |
|
{{0, 6}, false}, /* 9 */ |
|
{{1, 8}, true}, /* a */ |
|
{{2, 8}, false}, /* b */ |
|
{{3, 8}, false}}}, /* c */ |
|
{"portrait, widest first, unbounded height", AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst, {11, 0}, {11, 10}, { |
|
/* Should have the same result as above |
|
7ab |
|
7abc |
|
9988 |
|
99886644 |
|
000 6644555 |
|
00011 44555 |
|
0001122 555 |
|
0001122333 |
|
0001122333 |
|
0001122333 */ |
|
{{0, 0}, false}, /* 0 */ |
|
{{3, 0}, false}, /* 1 */ |
|
{{5, 0}, true}, /* 2 */ |
|
{{7, 0}, false}, /* 3 */ |
|
{{6, 4}, false}, /* 4 */ |
|
{{8, 3}, false}, /* 5 */ |
|
{{4, 5}, false}, /* 6 */ |
|
{{0, 8}, true}, /* 7 */ |
|
{{2, 6}, false}, /* 8 */ |
|
{{0, 6}, false}, /* 9 */ |
|
{{1, 8}, true}, /* a */ |
|
{{2, 8}, false}, /* b */ |
|
{{3, 8}, false}}}, /* c */ |
|
{"portrait, narrowest first", AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::NarrowestFirst, {11, 12}, {11, 10}, { |
|
/* 8899 |
|
8899 |
|
66b c |
|
66ba7555 |
|
000a7555333 |
|
00011555333 |
|
0001122 333 |
|
000112244 |
|
000112244 |
|
000112244 */ |
|
{{0, 0}, false}, /* 0 */ |
|
{{3, 0}, false}, /* 1 */ |
|
{{5, 0}, true}, /* 2 */ |
|
{{8, 3}, false}, /* 3 */ |
|
{{7, 0}, false}, /* 4 */ |
|
{{5, 4}, false}, /* 5 */ |
|
{{0, 6}, false}, /* 6 */ |
|
{{4, 5}, true}, /* 7 */ |
|
{{0, 8}, false}, /* 8 */ |
|
{{2, 8}, false}, /* 9 */ |
|
{{3, 5}, true}, /* a */ |
|
{{2, 6}, false}, /* b */ |
|
{{4, 7}, false}}}, /* c */ |
|
{"landscape, no width sorting", AtlasLandfillFlag::RotateLandscape, {11, 12}, {11, 10}, { |
|
/* 99 |
|
7799 |
|
cbbaa6688 |
|
22224446688 |
|
2222444 555 |
|
11111555 |
|
11111555 |
|
000000333 |
|
000000333 |
|
000000333 */ |
|
{{0, 0}, true}, /* 0 */ |
|
{{3, 3}, true}, /* 1 */ |
|
{{0, 5}, false}, /* 2 */ |
|
{{6, 0}, false}, /* 3 */ |
|
{{4, 5}, true}, /* 4 */ |
|
{{8, 3}, false}, /* 5 */ |
|
{{7, 6}, false}, /* 6 */ |
|
{{7, 8}, false}, /* 7 */ |
|
{{9, 6}, false}, /* 8 */ |
|
{{9, 8}, false}, /* 9 */ |
|
{{5, 7}, false}, /* a */ |
|
{{3, 7}, true}, /* b */ |
|
{{2, 7}, false}}}, /* c */ |
|
{"landscape, widest first", AtlasLandfillFlag::RotateLandscape|AtlasLandfillFlag::WidestFirst, {11, 12}, {11, 10}, { |
|
/* No change compared to "no width sorting" in this case |
|
99 |
|
7799 |
|
cbbaa6688 |
|
22224446688 |
|
2222444 555 |
|
11111555 |
|
11111555 |
|
000000333 |
|
000000333 |
|
000000333 */ |
|
{{0, 0}, true}, /* 0 */ |
|
{{3, 3}, true}, /* 1 */ |
|
{{0, 5}, false}, /* 2 */ |
|
{{6, 0}, false}, /* 3 */ |
|
{{4, 5}, true}, /* 4 */ |
|
{{8, 3}, false}, /* 5 */ |
|
{{7, 6}, false}, /* 6 */ |
|
{{7, 8}, false}, /* 7 */ |
|
{{9, 6}, false}, /* 8 */ |
|
{{9, 8}, false}, /* 9 */ |
|
{{5, 7}, false}, /* a */ |
|
{{3, 7}, true}, /* b */ |
|
{{2, 7}, false}}}, /* c */ |
|
{"landscape, narrowest first", AtlasLandfillFlag::RotateLandscape|AtlasLandfillFlag::NarrowestFirst, {11, 12}, {11, 10}, { |
|
/* 11111 |
|
bb c11111 |
|
aa772222 |
|
994442222 |
|
99444000000 |
|
8866000000 |
|
8866000000 |
|
333555 |
|
333555 |
|
333555 */ |
|
{{5, 3}, true}, /* 0 */ |
|
{{6, 8}, true}, /* 1 */ |
|
{{5, 6}, false}, /* 2 */ |
|
{{0, 0}, false}, /* 3 */ |
|
{{2, 5}, true}, /* 4 */ |
|
{{3, 0}, false}, /* 5 */ |
|
{{3, 3}, false}, /* 6 */ |
|
{{3, 7}, false}, /* 7 */ |
|
{{1, 3}, false}, /* 8 */ |
|
{{0, 5}, false}, /* 9 */ |
|
{{1, 7}, false}, /* a */ |
|
{{0, 8}, true}, /* b */ |
|
{{5, 8}, false}}}, /* c */ |
|
}; |
|
|
|
const Vector2i LandfillArraySizes[]{ |
|
{3, 6}, /* 0 */ |
|
{2, 5}, /* 1 */ |
|
{4, 2}, /* 2 */ |
|
{3, 3}, /* 3 */ |
|
{3, 3}, /* 4 */ |
|
{2, 2}, /* 5 */ |
|
{2, 2}, /* 6 */ |
|
{2, 1}, /* 7 */ |
|
{2, 2}, /* 8 */ |
|
{2, 2}, /* 9 */ |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
AtlasLandfillFlags flags; |
|
Vector3i size; |
|
Vector3i filledSize; |
|
Containers::Pair<Vector3i, bool> offsetsFlips[Containers::arraySize(LandfillArraySizes)]; |
|
} LandfillArrayData[]{ |
|
/* Various sorting aspects are tested in landfill() already, this just |
|
checks the array-specific behaviors and the rotation-less overload */ |
|
{"no rotation", {}, {11, 6, 3}, {11, 6, 2}, { |
|
/* 000 |
|
00011552222 |
|
00011552222 |
|
00011333444 |
|
00011333444 668899 |
|
00011333444 66889977 */ |
|
{{0, 0, 0}, false}, /* 0 */ |
|
{{3, 0, 0}, false}, /* 1 */ |
|
{{7, 3, 0}, false}, /* 2 */ |
|
{{5, 0, 0}, false}, /* 3 */ |
|
{{8, 0, 0}, false}, /* 4 */ |
|
{{5, 3, 0}, false}, /* 5 */ |
|
{{0, 0, 1}, false}, /* 6 */ |
|
{{6, 0, 1}, false}, /* 7 */ |
|
{{2, 0, 1}, false}, /* 8 */ |
|
{{4, 0, 1}, false}}}, /* 9 */ |
|
{"portrait, widest first", AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst, {11, 6, 3}, {11, 6, 2}, { |
|
/* 000 55444 |
|
00011 55444 |
|
0001122 444 |
|
0001122333 |
|
0001122333 6688997 |
|
0001122333 6688997 */ |
|
{{0, 0, 0}, false}, /* 0 */ |
|
{{3, 0, 0}, false}, /* 1 */ |
|
{{5, 0, 0}, true}, /* 2 */ |
|
{{7, 0, 0}, false}, /* 3 */ |
|
{{8, 3, 0}, false}, /* 4 */ |
|
{{6, 4, 0}, false}, /* 5 */ |
|
{{0, 0, 1}, false}, /* 6 */ |
|
{{6, 0, 1}, true}, /* 7 */ |
|
{{2, 0, 1}, false}, /* 8 */ |
|
{{4, 0, 1}, false}}}, /* 9 */ |
|
{"portrait, widest first, unbounded", AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst, {11, 6, 3}, {11, 6, 2}, { |
|
/* Should have the same result as above |
|
000 55444 |
|
00011 55444 |
|
0001122 444 |
|
0001122333 |
|
0001122333 6688997 |
|
0001122333 6688997 */ |
|
{{0, 0, 0}, false}, /* 0 */ |
|
{{3, 0, 0}, false}, /* 1 */ |
|
{{5, 0, 0}, true}, /* 2 */ |
|
{{7, 0, 0}, false}, /* 3 */ |
|
{{8, 3, 0}, false}, /* 4 */ |
|
{{6, 4, 0}, false}, /* 5 */ |
|
{{0, 0, 1}, false}, /* 6 */ |
|
{{6, 0, 1}, true}, /* 7 */ |
|
{{2, 0, 1}, false}, /* 8 */ |
|
{{4, 0, 1}, false}}}, /* 9 */ |
|
}; |
|
|
|
/* Could make order[15] and then Containers::arraySize(), but then it won't |
|
work on MSVC2015 and cause overly complicated code elsewhere */ |
|
constexpr std::size_t ArrayPowerOfTwoOneLayerImageCount = 15; |
|
const struct { |
|
const char* name; |
|
std::size_t order[ArrayPowerOfTwoOneLayerImageCount]; |
|
} ArrayPowerOfTwoOneLayerData[]{ |
|
{"sorted", |
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}}, |
|
{"", |
|
/* Because there are duplicate sizes, the shuffling needs to preserve |
|
the original order of duplicates to match the output */ |
|
{0, 2, 7, 13, 11, 3, 4, 5, 8, 14, 1, 9, 6, 12, 10}}, |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
Vector2i size; |
|
const char* message; |
|
} ArrayPowerOfTwoWrongLayerSizeData[]{ |
|
{"non-power-of-two", {128, 127}, "{128, 127}"}, |
|
{"non-square", {128, 256}, "{128, 256}"}, |
|
{"zero", {1024, 0}, "{1024, 0}"}, |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
Vector2i size; |
|
const char* message; |
|
} ArrayPowerOfTwoWrongSizeData[]{ |
|
{"larger than size", {512, 512}, "{512, 512}"}, |
|
{"non-power-of-two", {128, 127}, "{128, 127}"}, |
|
{"non-square", {128, 256}, "{128, 256}"}, |
|
{"zero", {1024, 0}, "{1024, 0}"}, |
|
}; |
|
|
|
AtlasTest::AtlasTest() { |
|
addTests({&AtlasTest::debugLandfillFlag, |
|
&AtlasTest::debugLandfillFlags, |
|
|
|
&AtlasTest::landfillFullFit}); |
|
|
|
addInstancedTests({&AtlasTest::landfill}, |
|
Containers::arraySize(LandfillData)); |
|
|
|
addTests({&AtlasTest::landfillIncremental, |
|
&AtlasTest::landfillNoFit, |
|
&AtlasTest::landfillCopy, |
|
&AtlasTest::landfillMove, |
|
|
|
&AtlasTest::landfillArrayFullFit}); |
|
|
|
addInstancedTests({&AtlasTest::landfillArray}, |
|
Containers::arraySize(LandfillArrayData)); |
|
|
|
addTests({&AtlasTest::landfillArrayIncremental, |
|
&AtlasTest::landfillArrayNoFit, |
|
&AtlasTest::landfillArrayCopy, |
|
&AtlasTest::landfillArrayMove, |
|
|
|
&AtlasTest::landfillInvalidSize, |
|
&AtlasTest::landfillSetFlagsInvalid, |
|
&AtlasTest::landfillAddMissingRotations, |
|
&AtlasTest::landfillAddInvalidViewSizes, |
|
&AtlasTest::landfillAddTooLargeElement, |
|
|
|
&AtlasTest::basic, |
|
&AtlasTest::padding, |
|
&AtlasTest::empty, |
|
&AtlasTest::tooSmall, |
|
|
|
&AtlasTest::arrayPowerOfTwoEmpty, |
|
&AtlasTest::arrayPowerOfTwoSingleElement, |
|
&AtlasTest::arrayPowerOfTwoAllSameElements}); |
|
|
|
addInstancedTests({&AtlasTest::arrayPowerOfTwoOneLayer}, |
|
Containers::arraySize(ArrayPowerOfTwoOneLayerData)); |
|
|
|
addTests({&AtlasTest::arrayPowerOfTwoMoreLayers, |
|
&AtlasTest::arrayPowerOfTwoInvalidViewSizes}); |
|
|
|
addInstancedTests({&AtlasTest::arrayPowerOfTwoWrongLayerSize}, |
|
Containers::arraySize(ArrayPowerOfTwoWrongLayerSizeData)); |
|
|
|
addInstancedTests({&AtlasTest::arrayPowerOfTwoWrongSize}, |
|
Containers::arraySize(ArrayPowerOfTwoWrongSizeData)); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
addTests({&AtlasTest::arrayPowerOfTwoDeprecated}); |
|
#endif |
|
} |
|
|
|
void AtlasTest::debugLandfillFlag() { |
|
std::ostringstream out; |
|
Debug{&out} << AtlasLandfillFlag::RotatePortrait << AtlasLandfillFlag(0xcafedead); |
|
CORRADE_COMPARE(out.str(), "TextureTools::AtlasLandfillFlag::RotatePortrait TextureTools::AtlasLandfillFlag(0xcafedead)\n"); |
|
} |
|
|
|
void AtlasTest::debugLandfillFlags() { |
|
std::ostringstream out; |
|
Debug{&out} << (AtlasLandfillFlag::RotateLandscape|AtlasLandfillFlag::NarrowestFirst|AtlasLandfillFlag(0xdead0000)) << AtlasLandfillFlags{}; |
|
CORRADE_COMPARE(out.str(), "TextureTools::AtlasLandfillFlag::RotateLandscape|TextureTools::AtlasLandfillFlag::NarrowestFirst|TextureTools::AtlasLandfillFlag(0xdead0000) TextureTools::AtlasLandfillFlags{}\n"); |
|
} |
|
|
|
void AtlasTest::landfillFullFit() { |
|
/* Trivial case to verify there are no off-by-one errors that would prevent |
|
a tight fit */ |
|
|
|
AtlasLandfill atlas{{4, 6}}; |
|
CORRADE_COMPARE(atlas.size(), (Vector2i{4, 6})); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{4, 0})); |
|
CORRADE_COMPARE(atlas.flags(), AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst); |
|
|
|
Vector2i offsets[4]; |
|
UnsignedByte rotationData[1]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, 4}; |
|
/* Testing the init list overload here as all others test the view */ |
|
CORRADE_VERIFY(atlas.add({ |
|
{2, 4}, /* 0 */ |
|
{2, 3}, /* 1 */ |
|
{2, 3}, /* 2 */ |
|
{2, 2}, /* 3 */ |
|
}, offsets, rotations)); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{4, 6})); |
|
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({ |
|
false, false, false, false |
|
}).sliceBit(0), TestSuite::Compare::Container); |
|
|
|
/* 3322 |
|
3322 |
|
0022 |
|
0011 |
|
0011 |
|
0011 */ |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), Containers::arrayView<Vector2i>({ |
|
{0, 0}, /* 0 */ |
|
{2, 0}, /* 1 */ |
|
{2, 3}, /* 2 */ |
|
{0, 4}, /* 3 */ |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfill() { |
|
auto&& data = LandfillData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
AtlasLandfill atlas{data.size}; |
|
/* For unbounded sizes it should return 0 again */ |
|
CORRADE_COMPARE(atlas.size(), data.size); |
|
|
|
Vector2i offsets[Containers::arraySize(LandfillSizes)]; |
|
/* In case rotations aren't enabled, this isn't zero-initialized by |
|
add() */ |
|
UnsignedByte rotationData[2]{}; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillSizes)}; |
|
atlas.setFlags(data.flags); |
|
|
|
/* Test the rotations-less overload if no rotations are enabled */ |
|
if(!(data.flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape))) |
|
CORRADE_VERIFY(atlas.add(LandfillSizes, offsets)); |
|
else |
|
CORRADE_VERIFY(atlas.add(LandfillSizes, offsets, rotations)); |
|
|
|
CORRADE_COMPARE(atlas.filledSize(), data.filledSize); |
|
CORRADE_COMPARE_AS(rotations, |
|
Containers::stridedArrayView(data.offsetsFlips) |
|
.slice(&Containers::Pair<Vector2i, bool>::second) |
|
.sliceBit(0), |
|
TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), |
|
Containers::stridedArrayView(data.offsetsFlips) |
|
.slice(&Containers::Pair<Vector2i, bool>::first), |
|
TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfillIncremental() { |
|
/* Same as landfill(portrait, widest first) (which is the default flags) |
|
but with the data split into three parts (0 to 4, 5 to 8, 9 to c), and |
|
shuffled to verify the sort works as it should */ |
|
|
|
Vector2i sizeData[]{ |
|
{4, 2}, /* 0, rotated */ |
|
{3, 6}, /* 1 */ |
|
{3, 3}, /* 2 */ |
|
{5, 2}, /* 3, rotated */ |
|
{3, 3}, /* 4 */ |
|
{2, 2}, /* 5 */ |
|
{2, 2}, /* 6 */ |
|
{2, 2}, /* 7 */ |
|
{3, 2}, /* 8, rotated */ |
|
{1, 1}, /* 9 */ |
|
{1, 2}, /* a */ |
|
{2, 1}, /* b, rotated */ |
|
{1, 2}, /* c */ |
|
}; |
|
auto sizes = Containers::arrayView(sizeData); |
|
|
|
Vector2i offsetData[Containers::arraySize(sizeData)]; |
|
auto offsets = Containers::arrayView(offsetData); |
|
UnsignedByte rotationData[2]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(sizeData)}; |
|
|
|
AtlasLandfill atlas{{11, 10}}; |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{11, 0})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.prefix(5), |
|
offsets.prefix(5), |
|
rotations.prefix(5))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{11, 6})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.slice(5, 9), |
|
offsets.slice(5, 9), |
|
rotations.slice(5, 9))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{11, 8})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.exceptPrefix(9), |
|
offsets.exceptPrefix(9), |
|
rotations.exceptPrefix(9))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector2i{11, 10})); |
|
|
|
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({ |
|
true, false, false, true, false, false, false, false, true, false, |
|
false, true, false |
|
}).sliceBit(0), TestSuite::Compare::Container); |
|
|
|
/* abc |
|
abc9 |
|
7766 |
|
77665588 |
|
111 5588444 |
|
11133 88444 |
|
1113300 444 |
|
1113300222 |
|
1113300222 |
|
1113300222 */ |
|
CORRADE_COMPARE_AS(offsets, Containers::arrayView<Vector2i>({ |
|
{5, 0}, /* 0 */ |
|
{0, 0}, /* 1 */ |
|
{7, 0}, /* 2 */ |
|
{3, 0}, /* 3 */ |
|
{8, 3}, /* 4 */ |
|
{4, 5}, /* 5 */ |
|
{2, 6}, /* 6 */ |
|
{0, 6}, /* 7 */ |
|
{6, 4}, /* 8 */ |
|
{3, 8}, /* 9 */ |
|
{0, 8}, /* a */ |
|
{1, 8}, /* b */ |
|
{2, 8}, /* c */ |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfillNoFit() { |
|
/* Same as landfill(portrait, widest first) (which is the default flags) |
|
which fits into {11, 10} but limiting height to 9 */ |
|
|
|
AtlasLandfill atlas{{11, 9}}; |
|
|
|
Vector2i offsets[Containers::arraySize(LandfillSizes)]; |
|
UnsignedByte rotationData[2]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillSizes)}; |
|
CORRADE_VERIFY(!atlas.add(LandfillSizes, offsets, rotations)); |
|
} |
|
|
|
void AtlasTest::landfillCopy() { |
|
CORRADE_VERIFY(!std::is_copy_constructible<AtlasLandfill>{}); |
|
CORRADE_VERIFY(!std::is_copy_assignable<AtlasLandfill>{}); |
|
} |
|
|
|
void AtlasTest::landfillMove() { |
|
AtlasLandfill a{{16, 24}}; |
|
|
|
Vector2i offsets[2]; |
|
UnsignedByte rotations[1]; |
|
CORRADE_VERIFY(a.add({{15, 17}, {2, 3}}, offsets, Containers::MutableBitArrayView{rotations, 0, 2})); |
|
|
|
AtlasLandfill b = Utility::move(a); |
|
CORRADE_COMPARE(b.size(), (Vector2i{16, 24})); |
|
CORRADE_COMPARE(b.filledSize(), (Vector2i{16, 20})); |
|
|
|
AtlasLandfill c{{16, 12}}; |
|
c = Utility::move(b); |
|
CORRADE_COMPARE(c.size(), (Vector2i{16, 24})); |
|
CORRADE_COMPARE(c.filledSize(), (Vector2i{16, 20})); |
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<AtlasLandfill>::value); |
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<AtlasLandfill>::value); |
|
} |
|
|
|
void AtlasTest::landfillArrayFullFit() { |
|
/* Trivial case to verify there are no off-by-one errors that would prevent |
|
a tight fit */ |
|
|
|
AtlasLandfillArray atlas{{4, 5, 2}}; |
|
CORRADE_COMPARE(atlas.size(), (Vector3i{4, 5, 2})); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{4, 5, 0})); |
|
CORRADE_COMPARE(atlas.flags(), AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::WidestFirst); |
|
|
|
Vector3i offsets[6]; |
|
UnsignedByte rotationData[1]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, 6}; |
|
/* Testing the init list overload as all others test the view */ |
|
CORRADE_VERIFY(atlas.add({ |
|
{3, 5}, /* 0 */ |
|
{1, 5}, /* 1 */ |
|
{3, 3}, /* 2 */ |
|
{1, 3}, /* 3 */ |
|
{2, 2}, /* 4 */ |
|
{2, 2}, /* 5 */ |
|
}, offsets, rotations)); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{4, 5, 2})); |
|
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({ |
|
false, false, false, false, false, false |
|
}).sliceBit(0), TestSuite::Compare::Container); |
|
|
|
/* 0001 5544 |
|
0001 5544 |
|
0001 2223 |
|
0001 2223 |
|
0001 2223 */ |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), Containers::arrayView<Vector3i>({ |
|
{0, 0, 0}, /* 0 */ |
|
{3, 0, 0}, /* 1 */ |
|
{0, 0, 1}, /* 2 */ |
|
{3, 0, 1}, /* 3 */ |
|
{2, 3, 1}, /* 4 */ |
|
{0, 3, 1}, /* 5 */ |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfillArray() { |
|
auto&& data = LandfillArrayData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
AtlasLandfillArray atlas{data.size}; |
|
/* For unbounded sizes it should return 0 again */ |
|
CORRADE_COMPARE(atlas.size(), data.size); |
|
|
|
Vector3i offsets[Containers::arraySize(LandfillArraySizes)]; |
|
/* In case rotations aren't enabled, this isn't zero-initialized by |
|
add() */ |
|
UnsignedByte rotationData[2]{}; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillArraySizes)}; |
|
atlas.setFlags(data.flags); |
|
|
|
/* Test the rotations-less overload if no rotations are enabled */ |
|
if(!(data.flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape))) |
|
CORRADE_VERIFY(atlas.add(LandfillArraySizes, offsets)); |
|
else |
|
CORRADE_VERIFY(atlas.add(LandfillArraySizes, offsets, rotations)); |
|
|
|
CORRADE_COMPARE(atlas.filledSize(), data.filledSize); |
|
CORRADE_COMPARE_AS(rotations, |
|
Containers::stridedArrayView(data.offsetsFlips) |
|
.slice(&Containers::Pair<Vector3i, bool>::second) |
|
.sliceBit(0), |
|
TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), |
|
Containers::stridedArrayView(data.offsetsFlips) |
|
.slice(&Containers::Pair<Vector3i, bool>::first), |
|
TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfillArrayIncremental() { |
|
/* Variant of landfillIncremental(), with less elements and different item |
|
4 to test sorting across slices */ |
|
|
|
Vector2i sizeData[]{ |
|
{4, 2}, /* 0, rotated */ |
|
{3, 6}, /* 1 */ |
|
{3, 3}, /* 2 */ |
|
{5, 2}, /* 3, rotated */ |
|
{2, 2}, /* 4 */ |
|
{2, 2}, /* 5 */ |
|
{3, 3}, /* 6 */ |
|
{2, 2}, /* 7 */ |
|
{2, 1}, /* 8, rotated */ |
|
{2, 2}, /* 9 */ |
|
}; |
|
auto sizes = Containers::arrayView(sizeData); |
|
|
|
Vector3i offsetData[Containers::arraySize(sizeData)]; |
|
auto offsets = Containers::arrayView(offsetData); |
|
UnsignedByte rotationData[2]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(sizeData)}; |
|
|
|
AtlasLandfillArray atlas{{11, 6, 2}}; |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 0})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.prefix(4), |
|
offsets.prefix(4), |
|
rotations.prefix(4))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 1})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.slice(4, 7), |
|
offsets.slice(4, 7), |
|
rotations.slice(4, 7))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 2})); |
|
|
|
CORRADE_VERIFY(atlas.add( |
|
sizes.exceptPrefix(7), |
|
offsets.exceptPrefix(7), |
|
rotations.exceptPrefix(7))); |
|
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 2})); |
|
|
|
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({ |
|
true, false, false, true, false, false, false, false, true, false |
|
}).sliceBit(0), TestSuite::Compare::Container); |
|
|
|
/* 111 44666 |
|
11133 44666 |
|
1113300 666 |
|
1113300222 |
|
1113300222 5577998 |
|
1113300222 5577998 */ |
|
CORRADE_COMPARE_AS(offsets, Containers::arrayView<Vector3i>({ |
|
{5, 0, 0}, /* 0 */ |
|
{0, 0, 0}, /* 1 */ |
|
{7, 0, 0}, /* 2 */ |
|
{3, 0, 0}, /* 3 */ |
|
{6, 4, 0}, /* 4 */ |
|
{0, 0, 1}, /* 5 */ |
|
{8, 3, 0}, /* 6 */ |
|
{2, 0, 1}, /* 7 */ |
|
{6, 0, 1}, /* 8 */ |
|
{4, 0, 1}, /* 9 */ |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::landfillArrayNoFit() { |
|
/* Same as landfillArray(portrait, widest first) (which is the default |
|
flags) which fits into {11, 6, 2} but limiting depth to 1 */ |
|
|
|
AtlasLandfillArray atlas{{11, 6, 1}}; |
|
|
|
Vector3i offsets[Containers::arraySize(LandfillArraySizes)]; |
|
UnsignedByte rotationData[2]; |
|
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillArraySizes)}; |
|
CORRADE_VERIFY(!atlas.add(LandfillArraySizes, offsets, rotations)); |
|
} |
|
|
|
void AtlasTest::landfillArrayCopy() { |
|
CORRADE_VERIFY(!std::is_copy_constructible<AtlasLandfillArray>{}); |
|
CORRADE_VERIFY(!std::is_copy_assignable<AtlasLandfillArray>{}); |
|
} |
|
|
|
void AtlasTest::landfillArrayMove() { |
|
AtlasLandfillArray a{{16, 24, 8}}; |
|
|
|
Vector3i offsets[2]; |
|
UnsignedByte rotations[1]; |
|
CORRADE_VERIFY(a.add({{12, 17}, {5, 12}}, offsets, Containers::MutableBitArrayView{rotations, 0, 2})); |
|
|
|
AtlasLandfillArray b = Utility::move(a); |
|
CORRADE_COMPARE(b.size(), (Vector3i{16, 24, 8})); |
|
CORRADE_COMPARE(b.filledSize(), (Vector3i{16, 24, 2})); |
|
|
|
AtlasLandfillArray c{{16, 12, 1}}; |
|
c = Utility::move(b); |
|
CORRADE_COMPARE(c.size(), (Vector3i{16, 24, 8})); |
|
CORRADE_COMPARE(c.filledSize(), (Vector3i{16, 24, 2})); |
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<AtlasLandfillArray>::value); |
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<AtlasLandfillArray>::value); |
|
} |
|
|
|
void AtlasTest::landfillInvalidSize() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* These are fine */ |
|
AtlasLandfill{{16, 0}}; |
|
AtlasLandfill{{65536, 16}}; |
|
AtlasLandfillArray{{16, 16, 0}}; |
|
AtlasLandfillArray{{65536, 16, 16}}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
AtlasLandfill{{0, 16}}; |
|
AtlasLandfill{{65537, 16}}; |
|
AtlasLandfillArray{{0, 16, 16}}; |
|
AtlasLandfillArray{{16, 0, 16}}; |
|
AtlasLandfillArray{{65537, 16, 16}}; |
|
CORRADE_COMPARE_AS(out.str(), |
|
"TextureTools::AtlasLandfill: expected non-zero width, got {0, 16}\n" |
|
"TextureTools::AtlasLandfill: expected width to fit into 16 bits, got {65537, 16}\n" |
|
"TextureTools::AtlasLandfillArray: expected non-zero width and height, got {0, 16, 16}\n" |
|
"TextureTools::AtlasLandfillArray: expected non-zero width and height, got {16, 0, 16}\n" |
|
"TextureTools::AtlasLandfillArray: expected width to fit into 16 bits, got {65537, 16, 16}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AtlasTest::landfillSetFlagsInvalid() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
AtlasLandfill atlas{{16, 16}}; |
|
AtlasLandfillArray array{{16, 16, 1}}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlas.setFlags(AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape); |
|
array.setFlags(AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape); |
|
atlas.setFlags(AtlasLandfillFlag::WidestFirst|AtlasLandfillFlag::NarrowestFirst); |
|
array.setFlags(AtlasLandfillFlag::WidestFirst|AtlasLandfillFlag::NarrowestFirst); |
|
CORRADE_COMPARE_AS(out.str(), |
|
"TextureTools::AtlasLandfill::setFlags(): only one of RotatePortrait and RotateLandscape can be set\n" |
|
"TextureTools::AtlasLandfillArray::setFlags(): only one of RotatePortrait and RotateLandscape can be set\n" |
|
"TextureTools::AtlasLandfill::setFlags(): only one of WidestFirst and NarrowestFirst can be set\n" |
|
"TextureTools::AtlasLandfillArray::setFlags(): only one of WidestFirst and NarrowestFirst can be set\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AtlasTest::landfillAddMissingRotations() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
AtlasLandfill atlasPortrait{{16, 23}}; |
|
AtlasLandfill atlasLandscape{{16, 23}}; |
|
AtlasLandfillArray arrayPortrait{{16, 23, 2}}; |
|
AtlasLandfillArray arrayLandscape{{16, 23, 2}}; |
|
atlasPortrait.setFlags(AtlasLandfillFlag::RotatePortrait); |
|
arrayPortrait.setFlags(AtlasLandfillFlag::RotatePortrait); |
|
atlasLandscape.setFlags(AtlasLandfillFlag::RotateLandscape); |
|
arrayLandscape.setFlags(AtlasLandfillFlag::RotateLandscape); |
|
Vector2i sizes[2]; |
|
Vector2i offsets[2]; |
|
Vector3i offsets3[2]; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlasPortrait.add(sizes, offsets); |
|
arrayPortrait.add(sizes, offsets3); |
|
/* "Testing" the rotation-less init list variants too */ |
|
atlasLandscape.add({{}, {}}, offsets); |
|
arrayLandscape.add({{}, {}}, offsets3); |
|
CORRADE_COMPARE(out.str(), |
|
"TextureTools::AtlasLandfill::add(): TextureTools::AtlasLandfillFlag::RotatePortrait set, expected a rotations view\n" |
|
"TextureTools::AtlasLandfillArray::add(): TextureTools::AtlasLandfillFlag::RotatePortrait set, expected a rotations view\n" |
|
"TextureTools::AtlasLandfill::add(): TextureTools::AtlasLandfillFlag::RotateLandscape set, expected a rotations view\n" |
|
"TextureTools::AtlasLandfillArray::add(): TextureTools::AtlasLandfillFlag::RotateLandscape set, expected a rotations view\n"); |
|
} |
|
|
|
void AtlasTest::landfillAddInvalidViewSizes() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
AtlasLandfill atlas{{16, 23}}; |
|
Vector2i sizes[2]; |
|
Vector2i offsets[2]; |
|
Vector2i offsetsInvalid[3]; |
|
UnsignedByte rotationsData[1]; |
|
Containers::MutableBitArrayView rotations{rotationsData, 0, 2}; |
|
Containers::MutableBitArrayView rotationsInvalid{rotationsData, 0, 3}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlas.add(sizes, offsetsInvalid, rotations); |
|
atlas.add(sizes, offsets, rotationsInvalid); |
|
CORRADE_COMPARE(out.str(), |
|
"TextureTools::AtlasLandfill::add(): expected sizes and offsets views to have the same size, got 2 and 3\n" |
|
"TextureTools::AtlasLandfill::add(): expected sizes and rotations views to have the same size, got 2 and 3\n"); |
|
} |
|
|
|
void AtlasTest::landfillAddTooLargeElement() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* The atlas makes the sizes portrait first, the array landscape instead */ |
|
AtlasLandfill atlas{{16, 23}}; |
|
AtlasLandfill atlas2{{16, 13}}; |
|
AtlasLandfillArray array{{23, 16, 3}}; |
|
AtlasLandfillArray array2{{13, 16, 3}}; |
|
array.setFlags(AtlasLandfillFlag::RotateLandscape); |
|
array2.setFlags(AtlasLandfillFlag::RotateLandscape); |
|
Vector2i offsets[2]; |
|
Vector3i offsets3[2]; |
|
UnsignedByte rotationsData[1]; |
|
Containers::MutableBitArrayView rotations{rotationsData, 0, 2}; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlas.add({{16, 23}, {0, 23}}, offsets, rotations); |
|
array.add({{23, 16}, {23, 0}}, offsets3, rotations); |
|
atlas.add({{16, 23}, {17, 23}}, offsets, rotations); |
|
array.add({{23, 16}, {23, 17}}, offsets3, rotations); |
|
/* Sizes that fit but don't after a flip */ |
|
atlas2.add({{13, 13}, {15, 13}}, offsets, rotations); |
|
array2.add({{13, 13}, {13, 15}}, offsets3, rotations); |
|
CORRADE_COMPARE_AS(out.str(), |
|
"TextureTools::AtlasLandfill::add(): expected size 1 to be non-zero and not larger than {16, 23} but got {0, 23}\n" |
|
"TextureTools::AtlasLandfillArray::add(): expected size 1 to be non-zero and not larger than {23, 16} but got {23, 0}\n" |
|
"TextureTools::AtlasLandfill::add(): expected size 1 to be non-zero and not larger than {16, 23} but got {17, 23}\n" |
|
"TextureTools::AtlasLandfillArray::add(): expected size 1 to be non-zero and not larger than {23, 16} but got {23, 17}\n" |
|
"TextureTools::AtlasLandfill::add(): expected size 1 to be non-zero and not larger than {16, 13} but got {13, 15}\n" |
|
"TextureTools::AtlasLandfillArray::add(): expected size 1 to be non-zero and not larger than {13, 16} but got {15, 13}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AtlasTest::basic() { |
|
std::vector<Range2Di> atlas = TextureTools::atlas({64, 64}, { |
|
{12, 18}, |
|
{32, 15}, |
|
{23, 25} |
|
}); |
|
|
|
CORRADE_COMPARE(atlas.size(), 3); |
|
CORRADE_COMPARE(atlas, (std::vector<Range2Di>{ |
|
Range2Di::fromSize({0, 0}, {12, 18}), |
|
Range2Di::fromSize({32, 0}, {32, 15}), |
|
Range2Di::fromSize({0, 25}, {23, 25})})); |
|
} |
|
|
|
void AtlasTest::padding() { |
|
std::vector<Range2Di> atlas = TextureTools::atlas({64, 64}, { |
|
{8, 16}, |
|
{28, 13}, |
|
{19, 23} |
|
}, {2, 1}); |
|
|
|
CORRADE_COMPARE(atlas.size(), 3); |
|
CORRADE_COMPARE(atlas, (std::vector<Range2Di>{ |
|
Range2Di::fromSize({2, 1}, {8, 16}), |
|
Range2Di::fromSize({34, 1}, {28, 13}), |
|
Range2Di::fromSize({2, 26}, {19, 23})})); |
|
} |
|
|
|
void AtlasTest::empty() { |
|
std::vector<Range2Di> atlas = TextureTools::atlas({}, {}); |
|
CORRADE_VERIFY(atlas.empty()); |
|
} |
|
|
|
void AtlasTest::tooSmall() { |
|
std::ostringstream o; |
|
Error redirectError{&o}; |
|
|
|
std::vector<Range2Di> atlas = TextureTools::atlas({64, 32}, { |
|
{8, 16}, |
|
{21, 13}, |
|
{19, 29} |
|
}, {2, 1}); |
|
CORRADE_VERIFY(atlas.empty()); |
|
CORRADE_COMPARE(o.str(), "TextureTools::atlas(): requested atlas size Vector(64, 32) is too small to fit 3 Vector(25, 31) textures. Generated atlas will be empty.\n"); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoEmpty() { |
|
Containers::ArrayView<Vector3i> offsets; |
|
CORRADE_COMPARE(atlasArrayPowerOfTwo({128, 128}, {}, offsets), 0); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoSingleElement() { |
|
Vector3i offsets[1]; |
|
CORRADE_COMPARE(atlasArrayPowerOfTwo({128, 128}, {{128, 128}}, offsets), 1); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), Containers::arrayView<Vector3i>({ |
|
{0, 0, 0} |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoAllSameElements() { |
|
Vector3i offsets[4]; |
|
CORRADE_COMPARE(atlasArrayPowerOfTwo({128, 128}, { |
|
{64, 64}, |
|
{64, 64}, |
|
{64, 64}, |
|
{64, 64}, |
|
}, offsets), 1); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), Containers::arrayView<Vector3i>({ |
|
{0, 0, 0}, |
|
{64, 0, 0}, |
|
{0, 64, 0}, |
|
{64, 64, 0} |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoOneLayer() { |
|
auto&& data = ArrayPowerOfTwoOneLayerData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
const Vector2i inputSorted[ArrayPowerOfTwoOneLayerImageCount]{ |
|
{1024, 1024}, /* 0 */ |
|
{1024, 1024}, /* 1 */ |
|
|
|
{512, 512}, /* 2 */ |
|
{512, 512}, /* 3 */ |
|
{512, 512}, /* 4 */ |
|
{512, 512}, /* 5 */ |
|
{512, 512}, /* 6 */ |
|
|
|
{256, 256}, /* 7 */ |
|
{256, 256}, /* 8 */ |
|
{256, 256}, /* 9 */ |
|
{256, 256}, /* 10 */ |
|
|
|
{128, 128}, /* 11 */ |
|
{128, 128}, /* 12 */ |
|
|
|
{32, 32}, /* 13 */ |
|
{32, 32} /* 14 */ |
|
}; |
|
|
|
const Vector3i expectedSorted[ArrayPowerOfTwoOneLayerImageCount]{ |
|
{0, 0, 0}, |
|
{1024, 0, 0}, |
|
|
|
{0, 1024, 0}, |
|
{512, 1024, 0}, |
|
{0, 1536, 0}, |
|
{512, 1536, 0}, |
|
{1024, 1024, 0}, |
|
|
|
{1536, 1024, 0}, |
|
{1792, 1024, 0}, |
|
{1536, 1280, 0}, |
|
{1792, 1280, 0}, |
|
|
|
{1024, 1536, 0}, |
|
{1152, 1536, 0}, |
|
|
|
{1024, 1664, 0}, |
|
{1056, 1664, 0} |
|
}; |
|
|
|
Vector2i input[ArrayPowerOfTwoOneLayerImageCount]; |
|
Vector3i expected[ArrayPowerOfTwoOneLayerImageCount]; |
|
for(std::size_t i = 0; i != ArrayPowerOfTwoOneLayerImageCount; ++i) { |
|
input[i] = inputSorted[data.order[i]]; |
|
expected[i] = expectedSorted[data.order[i]]; |
|
} |
|
|
|
Vector3i offsets[ArrayPowerOfTwoOneLayerImageCount]; |
|
CORRADE_COMPARE(atlasArrayPowerOfTwo({2048, 2048}, input, offsets), 1); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), |
|
Containers::arrayView(expected), |
|
TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoMoreLayers() { |
|
Vector3i offsets[11]; |
|
CORRADE_COMPARE(atlasArrayPowerOfTwo({2048, 2048}, { |
|
{2048, 2048}, |
|
|
|
{1024, 1024}, |
|
{1024, 1024}, |
|
{1024, 1024}, |
|
{512, 512}, |
|
{512, 512}, |
|
{512, 512}, |
|
{512, 512}, |
|
|
|
{512, 512}, |
|
{256, 256}, |
|
{256, 256} |
|
}, offsets), 3); |
|
CORRADE_COMPARE_AS(Containers::arrayView(offsets), Containers::arrayView<Vector3i>({ |
|
{0, 0, 0}, |
|
|
|
{0, 0, 1}, |
|
{1024, 0, 1}, |
|
{0, 1024, 1}, |
|
{1024, 1024, 1}, |
|
{1536, 1024, 1}, |
|
{1024, 1536, 1}, |
|
{1536, 1536, 1}, |
|
|
|
{0, 0, 2}, |
|
{512, 0, 2}, |
|
{768, 0, 2} |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoInvalidViewSizes() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
Vector2i sizes[2]; |
|
Vector3i offsetsInvalid[3]; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlasArrayPowerOfTwo({}, sizes, offsetsInvalid); |
|
CORRADE_COMPARE(out.str(), |
|
"TextureTools::atlasArrayPowerOfTwo(): expected sizes and offsets views to have the same size, got 2 and 3\n"); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoWrongLayerSize() { |
|
auto&& data = ArrayPowerOfTwoWrongLayerSizeData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlasArrayPowerOfTwo(data.size, {}, {}); |
|
CORRADE_COMPARE(out.str(), Utility::formatString("TextureTools::atlasArrayPowerOfTwo(): expected layer size to be a non-zero power-of-two square, got {}\n", data.message)); |
|
} |
|
|
|
void AtlasTest::arrayPowerOfTwoWrongSize() { |
|
auto&& data = ArrayPowerOfTwoWrongSizeData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
Vector3i offsets[3]; |
|
|
|
std::ostringstream out; |
|
Error redirectError{&out}; |
|
atlasArrayPowerOfTwo({256, 256}, { |
|
{64, 64}, |
|
{128, 128}, |
|
data.size |
|
}, offsets); |
|
CORRADE_COMPARE(out.str(), Utility::formatString("TextureTools::atlasArrayPowerOfTwo(): expected size 2 to be a non-zero power-of-two square not larger than {{256, 256}} but got {}\n", data.message)); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AtlasTest::arrayPowerOfTwoDeprecated() { |
|
/* Same as arrayPowerOfTwoAllSameElements(), but with the deprecated API */ |
|
|
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
Containers::Pair<Int, Containers::Array<Vector3i>> out = atlasArrayPowerOfTwo({128, 128}, { |
|
{64, 64}, |
|
{64, 64}, |
|
{64, 64}, |
|
{64, 64}, |
|
}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out.first(), 1); |
|
CORRADE_COMPARE_AS(out.second(), Containers::arrayView<Vector3i>({ |
|
{0, 0, 0}, |
|
{64, 0, 0}, |
|
{0, 64, 0}, |
|
{64, 64, 0} |
|
}), TestSuite::Compare::Container); |
|
} |
|
#endif |
|
|
|
}}}} |
|
|
|
CORRADE_TEST_MAIN(Magnum::TextureTools::Test::AtlasTest)
|
|
|