Browse Source

TextureTools: return the filled range from AtlasLandfill::add().

Because otherwise the users likely have to do something similar on their
end to perform a texture upload etc., which means they'll either take
the easy path and upload everything including the unused area, or they
introduce various bugs in the process, leading to random artifacts,
especially when it comes to padding.

Which is exactly what I think is causing random test failures in the Ui
library text rendering, because the glyph cache filling process in
plugins is calculating the rectangle too tight, without considering
padding. Gonna fix that now.
pull/651/merge
Vladimír Vondruš 1 year ago
parent
commit
b5325ab0ac
  1. 1
      doc/snippets/TextureTools.cpp
  2. 2
      src/Magnum/Text/AbstractGlyphCache.cpp
  3. 49
      src/Magnum/TextureTools/Atlas.cpp
  4. 38
      src/Magnum/TextureTools/Atlas.h
  5. 72
      src/Magnum/TextureTools/Test/AtlasTest.cpp

1
doc/snippets/TextureTools.cpp

@ -36,6 +36,7 @@
#include "Magnum/Math/Color.h"
#include "Magnum/Math/FunctionsBatch.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Range.h"
#include "Magnum/MeshTools/Transform.h"
#include "Magnum/TextureTools/Atlas.h"
#include "Magnum/Trade/MaterialData.h"

2
src/Magnum/Text/AbstractGlyphCache.cpp

@ -302,7 +302,7 @@ std::vector<Range2Di> AbstractGlyphCache::reserve(const std::vector<Vector2i>& s
for(std::size_t i = 0; i != sizes.size(); ++i)
out[i].max() = sizes[i];
const bool succeeded = state.atlas.add(
const bool succeeded = !!state.atlas.add(
Containers::stridedArrayView(out).slice(&Range2Di::max),
Containers::stridedArrayView(out).slice(&Range2Di::min));

49
src/Magnum/TextureTools/Atlas.cpp

@ -31,17 +31,17 @@
#include <Corrade/Containers/BitArrayView.h>
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/StridedArrayView.h>
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Functions.h"
#include "Magnum/Math/FunctionsBatch.h"
#include "Magnum/Math/Range.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <vector>
#include "Magnum/Math/Range.h"
#endif
namespace Magnum { namespace TextureTools {
@ -96,7 +96,7 @@ struct AtlasLandfillState {
namespace {
bool atlasLandfillAddSortedFlipped(Implementation::AtlasLandfillState& state, const Int slice, const Containers::StridedArrayView1D<const Containers::Pair<Vector2i, UnsignedInt>> sortedFlippedSizes, const Containers::StridedArrayView1D<Vector2i> offsets, const Containers::StridedArrayView1D<Int> zOffsets, const Containers::BitArrayView rotations) {
Containers::Optional<Range3Di> atlasLandfillAddSortedFlipped(Implementation::AtlasLandfillState& state, const Int slice, const Containers::StridedArrayView1D<const Containers::Pair<Vector2i, UnsignedInt>> sortedFlippedSizes, const Containers::StridedArrayView1D<Vector2i> offsets, const Containers::StridedArrayView1D<Int> zOffsets, const Containers::BitArrayView rotations) {
/* Add a new slice if not there yet, extend the yOffsets array */
if(UnsignedInt(slice) >= state.slices.size()) {
CORRADE_INTERNAL_ASSERT(UnsignedInt(slice) == state.slices.size());
@ -117,6 +117,7 @@ bool atlasLandfillAddSortedFlipped(Implementation::AtlasLandfillState& state, co
if(sliceState.direction == -1)
sliceYOffsets = sliceYOffsets.flipped<0>();
Range3Di range;
std::size_t i;
for(i = 0; i != sortedFlippedSizes.size(); ++i) {
const Vector2i size = sortedFlippedSizes[i].first();
@ -161,11 +162,15 @@ bool atlasLandfillAddSortedFlipped(Implementation::AtlasLandfillState& state, co
/* Save the position (X-flip it in case we're in reverse direction),
add the (appropriately rotated) padding to it so it points to the
original unpadded size */
offsets[index] = padding + Vector2i{
const Vector2i offset{
sliceState.direction > 0 ? sliceState.xOffset :
state.size.x() - sliceState.xOffset - size.x(),
placementYOffset
};
placementYOffset};
offsets[index] = padding + offset;
/* Add this item to the range spanning all added items, including the
(potentially rotated) padding */
range = join(range, Range3Di::fromSize({offset, slice}, {size, 1}));
/* Advance to the next X offset */
sliceState.xOffset += size.x();
@ -179,13 +184,18 @@ bool atlasLandfillAddSortedFlipped(Implementation::AtlasLandfillState& state, co
/* If there are items that didn't fit, recurse to the next slice. This
should only happen if the Y size is bounded. */
if(i < sortedFlippedSizes.size()) {
/* If there are no more slices, fail */
if(slice + 1 == state.size.z())
return false;
return atlasLandfillAddSortedFlipped(state, slice + 1, sortedFlippedSizes.exceptPrefix(i), offsets, zOffsets, rotations);
return {};
/* If the recursion succeeded, return the two ranges joined */
if(const Containers::Optional<Range3Di> out = atlasLandfillAddSortedFlipped(state, slice + 1, sortedFlippedSizes.exceptPrefix(i), offsets, zOffsets, rotations))
return Range3Di{join(range, *out)};
/* If it didn't, fail */
return {};
}
/* Everything fit, success */
return true;
return range;
}
}
@ -252,7 +262,7 @@ AtlasLandfill& AtlasLandfill::setFlags(AtlasLandfillFlags flags) {
namespace {
bool atlasLandfillAdd(Implementation::AtlasLandfillState& state, const Containers::StridedArrayView1D<const Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i> offsets, const Containers::StridedArrayView1D<Int> zOffsets, const Containers::MutableBitArrayView rotations) {
Containers::Optional<Range3Di> atlasLandfillAdd(Implementation::AtlasLandfillState& state, const Containers::StridedArrayView1D<const Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i> offsets, const Containers::StridedArrayView1D<Int> zOffsets, const Containers::MutableBitArrayView rotations) {
CORRADE_ASSERT(offsets.size() == sizes.size(),
"TextureTools::AtlasLandfill::add(): expected sizes and offsets views to have the same size, got" << sizes.size() << "and" << offsets.size(), {});
CORRADE_ASSERT((!(state.flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)) && rotations.isEmpty()) || rotations.size() == sizes.size(),
@ -342,41 +352,42 @@ bool atlasLandfillAdd(Implementation::AtlasLandfillState& state, const Container
}
bool AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView flips) {
Containers::Optional<Range3Di> AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView flips) {
return atlasLandfillAdd(*_state, sizes, offsets.slice(&Vector3i::xy), offsets.slice(&Vector3i::z), flips);
}
bool AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView flips) {
Containers::Optional<Range3Di> AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView flips) {
return add(Containers::stridedArrayView(sizes), offsets, flips);
}
bool AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets) {
Containers::Optional<Range3Di> AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets) {
CORRADE_ASSERT(!(_state->flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)),
"TextureTools::AtlasLandfill::add():" << (_state->flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)) << "set, expected a rotations view", {});
return add(sizes, offsets, nullptr);
}
bool AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets) {
Containers::Optional<Range3Di> AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets) {
return add(Containers::stridedArrayView(sizes), offsets);
}
bool AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView flips) {
Containers::Optional<Range2Di> AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView flips) {
CORRADE_ASSERT(_state->size.z() == 1,
"TextureTools::AtlasLandfill::add(): use the three-component overload for an array atlas", {});
return atlasLandfillAdd(*_state, sizes, offsets, nullptr, flips);
const Containers::Optional<Range3Di> out = atlasLandfillAdd(*_state, sizes, offsets, nullptr, flips);
return out ? Containers::optional(out->xy()) : Containers::NullOpt;
}
bool AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView flips) {
Containers::Optional<Range2Di> AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView flips) {
return add(Containers::stridedArrayView(sizes), offsets, flips);
}
bool AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets) {
Containers::Optional<Range2Di> AtlasLandfill::add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets) {
CORRADE_ASSERT(!(_state->flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)),
"TextureTools::AtlasLandfill::add():" << (_state->flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)) << "set, expected a rotations view", {});
return add(sizes, offsets, nullptr);
}
bool AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets) {
Containers::Optional<Range2Di> AtlasLandfill::add(const std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets) {
return add(Containers::stridedArrayView(sizes), offsets);
}

38
src/Magnum/TextureTools/Atlas.h

@ -345,6 +345,8 @@ class MAGNUM_TEXTURETOOLS_EXPORT AtlasLandfill {
* @param[in] sizes Texture sizes
* @param[out] offsets Resulting offsets in the atlas
* @param[out] rotations Which textures got rotated
* @return Range spanning all added items including padding or
* @relativeref{Corrade,Containers::NullOpt} if they didn't fit
*
* The @p sizes, @p offsets and @p rotations views are expected to have
* the same size. The @p sizes are all expected to be not larger than
@ -364,17 +366,18 @@ class MAGNUM_TEXTURETOOLS_EXPORT AtlasLandfill {
* height are treated as any others to make sure they don't overlap
* other items.
*
* On success returns @cpp true @ce and updates @ref filledSize(). If
* @ref size() is bounded, can return @cpp false @ce if the items
* didn't fit, in which case the internals and contents of @p offsets
* and @p rotations are left in an undefined state. For an unbounded
* @ref size() returns @cpp true @ce always.
* On success updates @ref filledSize() and returns a range spanning
* all added items including padding, which can be used for example to
* perform a partial GPU texture upload. If @ref size() is bounded, can
* return @relativeref{Corrade,Containers::NullOpt} if the items didn't
* fit, in which case the internals and contents of @p offsets and
* @p rotations are left in an undefined state. For an unbounded
* @ref size() the function never fails.
* @see @ref setFlags(), @ref setPadding()
*/
bool add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView rotations);
Containers::Optional<Range3Di> add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView rotations);
/** @overload */
bool add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView rotations);
Containers::Optional<Range3Di> add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets, Containers::MutableBitArrayView rotations);
/**
* @brief Add textures to the atlas with rotations disabled
@ -385,20 +388,20 @@ class MAGNUM_TEXTURETOOLS_EXPORT AtlasLandfill {
* @relativeref{AtlasLandfillFlag,RotateLandscape} is set.
* @see @ref clearFlags()
*/
bool add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets);
Containers::Optional<Range3Di> add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector3i>& offsets);
/** @overload */
bool add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets);
Containers::Optional<Range3Di> add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector3i>& offsets);
/**
* @brief Add textures to a non-array atlas
*
* Can be called only if @ref size() depth is @cpp 1 @ce.
* Like @ref add(const Containers::StridedArrayView1D<const Vector2i>&, const Containers::StridedArrayView1D<Vector3i>&, Containers::MutableBitArrayView),
* but omitting the third dimension. Can be called only if @ref size()
* depth is @cpp 1 @ce.
*/
bool add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView rotations);
Containers::Optional<Range2Di> add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView rotations);
/** @overload */
bool add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView rotations);
Containers::Optional<Range2Di> add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets, Containers::MutableBitArrayView rotations);
/**
* @brief Add textures to a non-array atlas with rotations disabled
@ -410,10 +413,9 @@ class MAGNUM_TEXTURETOOLS_EXPORT AtlasLandfill {
* @relativeref{AtlasLandfillFlag,RotateLandscape} is set.
* @see @ref clearFlags()
*/
bool add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets);
Containers::Optional<Range2Di> add(const Containers::StridedArrayView1D<const Vector2i>& sizes, const Containers::StridedArrayView1D<Vector2i>& offsets);
/** @overload */
bool add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets);
Containers::Optional<Range2Di> add(std::initializer_list<Vector2i> sizes, const Containers::StridedArrayView1D<Vector2i>& offsets);
private:
Containers::Pointer<Implementation::AtlasLandfillState> _state;

72
src/Magnum/TextureTools/Test/AtlasTest.cpp

@ -25,9 +25,10 @@
*/
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StridedBitArrayView.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/String.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
@ -35,12 +36,11 @@
#include <Corrade/Utility/Format.h>
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Range.h"
#include "Magnum/TextureTools/Atlas.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <vector>
#include "Magnum/Math/Range.h"
#endif
namespace Magnum { namespace TextureTools { namespace Test { namespace {
@ -584,12 +584,12 @@ void AtlasTest::landfillFullFit() {
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({
CORRADE_COMPARE(atlas.add({
{2, 4}, /* 0 */
{2, 3}, /* 1 */
{2, 3}, /* 2 */
{2, 2}, /* 3 */
}, offsets, rotations));
}, offsets, rotations), (Range2Di{{}, {4, 6}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{4, 6, 1}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
false, false, false, false
@ -626,9 +626,9 @@ void AtlasTest::landfill() {
/* Test the rotations-less overload if no rotations are enabled */
if(!(data.flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)))
CORRADE_VERIFY(atlas.add(LandfillSizes, offsets));
CORRADE_COMPARE(atlas.add(LandfillSizes, offsets), (Range2Di{{}, data.filledSize}));
else
CORRADE_VERIFY(atlas.add(LandfillSizes, offsets, rotations));
CORRADE_COMPARE(atlas.add(LandfillSizes, offsets, rotations), (Range2Di{{}, data.filledSize}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{data.filledSize, 1}));
CORRADE_COMPARE_AS(rotations,
@ -672,22 +672,25 @@ void AtlasTest::landfillIncremental() {
AtlasLandfill atlas{{11, 8}};
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 0, 1}));
CORRADE_VERIFY(atlas.add(
/* The first addition spans a range that begins at the origin and ends at
filledSize() */
CORRADE_COMPARE(atlas.add(
sizes.prefix(5),
offsets.prefix(5),
rotations.prefix(5)));
rotations.prefix(5)), (Range2Di{{}, {11, 6}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 1}));
CORRADE_VERIFY(atlas.add(
/* Following additions are just incremental */
CORRADE_COMPARE(atlas.add(
sizes.slice(5, 9),
offsets.slice(5, 9),
rotations.slice(5, 9)));
rotations.slice(5, 9)), (Range2Di{{0, 4}, {8, 8}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 8, 1}));
CORRADE_VERIFY(atlas.add(
CORRADE_COMPARE(atlas.add(
sizes.exceptPrefix(9),
offsets.exceptPrefix(9),
rotations.exceptPrefix(9)));
rotations.exceptPrefix(9)), (Range2Di{{7, 6}, {11, 8}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 8, 1}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
@ -728,7 +731,10 @@ void AtlasTest::landfillPadded() {
Vector2i offsets[8];
UnsignedByte rotationData[1];
Containers::MutableBitArrayView rotations{rotationData, 0, 8};
CORRADE_VERIFY(atlas.add({
/* The filled size includes the padding as well, since that's what is
likely desirable to get copied as well */
CORRADE_COMPARE(atlas.add({
{6, 2}, /* 0, padded to {8, 6}, flipped */
{1, 3}, /* 1, padded to {3, 7} */
{4, 1}, /* 2, padded to {6, 5}, flipped */
@ -737,7 +743,7 @@ void AtlasTest::landfillPadded() {
{1, 1}, /* 5, padded to {3, 5} */
{3, 0}, /* 6 (zero height), padded to {5, 4}, flipped */
{0, 2}, /* 7 (zero width), padded to {2, 6} */
}, offsets, rotations));
}, offsets, rotations), (Range2Di{{}, {17, 13}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{17, 13, 1}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
@ -780,7 +786,7 @@ void AtlasTest::landfillNoFit() {
Vector2i offsets[Containers::arraySize(LandfillSizes)];
UnsignedByte rotationData[2];
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillSizes)};
CORRADE_VERIFY(!atlas.add(LandfillSizes, offsets, rotations));
CORRADE_COMPARE(atlas.add(LandfillSizes, offsets, rotations), Containers::NullOpt);
}
void AtlasTest::landfillCopy() {
@ -822,14 +828,14 @@ void AtlasTest::landfillArrayFullFit() {
UnsignedByte rotationData[1];
Containers::MutableBitArrayView rotations{rotationData, 0, 6};
/* Testing the init list overload as all others test the view */
CORRADE_VERIFY(atlas.add({
CORRADE_COMPARE(atlas.add({
{3, 5}, /* 0 */
{1, 5}, /* 1 */
{3, 3}, /* 2 */
{1, 3}, /* 3 */
{2, 2}, /* 4 */
{2, 2}, /* 5 */
}, offsets, rotations));
}, offsets, rotations), (Range3Di{{}, {4, 5, 2}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{4, 5, 2}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
false, false, false, false, false, false
@ -867,9 +873,9 @@ void AtlasTest::landfillArray() {
/* Test the rotations-less overload if no rotations are enabled */
if(!(data.flags & (AtlasLandfillFlag::RotatePortrait|AtlasLandfillFlag::RotateLandscape)))
CORRADE_VERIFY(atlas.add(LandfillArraySizes, offsets));
CORRADE_COMPARE(atlas.add(LandfillArraySizes, offsets), (Range3Di{{}, data.filledSize}));
else
CORRADE_VERIFY(atlas.add(LandfillArraySizes, offsets, rotations));
CORRADE_COMPARE(atlas.add(LandfillArraySizes, offsets, rotations), (Range3Di{{}, data.filledSize}));
CORRADE_COMPARE(atlas.filledSize(), data.filledSize);
CORRADE_COMPARE_AS(rotations,
@ -909,22 +915,28 @@ void AtlasTest::landfillArrayIncremental() {
AtlasLandfill atlas{{11, 6, 2}};
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 0}));
CORRADE_VERIFY(atlas.add(
/* The first addition spans a range that begins at the origin and ends at
filledSize(). Well, almost, because the first four items don't make use
of the rightmost column. */
CORRADE_COMPARE(atlas.add(
sizes.prefix(4),
offsets.prefix(4),
rotations.prefix(4)));
rotations.prefix(4)), (Range3Di{{}, {10, 6, 1}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 1}));
CORRADE_VERIFY(atlas.add(
/* Following additions are incremental ... well, in this case it overflows
to the next slice, which means it covers basically the whole area */
CORRADE_COMPARE(atlas.add(
sizes.slice(4, 7),
offsets.slice(4, 7),
rotations.slice(4, 7)));
rotations.slice(4, 7)), (Range3Di{{}, {11, 6, 2}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 2}));
CORRADE_VERIFY(atlas.add(
/* The last addition is then just a tiny bit of the second slice */
CORRADE_COMPARE(atlas.add(
sizes.exceptPrefix(7),
offsets.exceptPrefix(7),
rotations.exceptPrefix(7)));
rotations.exceptPrefix(7)), (Range3Di{{2, 0, 1}, {7, 2, 2}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{11, 6, 2}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
@ -961,7 +973,7 @@ void AtlasTest::landfillArrayPadded() {
Vector3i offsets[8];
UnsignedByte rotationData[1];
Containers::MutableBitArrayView rotations{rotationData, 0, 8};
CORRADE_VERIFY(atlas.add({
CORRADE_COMPARE(atlas.add({
{6, 2}, /* 0, padded to {8, 6}, flipped */
{1, 3}, /* 1, padded to {3, 7} */
{4, 1}, /* 2, padded to {6, 5}, flipped */
@ -970,7 +982,7 @@ void AtlasTest::landfillArrayPadded() {
{1, 1}, /* 5, padded to {3, 5} */
{3, 0}, /* 6 (zero height), padded to {5, 4}, flipped */
{0, 2}, /* 7 (zero width), padded to {2, 6} */
}, offsets, rotations));
}, offsets, rotations), (Range3Di{{}, {16, 12, 2}}));
CORRADE_COMPARE(atlas.filledSize(), (Vector3i{16, 12, 2}));
CORRADE_COMPARE_AS(rotations, Containers::stridedArrayView({
@ -1011,7 +1023,7 @@ void AtlasTest::landfillArrayNoFit() {
Vector3i offsets[Containers::arraySize(LandfillArraySizes)];
UnsignedByte rotationData[2];
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillArraySizes)};
CORRADE_VERIFY(!atlas.add(LandfillArraySizes, offsets, rotations));
CORRADE_COMPARE(atlas.add(LandfillArraySizes, offsets, rotations), Containers::NullOpt);
/* Sanity check that with one more slice it works */
} {
@ -1019,7 +1031,7 @@ void AtlasTest::landfillArrayNoFit() {
Vector3i offsets[Containers::arraySize(LandfillArraySizes)];
UnsignedByte rotationData[2];
Containers::MutableBitArrayView rotations{rotationData, 0, Containers::arraySize(LandfillArraySizes)};
CORRADE_VERIFY(atlas.add(LandfillArraySizes, offsets, rotations));
CORRADE_COMPARE(atlas.add(LandfillArraySizes, offsets, rotations), (Range3Di{{}, {6, 6, 3}}));
}
}

Loading…
Cancel
Save