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.
2257 lines
88 KiB
2257 lines
88 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022, 2023, 2024, 2025 |
|
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 <Corrade/Containers/Optional.h> |
|
#include <Corrade/Containers/StridedArrayView.h> |
|
#include <Corrade/Containers/String.h> |
|
#include <Corrade/Containers/Triple.h> |
|
#include <Corrade/TestSuite/Tester.h> |
|
#include <Corrade/TestSuite/Compare/Container.h> |
|
#include <Corrade/TestSuite/Compare/String.h> |
|
#include <Corrade/Utility/Algorithms.h> |
|
|
|
#include "Magnum/Image.h" |
|
#include "Magnum/ImageView.h" |
|
#include "Magnum/PixelFormat.h" |
|
#include "Magnum/DebugTools/CompareImage.h" |
|
#include "Magnum/Math/Range.h" |
|
#include "Magnum/Text/AbstractGlyphCache.h" |
|
#include "Magnum/TextureTools/Atlas.h" |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
#include <vector> |
|
#include <Corrade/Containers/ArrayViewStl.h> |
|
#include <Corrade/Utility/DebugStl.h> /* std::pair */ |
|
#endif |
|
|
|
namespace Magnum { namespace Text { namespace Test { namespace { |
|
|
|
struct AbstractGlyphCacheTest: TestSuite::Tester { |
|
explicit AbstractGlyphCacheTest(); |
|
|
|
void debugFeature(); |
|
void debugFeatures(); |
|
void debugFeaturesSupersets(); |
|
|
|
void construct(); |
|
void constructNoPadding(); |
|
void construct2D(); |
|
void construct2DNoPadding(); |
|
void constructProcessed(); |
|
void constructProcessedNoPadding(); |
|
void constructProcessed2D(); |
|
void constructProcessed2DNoPadding(); |
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void constructDeprecated(); |
|
void constructDeprecatedNoPadding(); |
|
#endif |
|
void constructImageRowPadding(); |
|
void constructZeroSize(); |
|
void constructNoCreate(); |
|
|
|
void constructCopy(); |
|
void constructMove(); |
|
|
|
void features(); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void textureSizeNot2D(); |
|
#endif |
|
|
|
void setInvalidGlyph(); |
|
void setInvalidGlyph2D(); |
|
void setInvalidGlyphOutOfRange(); |
|
void setInvalidGlyphOutOfRangePadded(); |
|
void setInvalidGlyph2DNot2D(); |
|
|
|
void addFont(); |
|
void addFontDuplicatePointer(); |
|
void fontOutOfRange(); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void reserve(); |
|
void reserveIncremental(); |
|
void reserveTooSmall(); |
|
void reserveNot2D(); |
|
#endif |
|
|
|
void addGlyph(); |
|
void addGlyph2D(); |
|
void addGlyphIndexOutOfRange(); |
|
void addGlyphAlreadyAdded(); |
|
void addGlyphOutOfRange(); |
|
void addGlyphOutOfRangePadded(); |
|
void addGlyphTooMany(); |
|
void addGlyph2DNot2D(); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void insert(); |
|
void insertNot2D(); |
|
void insertMultiFont(); |
|
#endif |
|
|
|
void flushImage(); |
|
void flushImageWholeArea(); |
|
void flushImageLayer(); |
|
void flushImage2D(); |
|
void flushImage2DPassthrough2D(); |
|
void flushImageNotImplemented(); |
|
void flushImagePassthrough2DNotImplemented(); |
|
void flushImageOutOfRange(); |
|
void flushImage2DNot2D(); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void setImage(); |
|
void setImageOutOfRange(); |
|
void setImageInvalidFormat(); |
|
void setImageNot2D(); |
|
#endif |
|
|
|
void processedImage(); |
|
void processedImageNotSupported(); |
|
void processedImageNotImplemented(); |
|
|
|
void setProcessedImage(); |
|
void setProcessedImage2D(); |
|
void setProcessedImage2DPassthrough2D(); |
|
void setProcessedImageNotImplemented(); |
|
void setProcessedImagePassthrough2DNotImplemented(); |
|
void setProcessedImageOutOfRange(); |
|
void setProcessedImageInvalidFormat(); |
|
void setProcessedImage2DNot2D(); |
|
|
|
void access(); |
|
void accessBatch(); |
|
void accessInvalid(); |
|
void accessBatchInvalid(); |
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void accessDeprecated(); |
|
void accessDeprecatedNot2D(); |
|
#endif |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
Vector2i padding; |
|
bool differentProcessedFormatSize; |
|
} FlushImageData[]{ |
|
{"", {}, false}, |
|
{"with padding", {2, 3}, false}, |
|
{"with different processed format and size", {}, false} |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
GlyphCacheFeatures features; |
|
} ProcessedImageNotSupportedData[]{ |
|
{"no processing", {}}, |
|
{"no processed image download", GlyphCacheFeature::ImageProcessing}, |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
Vector2i padding; |
|
} SetProcessedImageOutOfRangeData[]{ |
|
{"", {}}, |
|
{"with padding", {2, 3}}, |
|
}; |
|
|
|
AbstractGlyphCacheTest::AbstractGlyphCacheTest() { |
|
addTests({&AbstractGlyphCacheTest::debugFeature, |
|
&AbstractGlyphCacheTest::debugFeatures, |
|
&AbstractGlyphCacheTest::debugFeaturesSupersets, |
|
|
|
&AbstractGlyphCacheTest::construct, |
|
&AbstractGlyphCacheTest::constructNoPadding, |
|
&AbstractGlyphCacheTest::construct2D, |
|
&AbstractGlyphCacheTest::construct2DNoPadding, |
|
&AbstractGlyphCacheTest::constructProcessed, |
|
&AbstractGlyphCacheTest::constructProcessedNoPadding, |
|
&AbstractGlyphCacheTest::constructProcessed2D, |
|
&AbstractGlyphCacheTest::constructProcessed2DNoPadding, |
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
&AbstractGlyphCacheTest::constructDeprecated, |
|
&AbstractGlyphCacheTest::constructDeprecatedNoPadding, |
|
#endif |
|
&AbstractGlyphCacheTest::constructImageRowPadding, |
|
&AbstractGlyphCacheTest::constructZeroSize, |
|
&AbstractGlyphCacheTest::constructNoCreate, |
|
|
|
&AbstractGlyphCacheTest::constructCopy, |
|
&AbstractGlyphCacheTest::constructMove, |
|
|
|
&AbstractGlyphCacheTest::features, |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
&AbstractGlyphCacheTest::textureSizeNot2D, |
|
#endif |
|
|
|
&AbstractGlyphCacheTest::setInvalidGlyph, |
|
&AbstractGlyphCacheTest::setInvalidGlyph2D, |
|
&AbstractGlyphCacheTest::setInvalidGlyphOutOfRange, |
|
&AbstractGlyphCacheTest::setInvalidGlyphOutOfRangePadded, |
|
&AbstractGlyphCacheTest::setInvalidGlyph2DNot2D, |
|
|
|
&AbstractGlyphCacheTest::addFont, |
|
&AbstractGlyphCacheTest::addFontDuplicatePointer, |
|
&AbstractGlyphCacheTest::fontOutOfRange, |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
&AbstractGlyphCacheTest::reserve, |
|
&AbstractGlyphCacheTest::reserveIncremental, |
|
&AbstractGlyphCacheTest::reserveTooSmall, |
|
&AbstractGlyphCacheTest::reserveNot2D, |
|
#endif |
|
|
|
&AbstractGlyphCacheTest::addGlyph, |
|
&AbstractGlyphCacheTest::addGlyph2D, |
|
&AbstractGlyphCacheTest::addGlyphIndexOutOfRange, |
|
&AbstractGlyphCacheTest::addGlyphAlreadyAdded, |
|
&AbstractGlyphCacheTest::addGlyphOutOfRange, |
|
&AbstractGlyphCacheTest::addGlyphOutOfRangePadded, |
|
&AbstractGlyphCacheTest::addGlyphTooMany, |
|
&AbstractGlyphCacheTest::addGlyph2DNot2D, |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
&AbstractGlyphCacheTest::insert, |
|
&AbstractGlyphCacheTest::insertNot2D, |
|
&AbstractGlyphCacheTest::insertMultiFont, |
|
#endif |
|
}); |
|
|
|
addInstancedTests({&AbstractGlyphCacheTest::flushImage, |
|
&AbstractGlyphCacheTest::flushImageWholeArea, |
|
&AbstractGlyphCacheTest::flushImageLayer, |
|
&AbstractGlyphCacheTest::flushImage2D, |
|
&AbstractGlyphCacheTest::flushImage2DPassthrough2D}, |
|
Containers::arraySize(FlushImageData)); |
|
|
|
addTests({&AbstractGlyphCacheTest::flushImageNotImplemented, |
|
&AbstractGlyphCacheTest::flushImagePassthrough2DNotImplemented}); |
|
|
|
addInstancedTests({&AbstractGlyphCacheTest::flushImageOutOfRange}, |
|
Containers::arraySize(FlushImageData)); |
|
|
|
addTests({&AbstractGlyphCacheTest::flushImage2DNot2D}); |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
addInstancedTests({&AbstractGlyphCacheTest::setImage}, |
|
Containers::arraySize(FlushImageData)); |
|
|
|
addTests({&AbstractGlyphCacheTest::setImageOutOfRange, |
|
&AbstractGlyphCacheTest::setImageInvalidFormat, |
|
&AbstractGlyphCacheTest::setImageNot2D}); |
|
#endif |
|
|
|
addTests({&AbstractGlyphCacheTest::processedImage}); |
|
|
|
addInstancedTests({&AbstractGlyphCacheTest::processedImageNotSupported}, |
|
Containers::arraySize(ProcessedImageNotSupportedData)); |
|
|
|
addTests({&AbstractGlyphCacheTest::processedImageNotImplemented, |
|
|
|
&AbstractGlyphCacheTest::setProcessedImage, |
|
&AbstractGlyphCacheTest::setProcessedImage2D, |
|
&AbstractGlyphCacheTest::setProcessedImage2DPassthrough2D, |
|
&AbstractGlyphCacheTest::setProcessedImageNotImplemented, |
|
&AbstractGlyphCacheTest::setProcessedImagePassthrough2DNotImplemented}); |
|
|
|
addInstancedTests({&AbstractGlyphCacheTest::setProcessedImageOutOfRange}, |
|
Containers::arraySize(SetProcessedImageOutOfRangeData)); |
|
|
|
addTests({&AbstractGlyphCacheTest::setProcessedImageInvalidFormat, |
|
&AbstractGlyphCacheTest::setProcessedImage2DNot2D, |
|
|
|
&AbstractGlyphCacheTest::access, |
|
&AbstractGlyphCacheTest::accessBatch, |
|
&AbstractGlyphCacheTest::accessInvalid, |
|
&AbstractGlyphCacheTest::accessBatchInvalid, |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
&AbstractGlyphCacheTest::accessDeprecated, |
|
&AbstractGlyphCacheTest::accessDeprecatedNot2D, |
|
#endif |
|
}); |
|
} |
|
|
|
void AbstractGlyphCacheTest::debugFeature() { |
|
Containers::String out; |
|
Debug{&out} << GlyphCacheFeature::ImageProcessing << GlyphCacheFeature(0xca); |
|
CORRADE_COMPARE(out, "Text::GlyphCacheFeature::ImageProcessing Text::GlyphCacheFeature(0xca)\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::debugFeatures() { |
|
Containers::String out; |
|
Debug{&out} << (GlyphCacheFeature::ImageProcessing|GlyphCacheFeature(0xf0)) << GlyphCacheFeatures{}; |
|
CORRADE_COMPARE(out, "Text::GlyphCacheFeature::ImageProcessing|Text::GlyphCacheFeature(0xf0) Text::GlyphCacheFeatures{}\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::debugFeaturesSupersets() { |
|
/* ProcessedImageDownload is a superset of ImageProcessing, only one should |
|
be printed */ |
|
Containers::String out; |
|
Debug{&out} << (GlyphCacheFeature::ImageProcessing|GlyphCacheFeature::ProcessedImageDownload); |
|
CORRADE_COMPARE(out, "Text::GlyphCacheFeature::ProcessedImageDownload\n"); |
|
} |
|
|
|
struct DummyGlyphCache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
}; |
|
|
|
struct DummyProcessingGlyphCache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
}; |
|
|
|
void AbstractGlyphCacheTest::construct() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {2, 5}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 512, 0})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.image().format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.image().size(), (Vector3i{1024, 512, 3})); |
|
|
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple(Vector2i{}, 0, Range2Di{})); |
|
CORRADE_COMPARE_AS(cache.glyphOffsets(), Containers::arrayView({ |
|
Vector2i{} |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphLayers(), Containers::arrayView({ |
|
0 |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphRectangles(), Containers::arrayView({ |
|
Range2Di{} |
|
}), TestSuite::Compare::Container); |
|
|
|
/* Const overloads */ |
|
const DummyGlyphCache& ccache = cache; |
|
CORRADE_COMPARE(ccache.atlas().size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(ccache.atlas().filledSize(), (Vector3i{1024, 512, 0})); |
|
CORRADE_COMPARE(ccache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(ccache.atlas().padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(ccache.image().format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(ccache.image().size(), (Vector3i{1024, 512, 3})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructNoPadding() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{1024, 512, 3})); |
|
/* 1 by default to avoid artifacts */ |
|
CORRADE_COMPARE(cache.padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple(Vector2i{}, 0, Range2Di{})); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 512, 0})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.image().format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.image().size(), (Vector3i{1024, 512, 3})); |
|
|
|
/* Invalid glyph is always present, has zero size in this case as well */ |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple(Vector2i{}, 0, Range2Di{})); |
|
CORRADE_COMPARE_AS(cache.glyphOffsets(), Containers::arrayView({ |
|
Vector2i{} |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphLayers(), Containers::arrayView({ |
|
0 |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphRectangles(), Containers::arrayView({ |
|
Range2Di{} |
|
}), TestSuite::Compare::Container); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::construct2D() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}, {2, 5}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), (Vector2i{2, 5})); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::construct2DNoPadding() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{1024, 512, 1})); |
|
/* 1 by default to avoid artifacts */ |
|
CORRADE_COMPARE(cache.padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), Vector2i{1}); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructProcessed() { |
|
DummyProcessingGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, PixelFormat::R16F, {256, 128}, {2, 5}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R16F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{256, 128, 3})); |
|
CORRADE_COMPARE(cache.padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 512, 0})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), (Vector2i{2, 5})); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructProcessedNoPadding() { |
|
DummyProcessingGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, PixelFormat::R16F, {256, 128}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R16F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{256, 128, 3})); |
|
/* 1 by default to avoid artifacts */ |
|
CORRADE_COMPARE(cache.padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 3})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 512, 0})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), Vector2i{1}); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructProcessed2D() { |
|
DummyProcessingGlyphCache cache{PixelFormat::R32F, {1024, 512}, PixelFormat::R16F, {256, 128}, {2, 5}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R16F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{256, 128, 1})); |
|
CORRADE_COMPARE(cache.padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), (Vector2i{2, 5})); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructProcessed2DNoPadding() { |
|
DummyProcessingGlyphCache cache{PixelFormat::R32F, {1024, 512}, PixelFormat::R16F, {256, 128}}; |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R32F); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.processedFormat(), PixelFormat::R16F); |
|
CORRADE_COMPARE(cache.processedSize(), (Vector3i{256, 128, 1})); |
|
/* 1 by default to avoid artifacts */ |
|
CORRADE_COMPARE(cache.padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
/* Invalid glyph is always present */ |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), Vector2i{1}); |
|
|
|
/* The rest shouldn't be any different */ |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::constructDeprecated() { |
|
/* Testing just the minimal set of getters as the deprecated constructor |
|
should delegate */ |
|
|
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
/* Not using the DummyGlyphCache as it'd warn about the deprecated |
|
constructor even with the IGNORE macros */ |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
} cache{{1024, 512}, {2, 5}}; |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R8Unorm); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_COMPARE(cache.textureSize(), (Vector2i{1024, 512})); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.padding(), (Vector2i{2, 5})); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), (Vector2i{2, 5})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructDeprecatedNoPadding() { |
|
/* Testing just the minimal set of getters as the deprecated constructor |
|
should delegate */ |
|
|
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
/* Not using the DummyGlyphCache as it'd warn about the deprecated |
|
constructor even with the IGNORE macros */ |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
} cache{{1024, 512}}; |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.format(), PixelFormat::R8Unorm); |
|
CORRADE_COMPARE(cache.size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_COMPARE(cache.textureSize(), (Vector2i{1024, 512})); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
/* 1 by default to avoid artifacts */ |
|
CORRADE_COMPARE(cache.padding(), Vector2i{1}); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.atlas().size(), (Vector3i{1024, 512, 1})); |
|
CORRADE_COMPARE(cache.atlas().filledSize(), (Vector3i{1024, 0, 1})); |
|
CORRADE_COMPARE(cache.atlas().flags(), TextureTools::AtlasLandfillFlag::WidestFirst); |
|
CORRADE_COMPARE(cache.atlas().padding(), Vector2i{1}); |
|
} |
|
#endif |
|
|
|
void AbstractGlyphCacheTest::constructImageRowPadding() { |
|
/* This shouldn't assert due to the data for the image being too small */ |
|
|
|
DummyGlyphCache cache{PixelFormat::RGB8Unorm, {2, 3, 5}}; |
|
CORRADE_COMPARE(cache.size(), (Vector3i{2, 3, 5})); |
|
CORRADE_COMPARE(cache.image().format(), PixelFormat::RGB8Unorm); |
|
CORRADE_COMPARE(cache.image().size(), (Vector3i{2, 3, 5})); |
|
CORRADE_COMPARE(cache.image().data().size(), 8*3*5); /* not 6*3*5 */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructZeroSize() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
DummyGlyphCache{PixelFormat::R8Unorm, {2, 0, 1}}; |
|
DummyGlyphCache{PixelFormat::R8Unorm, {0, 2, 1}}; |
|
DummyGlyphCache{PixelFormat::R8Unorm, {2, 2, 0}}; |
|
DummyGlyphCache{PixelFormat::R8Unorm, {2, 2}, PixelFormat::R8Unorm, {2, 0}}; |
|
DummyGlyphCache{PixelFormat::R8Unorm, {2, 2}, PixelFormat::R8Unorm, {0, 2}}; |
|
CORRADE_COMPARE(out, |
|
"Text::AbstractGlyphCache: expected non-zero size, got {2, 0, 1}\n" |
|
"Text::AbstractGlyphCache: expected non-zero size, got {0, 2, 1}\n" |
|
"Text::AbstractGlyphCache: expected non-zero size, got {2, 2, 0}\n" |
|
"Text::AbstractGlyphCache: expected non-zero processed size, got {2, 0}\n" |
|
"Text::AbstractGlyphCache: expected non-zero processed size, got {0, 2}\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructNoCreate() { |
|
DummyGlyphCache cache{NoCreate}; |
|
|
|
/* Shouldn't crash */ |
|
CORRADE_VERIFY(true); |
|
|
|
/* Implicit construction is not allowed */ |
|
CORRADE_VERIFY(!std::is_convertible<NoCreateT, DummyGlyphCache>::value); |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructCopy() { |
|
CORRADE_VERIFY(!std::is_copy_constructible<DummyGlyphCache>{}); |
|
CORRADE_VERIFY(!std::is_copy_assignable<DummyGlyphCache>{}); |
|
} |
|
|
|
void AbstractGlyphCacheTest::constructMove() { |
|
DummyGlyphCache a{PixelFormat::R16F, {1024, 512, 3}, {2, 5}}; |
|
|
|
DummyGlyphCache b = Utility::move(a); |
|
CORRADE_COMPARE(b.size(), (Vector3i{1024, 512, 3})); |
|
|
|
DummyGlyphCache c{PixelFormat::R8Unorm, {2, 3}}; |
|
c = Utility::move(b); |
|
CORRADE_COMPARE(c.size(), (Vector3i{1024, 512, 3})); |
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<DummyGlyphCache>::value); |
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<DummyGlyphCache>::value); |
|
} |
|
|
|
void AbstractGlyphCacheTest::features() { |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return GlyphCacheFeature::ImageProcessing; } |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
} cache{PixelFormat::R8Unorm, {2, 3}}; |
|
|
|
CORRADE_COMPARE(cache.features(), GlyphCacheFeature::ImageProcessing); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::textureSizeNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.textureSize(); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::textureSize(): can't be used on an array glyph cache\n"); |
|
} |
|
#endif |
|
|
|
void AbstractGlyphCacheTest::setInvalidGlyph() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {2, 3}}; |
|
|
|
cache.setInvalidGlyph({3, 5}, 2, {{15, 30}, {45, 35}}); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple( |
|
Vector2i{1, 2}, |
|
2, |
|
Range2Di{{13, 27}, {47, 38}})); |
|
|
|
/* Invalid glyph spanning the whole area (with padding) shouldn't assert */ |
|
cache.setInvalidGlyph({3, 5}, 2, {{2, 3}, {1022, 509}}); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple( |
|
Vector2i{1, 2}, |
|
2, |
|
Range2Di{{}, {1024, 512}})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setInvalidGlyph2D() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}, {2, 3}}; |
|
|
|
cache.setInvalidGlyph({3, 5}, {{15, 30}, {45, 35}}); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple( |
|
Vector2i{1, 2}, |
|
0, |
|
Range2Di{{13, 27}, {47, 38}})); |
|
|
|
/* Invalid glyph spanning the whole area is tested above already */ |
|
} |
|
|
|
void AbstractGlyphCacheTest::setInvalidGlyphOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Default padding is 1, test that it works for zero as well */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setInvalidGlyph({}, -1, {{15, 30}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 3, {{15, 30}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, -1}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{-1, 30}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 30}, {1025, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 30}, {45, 513}}); |
|
/* Negative rect size */ |
|
cache.setInvalidGlyph({}, 0, {{45, 30}, {15, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 35}, {45, 30}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer -1 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 3 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
|
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, -1}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{-1, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 30}, {1025, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 30}, {45, 513}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
|
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{45, 30}, {15, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 35}, {45, 30}} out of range for size {1024, 512, 3} and padding {0, 0}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setInvalidGlyphOutOfRangePadded() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {2, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
/* Padding has no effect on layers */ |
|
cache.setInvalidGlyph({}, -1, {{15, 30}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 3, {{15, 30}, {45, 35}}); |
|
/* These four pass if padding is not included in the check */ |
|
cache.setInvalidGlyph({}, 0, {{15, 1}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{1, 30}, {45, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 30}, {1023, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 30}, {45, 510}}); |
|
/* Negative rect size. The second would pass if it was checked with |
|
padding included. */ |
|
cache.setInvalidGlyph({}, 0, {{45, 30}, {15, 35}}); |
|
cache.setInvalidGlyph({}, 0, {{15, 35}, {45, 30}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer -1 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 3 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
|
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 1}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{1, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 30}, {1023, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 30}, {45, 510}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
|
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{45, 30}, {15, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::setInvalidGlyph(): layer 0 and rectangle {{15, 35}, {45, 30}} out of range for size {1024, 512, 3} and padding {2, 3}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setInvalidGlyph2DNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setInvalidGlyph({}, {}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setInvalidGlyph(): use the layer overload for an array glyph cache\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addFont() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
const AbstractFont* font = reinterpret_cast<const AbstractFont*>(std::size_t{0xdeadbeef}); |
|
CORRADE_COMPARE(cache.findFont(*font), Containers::NullOpt); |
|
|
|
CORRADE_COMPARE(cache.addFont(35, nullptr), 0); |
|
CORRADE_COMPARE(cache.fontCount(), 1); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.fontGlyphCount(0), 35); |
|
CORRADE_COMPARE(cache.fontPointer(0), nullptr); |
|
CORRADE_COMPARE(cache.findFont(*font), Containers::NullOpt); |
|
|
|
CORRADE_COMPARE(cache.addFont(12, font), 1); |
|
CORRADE_COMPARE(cache.fontCount(), 2); |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.fontGlyphCount(1), 12); |
|
CORRADE_COMPARE(cache.fontPointer(1), font); |
|
CORRADE_COMPARE(cache.findFont(*font), 1); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addFontDuplicatePointer() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
cache.addFont(7, nullptr); |
|
|
|
const AbstractFont* font = reinterpret_cast<const AbstractFont*>(std::size_t{0xdeadbeef}); |
|
cache.addFont(35, font); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addFont(12, font); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::addFont(): pointer 0xdeadbeef already used for font 1\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::fontOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
const AbstractFont* font = reinterpret_cast<const AbstractFont*>(std::size_t{0xdeadbeef}); |
|
cache.addFont(35, nullptr); |
|
cache.addFont(12, font); |
|
CORRADE_COMPARE(cache.fontCount(), 2); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.fontGlyphCount(2); |
|
cache.fontPointer(2); |
|
CORRADE_COMPARE(out, |
|
"Text::AbstractGlyphCache::fontGlyphCount(): index 2 out of range for 2 fonts\n" |
|
"Text::AbstractGlyphCache::fontPointer(): index 2 out of range for 2 fonts\n"); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::reserve() { |
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {24, 20}, {1, 2}}; |
|
|
|
/* Padding should get applied to all */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
std::vector<Range2Di> out = cache.reserve({ |
|
{5, 3}, |
|
/* Landscape glyphs shouldn't get rotated */ |
|
{12, 6}, |
|
{10, 5}, |
|
/* Zero-sized glyphs should get preserved */ |
|
{0, 1}, |
|
{3, 0}, |
|
}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE_AS(Containers::arrayView(out), Containers::arrayView<Range2Di>({ |
|
Range2Di::fromSize({6, 12}, {5, 3}), |
|
Range2Di::fromSize({1, 2}, {12, 6}), |
|
Range2Di::fromSize({13, 12}, {10, 5}), |
|
Range2Di::fromSize({4, 12}, {0, 1}), |
|
Range2Di::fromSize({1, 17}, {3, 0}), |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AbstractGlyphCacheTest::reserveIncremental() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {24, 20}, {1, 2}}; |
|
|
|
/* insert() is what triggers the assert, not reserve() alone */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(34, {3, 5}, {{10, 10}, {23, 10}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.reserve({{12, 6}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::reserve(): reserving space in non-empty cache is not yet implemented\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::reserveTooSmall() { |
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {24, 18}, {1, 2}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_VERIFY(cache.reserve({{5, 3}, {12, 6}, {10, 5}}).empty()); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::reserve(): requested atlas size Vector(24, 18) is too small to fit 3 textures. Generated atlas will be empty.\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::reserveNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.reserve({}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::reserve(): can't be used on an array glyph cache\n"); |
|
} |
|
#endif |
|
|
|
void AbstractGlyphCacheTest::addGlyph() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {2, 3}}; |
|
|
|
UnsignedInt font9 = cache.addFont(9); |
|
UnsignedInt font3 = cache.addFont(3); |
|
|
|
/* The queried values are with padding applied */ |
|
UnsignedInt font9Glyph6 = cache.addGlyph(font9, 6, {3, 4}, 2, {{15, 30}, {45, 35}}); |
|
CORRADE_COMPARE(font9Glyph6, 1); |
|
CORRADE_COMPARE(cache.glyph(font9Glyph6), Containers::triple( |
|
Vector2i{1, 1}, |
|
2, |
|
Range2Di{{13, 27}, {47, 38}})); |
|
|
|
/* Glyph in another font */ |
|
UnsignedInt font3Glyph1 = cache.addGlyph(font3, 1, {5, 6}, 1, {{10, 15}, {25, 30}}); |
|
CORRADE_COMPARE(font3Glyph1, 2); |
|
CORRADE_COMPARE(cache.glyph(font3Glyph1), Containers::triple( |
|
Vector2i{3, 3}, |
|
1, |
|
Range2Di{{8, 12}, {27, 33}})); |
|
|
|
/* Glyph adding order shouldn't matter; glyph spanning the whole area (with |
|
padding) shouldn't assert */ |
|
UnsignedInt font3Glyph0 = cache.addGlyph(font3, 0, {3, 5}, 2, {{2, 3}, {1022, 509}}); |
|
CORRADE_COMPARE(font3Glyph0, 3); |
|
CORRADE_COMPARE(cache.glyph(font3Glyph0), Containers::triple( |
|
Vector2i{1, 2}, |
|
2, |
|
Range2Di{{}, {1024, 512}})); |
|
|
|
/* Another glyph in an earlier font */ |
|
UnsignedInt font9Glyph3 = cache.addGlyph(font9, 3, {5, 7}, 0, {{5, 10}, {15, 30}}); |
|
CORRADE_COMPARE(font9Glyph3, 4); |
|
CORRADE_COMPARE(cache.glyph(font9Glyph3), Containers::triple( |
|
Vector2i{3, 4}, |
|
0, |
|
Range2Di{{3, 7}, {17, 33}})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyph2D() { |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}, {2, 3}}; |
|
|
|
cache.addFont(9); |
|
UnsignedInt fontId = cache.addFont(3); |
|
CORRADE_COMPARE(cache.addGlyph(fontId, 2, {3, 5}, {{15, 30}, {45, 35}}), 1); |
|
CORRADE_COMPARE(cache.glyphCount(), 2); |
|
CORRADE_COMPARE(cache.glyph(1), Containers::triple( |
|
Vector2i{1, 2}, |
|
0, |
|
Range2Di{{13, 27}, {47, 38}})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyphIndexOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
cache.addFont(9); |
|
UnsignedInt fontId = cache.addFont(3); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addGlyph(cache.fontCount(), 0, {}, 2, {}); |
|
cache.addGlyph(fontId, cache.fontGlyphCount(fontId), {}, 2, {}); |
|
CORRADE_COMPARE(out, |
|
"Text::AbstractGlyphCache::addGlyph(): index 2 out of range for 2 fonts\n" |
|
"Text::AbstractGlyphCache::addGlyph(): index 3 out of range for 3 glyphs in font 1\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyphAlreadyAdded() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Default padding of 1 makes it impossible to add a glyph at zero offset |
|
as it's out of range. Don't want to bother with that here so resetting |
|
it to 0. */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
cache.addFont(9); |
|
UnsignedInt fontId = cache.addFont(3); |
|
cache.addGlyph(fontId, 0, {}, 2, {}); |
|
cache.addGlyph(fontId, 1, {}, 2, {}); |
|
cache.addGlyph(fontId, 2, {}, 2, {}); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addGlyph(fontId, 2, {}, 2, {}); |
|
CORRADE_COMPARE(out, |
|
"Text::AbstractGlyphCache::addGlyph(): glyph 2 in font 1 already added at index 3\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyphOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Default padding is 1, test that it works for zero as well */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
UnsignedInt fontId = cache.addFont(9); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addGlyph(fontId, 1, {}, -1, {{15, 30}, {45, 35}}); |
|
cache.addGlyph(fontId, 2, {}, 3, {{15, 30}, {45, 35}}); |
|
cache.addGlyph(fontId, 3, {}, 0, {{15, -1}, {45, 35}}); |
|
cache.addGlyph(fontId, 4, {}, 0, {{-1, 30}, {45, 35}}); |
|
cache.addGlyph(fontId, 5, {}, 0, {{15, 30}, {1025, 35}}); |
|
cache.addGlyph(fontId, 6, {}, 0, {{15, 30}, {45, 513}}); |
|
/* Negative rect size */ |
|
cache.addGlyph(fontId, 8, {}, 0, {{45, 30}, {15, 35}}); |
|
cache.addGlyph(fontId, 7, {}, 0, {{15, 35}, {45, 30}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::addGlyph(): layer -1 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 3 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
|
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, -1}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{-1, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 30}, {1025, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 30}, {45, 513}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
|
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{45, 30}, {15, 35}} out of range for size {1024, 512, 3} and padding {0, 0}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 35}, {45, 30}} out of range for size {1024, 512, 3} and padding {0, 0}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyphOutOfRangePadded() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {2, 3}}; |
|
|
|
UnsignedInt fontId = cache.addFont(9); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
/* Padding has no effect on layers */ |
|
cache.addGlyph(fontId, 1, {}, -1, {{15, 30}, {45, 35}}); |
|
cache.addGlyph(fontId, 2, {}, 3, {{15, 30}, {45, 35}}); |
|
/* These four pass if padding is not included in the check */ |
|
cache.addGlyph(fontId, 3, {}, 0, {{15, 1}, {45, 35}}); |
|
cache.addGlyph(fontId, 4, {}, 0, {{1, 30}, {45, 35}}); |
|
cache.addGlyph(fontId, 5, {}, 0, {{15, 30}, {1023, 35}}); |
|
cache.addGlyph(fontId, 6, {}, 0, {{15, 30}, {45, 510}}); |
|
/* Negative rect size. The second would pass if it was checked with |
|
padding included. */ |
|
cache.addGlyph(fontId, 8, {}, 0, {{45, 30}, {15, 35}}); |
|
cache.addGlyph(fontId, 7, {}, 0, {{15, 35}, {45, 30}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::addGlyph(): layer -1 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 3 and rectangle {{15, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
|
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 1}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{1, 30}, {45, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 30}, {1023, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 30}, {45, 510}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
|
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{45, 30}, {15, 35}} out of range for size {1024, 512, 3} and padding {2, 3}\n" |
|
"Text::AbstractGlyphCache::addGlyph(): layer 0 and rectangle {{15, 35}, {45, 30}} out of range for size {1024, 512, 3} and padding {2, 3}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyphTooMany() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Default padding of 1 makes it impossible to add a glyph at zero offset |
|
as it's out of range. Don't want to bother with that here so resetting |
|
it to 0. */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}, {}}; |
|
|
|
/* Adding a font with over 65k potential glyphs is okay */ |
|
UnsignedInt fontId = cache.addFont(100000); |
|
|
|
for(UnsignedInt i = 0; i != 65535; ++i) |
|
cache.addGlyph(fontId, i, {}, {}); |
|
|
|
CORRADE_COMPARE(cache.glyphCount(), 65536); |
|
|
|
/* But adding 65k actual glyphs isn't */ |
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addGlyph(fontId, 65536, {}, {}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::addGlyph(): only at most 65536 glyphs can be added\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::addGlyph2DNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.addGlyph(0, 0, {}, {}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::addGlyph(): use the layer overload for an array glyph cache\n"); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::insert() { |
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {100, 200}, {2, 3}}; |
|
|
|
/* Overwriting the "Not Found" glyph. Shouldn't result in any font or glyph |
|
being added. */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(0, {3, 5}, {{10, 10}, {23, 45}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.glyphCount(), 1); |
|
CORRADE_COMPARE(cache.fontCount(), 0); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple( |
|
Vector2i{1, 2}, |
|
0, |
|
Range2Di{{8, 7}, {25, 48}})); |
|
|
|
/* Adding a new glyph adds the first font if not there yet, setting its |
|
glyph count to fit the glyph ID */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(25, {3, 4}, {{15, 30}, {45, 35}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.glyphCount(), 2); |
|
CORRADE_COMPARE(cache.fontCount(), 1); |
|
CORRADE_COMPARE(cache.fontGlyphCount(0), 26); |
|
CORRADE_COMPARE(cache.glyph(0, 25), Containers::triple( |
|
Vector2i{1, 1}, |
|
0, |
|
Range2Di{{13, 27}, {47, 38}})); |
|
|
|
/* Adding another glyph with a lower ID doesn't change the font in any |
|
way */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(5, {5, 6}, {{10, 15}, {25, 30}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.glyphCount(), 3); |
|
CORRADE_COMPARE(cache.fontCount(), 1); |
|
CORRADE_COMPARE(cache.fontGlyphCount(0), 26); |
|
CORRADE_COMPARE(cache.glyph(0, 5), Containers::triple( |
|
Vector2i{3, 3}, |
|
0, |
|
Range2Di{{8, 12}, {27, 33}})); |
|
|
|
/* Adding a glyph with greater ID expands the font glyph count again */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(35, {5, 7}, {{5, 10}, {15, 30}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(cache.glyphCount(), 4); |
|
CORRADE_COMPARE(cache.fontCount(), 1); |
|
CORRADE_COMPARE(cache.fontGlyphCount(0), 36); |
|
CORRADE_COMPARE(cache.glyph(0, 35), Containers::triple( |
|
Vector2i{3, 4}, |
|
0, |
|
Range2Di{{3, 7}, {17, 33}})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::insertNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(0, {}, {}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::insert(): can't be used on an array glyph cache\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::insertMultiFont() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
cache.addFont(15); |
|
cache.addFont(35); |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.insert(0, {}, {}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::insert(): can't be used on a multi-font glyph cache\n"); |
|
} |
|
#endif |
|
|
|
void AbstractGlyphCacheTest::flushImage() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Cache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector3i{15, 30, 3} - Vector3i{padding(), 0})); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 2} + Vector3i{2*padding(), 0})); |
|
|
|
if(padding().isZero()) { |
|
char pixels0[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
char pixels1[]{ |
|
'0', '1', '2', 0, |
|
'3', '4', '5', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels0}), |
|
DebugTools::CompareImage); |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[1], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels1}), |
|
DebugTools::CompareImage); |
|
} else { |
|
char pixels0[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 'a', 'b', 'c', 0, 0, 0, |
|
0, 0, 'd', 'e', 'f', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
char pixels1[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, '0', '1', '2', 0, 0, 0, |
|
0, 0, '3', '4', '5', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels0}), |
|
DebugTools::CompareImage); |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[1], |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels1}), |
|
DebugTools::CompareImage); |
|
} |
|
} |
|
|
|
bool called = false; |
|
} cache{NoCreate}; |
|
|
|
if(data.differentProcessedFormatSize) |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35, 5}, PixelFormat::RG32F, {12, 34}}; |
|
else |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35, 5}, data.padding}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
/* Copy two slices of the image */ |
|
char pixels[]{ |
|
'a', 'b', 'c', |
|
'd', 'e', 'f', |
|
'0', '1', '2', |
|
'3', '4', '5', |
|
}; |
|
Utility::copy( |
|
Containers::StridedArrayView3D<char>{pixels, {2, 2, 3}}, |
|
cache.image().pixels<char>().sliceSize({3, 30, 15}, {2, 2, 3})); |
|
|
|
cache.flushImage(Range3Di::fromSize({15, 30, 3}, {3, 2, 2})); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImageWholeArea() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Like above, but calling flushImage() with the whole size to test bounds |
|
checking. The padding doesn't affect the call in this case -- the actual |
|
range is always the whole image. */ |
|
|
|
struct Cache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
char pixels0[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
char pixels1[]{ |
|
'0', '1', '2', 0, |
|
'3', '4', '5', 0, |
|
}; |
|
CORRADE_COMPARE(offset, Vector3i{}); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 2})); |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels0}), |
|
DebugTools::CompareImage); |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[1], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels1}), |
|
DebugTools::CompareImage); |
|
} |
|
|
|
bool called = false; |
|
} cache{NoCreate}; |
|
|
|
if(data.differentProcessedFormatSize) |
|
cache = Cache{PixelFormat::R8Snorm, {3, 2, 5}, PixelFormat::RG32F, {1, 1}}; |
|
else |
|
cache = Cache{PixelFormat::R8Snorm, {3, 2, 2}, data.padding}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
/* Copy two slices of the image */ |
|
char pixels[]{ |
|
'a', 'b', 'c', |
|
'd', 'e', 'f', |
|
'0', '1', '2', |
|
'3', '4', '5', |
|
}; |
|
Utility::copy( |
|
Containers::StridedArrayView3D<char>{pixels, {2, 2, 3}}, |
|
cache.image().pixels<char>()); |
|
|
|
cache.flushImage({{}, {3, 2, 2}}); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImageLayer() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Single slice subset of flushImage() */ |
|
|
|
struct Cache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector3i{15, 30, 3} - Vector3i{padding(), 0})); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 1} + Vector3i{2*padding(), 0})); |
|
|
|
if(padding().isZero()) { |
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}), |
|
DebugTools::CompareImage); |
|
} else { |
|
char pixels[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 'a', 'b', 'c', 0, 0, 0, |
|
0, 0, 'd', 'e', 'f', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels}), |
|
DebugTools::CompareImage); |
|
} |
|
} |
|
|
|
bool called = false; |
|
} cache{NoCreate}; |
|
|
|
if(data.differentProcessedFormatSize) |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35, 5}, PixelFormat::RG32F, {12, 34}}; |
|
else |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35, 5}, data.padding}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', |
|
'd', 'e', 'f', |
|
}; |
|
Utility::copy( |
|
Containers::StridedArrayView3D<char>{pixels, {1, 2, 3}}, |
|
cache.image().pixels<char>().sliceSize({3, 30, 15}, {1, 2, 3})); |
|
|
|
cache.flushImage(3, Range2Di::fromSize({15, 30}, {3, 2})); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImage2D() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Like flushImageLayer() but reduced to two dimensions */ |
|
|
|
struct Cache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector3i{15, 30, 0} - Vector3i{padding(), 0})); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 1} + Vector3i{2*padding(), 0})); |
|
|
|
if(padding().isZero()) { |
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}), |
|
DebugTools::CompareImage); |
|
} else { |
|
char pixels[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 'a', 'b', 'c', 0, 0, 0, |
|
0, 0, 'd', 'e', 'f', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels}), |
|
DebugTools::CompareImage); |
|
} |
|
} |
|
|
|
bool called = false; |
|
} cache{NoCreate}; |
|
|
|
if(data.differentProcessedFormatSize) |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35}, PixelFormat::RG32F, {12, 34}}; |
|
else |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35}, data.padding}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', |
|
'd', 'e', 'f', |
|
}; |
|
Utility::copy( |
|
Containers::StridedArrayView2D<char>{pixels, {2, 3}}, |
|
cache.image().pixels<char>()[0].sliceSize({30, 15}, {2, 3})); |
|
|
|
cache.flushImage(Range2Di::fromSize({15, 30}, {3, 2})); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImage2DPassthrough2D() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Like flushImage2D() but with 2D doSetImage() */ |
|
|
|
struct Cache: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector2i& offset, const ImageView2D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector2i{15, 30}) - padding()); |
|
CORRADE_COMPARE(image.size(), (Vector2i{3, 2}) + 2*padding()); |
|
|
|
if(padding().isZero()) { |
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>(), |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}), |
|
DebugTools::CompareImage); |
|
} else { |
|
char pixels[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 'a', 'b', 'c', 0, 0, 0, |
|
0, 0, 'd', 'e', 'f', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>(), |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels}), |
|
DebugTools::CompareImage); |
|
} |
|
} |
|
|
|
bool called = false; |
|
} cache{NoCreate}; |
|
|
|
if(data.differentProcessedFormatSize) |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35}, PixelFormat::RG32F, {12, 34}}; |
|
else |
|
cache = Cache{PixelFormat::R8Snorm, {45, 35}, data.padding}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', |
|
'd', 'e', 'f', |
|
}; |
|
Utility::copy( |
|
Containers::StridedArrayView2D<char>{pixels, {2, 3}}, |
|
cache.image().pixels<char>()[0].sliceSize({30, 15}, {2, 3})); |
|
|
|
cache.flushImage(Range2Di::fromSize({15, 30}, {3, 2})); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImageNotImplemented() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
|
|
/* The 2D variant shouldn't be called on an array cache */ |
|
void doSetImage(const Vector2i&, const ImageView2D&) override { |
|
CORRADE_FAIL("This should not be called"); |
|
} |
|
} cache{PixelFormat::R32F, {1024, 512, 8}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.flushImage(0, {}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::image(): not implemented by derived class\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImagePassthrough2DNotImplemented() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
|
|
/* Should try the 3D variant, and from that one call into the 2D where |
|
it'd assert */ |
|
} cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.flushImage(0, {}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::image(): not implemented by derived class\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImageOutOfRange() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{NoCreate}; |
|
|
|
/* Neither the padding nor the processed size should not have any effect on |
|
the check */ |
|
if(data.differentProcessedFormatSize) |
|
cache = DummyGlyphCache{PixelFormat::R32F, {1024, 512, 8}, PixelFormat::R8Snorm, {1536, 768}}; |
|
else |
|
cache = DummyGlyphCache{PixelFormat::R32F, {1024, 512, 8}, data.padding}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
/* Negative min X, Y, layer */ |
|
cache.flushImage({{-1, 30, 4}, {45, 35, 6}}); |
|
cache.flushImage({{15, -1, 4}, {45, 35, 6}}); |
|
cache.flushImage({{15, 30, -1}, {45, 35, 6}}); |
|
cache.flushImage(-1, {{15, 30}, {45, 35}}); |
|
/* Too large max X, Y, layer */ |
|
cache.flushImage({{15, 30, 4}, {1025, 35, 6}}); |
|
cache.flushImage({{15, 30, 4}, {45, 513, 6}}); |
|
cache.flushImage({{15, 30, 4}, {45, 35, 9}}); |
|
cache.flushImage(8, {{15, 30}, {45, 35}}); |
|
/* Negative range size on X, Y, layer */ |
|
cache.flushImage({{45, 30, 4}, {15, 35, 6}}); |
|
cache.flushImage({{15, 35, 4}, {45, 30, 6}}); |
|
cache.flushImage({{15, 30, 6}, {45, 35, 4}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::flushImage(): {{-1, 30, 4}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, -1, 4}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, -1}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, -1}, {45, 35, 0}} out of range for size {1024, 512, 8}\n" |
|
|
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, 4}, {1025, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, 4}, {45, 513, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, 4}, {45, 35, 9}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, 8}, {45, 35, 9}} out of range for size {1024, 512, 8}\n" |
|
|
|
"Text::AbstractGlyphCache::flushImage(): {{45, 30, 4}, {15, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 35, 4}, {45, 30, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::flushImage(): {{15, 30, 6}, {45, 35, 4}} out of range for size {1024, 512, 8}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::flushImage2DNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.flushImage(Range2Di{}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::flushImage(): use the 3D or layer overload for an array glyph cache\n"); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::setImage() { |
|
auto&& data = FlushImageData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { return {}; } |
|
void doSetImage(const Vector2i& offset, const ImageView2D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector2i{15, 30}) - padding()); |
|
CORRADE_COMPARE(image.size(), (Vector2i{3, 2}) + 2*padding()); |
|
|
|
if(padding().isZero()) { |
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>(), |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}), |
|
DebugTools::CompareImage); |
|
} else { |
|
char pixels[]{ |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 'a', 'b', 'c', 0, 0, 0, |
|
0, 0, 'd', 'e', 'f', 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0, |
|
0, 0, 0, 0, 0, 0, 0, 0 |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>(), |
|
(ImageView2D{PixelFormat::R8Snorm, {7, 8}, pixels}), |
|
DebugTools::CompareImage); |
|
} |
|
} |
|
|
|
bool called = false; |
|
/* Deliberately using the deprecated PixelFormat-less constructor to verify |
|
that passing a R8Unorm image "just works" */ |
|
} cache{{45, 35}, data.padding}; |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
0, 0, 0, 0, 0, |
|
0, 'a', 'b', 'c', 0, |
|
0, 'd', 'e', 'f', 0, |
|
0, 0, 0, 0, 0 |
|
}; |
|
|
|
/* Testing with a custom PixelStorage to verify the right area gets copied |
|
to the internal image */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.setImage({15, 30}, ImageView2D{ |
|
PixelStorage{} |
|
.setAlignment(1) |
|
.setRowLength(5) |
|
.setSkip({1, 1, 0}), |
|
PixelFormat::R8Unorm, |
|
{3, 2}, |
|
pixels}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setImageOutOfRange() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {100, 200}}; |
|
|
|
/* This is fine */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.setImage({80, 175}, ImageView2D{PixelFormat::R8Unorm, {20, 25}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.setImage({81, 175}, ImageView2D{PixelFormat::R8Unorm, {20, 25}}); |
|
cache.setImage({80, 176}, ImageView2D{PixelFormat::R8Unorm, {20, 25}}); |
|
cache.setImage({-1, 175}, ImageView2D{PixelFormat::R8Unorm, {20, 25}}); |
|
cache.setImage({80, -1}, ImageView2D{PixelFormat::R8Unorm, {20, 25}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::setImage(): Range({81, 175}, {101, 200}) out of range for glyph cache of size Vector(100, 200)\n" |
|
"Text::AbstractGlyphCache::setImage(): Range({80, 176}, {100, 201}) out of range for glyph cache of size Vector(100, 200)\n" |
|
"Text::AbstractGlyphCache::setImage(): Range({-1, 175}, {19, 200}) out of range for glyph cache of size Vector(100, 200)\n" |
|
"Text::AbstractGlyphCache::setImage(): Range({80, -1}, {100, 24}) out of range for glyph cache of size Vector(100, 200)\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setImageInvalidFormat() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.setImage({15, 30}, ImageView2D{PixelFormat::R8Unorm, {45, 35}}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setImage(): expected PixelFormat::R32F but got PixelFormat::R8Unorm\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setImageNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache.setImage({}, ImageView2D{PixelFormat::R32F, {}, nullptr}); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setImage(): can't be used on an array glyph cache\n"); |
|
} |
|
#endif |
|
|
|
void AbstractGlyphCacheTest::processedImage() { |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ProcessedImageDownload; |
|
} |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
|
|
Image3D doProcessedImage() override { return Image3D{PixelFormat::RG8Unorm, {2, 3, 1}, Containers::Array<char>{NoInit, 6*2}}; } |
|
/* Using a different format or size for the source image shouldn't cause |
|
any problem */ |
|
} cache{PixelFormat::RG8Srgb, {200, 300}}; |
|
|
|
Image3D image = cache.processedImage(); |
|
CORRADE_COMPARE(image.format(), PixelFormat::RG8Unorm); |
|
CORRADE_COMPARE(image.size(), (Vector3i{2, 3, 1})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::processedImageNotSupported() { |
|
auto&& data = ProcessedImageNotSupportedData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct Cache: AbstractGlyphCache { |
|
explicit Cache(const Vector2i& size, GlyphCacheFeatures features): AbstractGlyphCache{PixelFormat::R8Unorm, size}, _features{features} {} |
|
|
|
GlyphCacheFeatures doFeatures() const override { return _features; } |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
|
|
GlyphCacheFeatures _features; |
|
} cache{{200, 300}, data.features}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.processedImage(); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::processedImage(): feature not supported\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::processedImageNotImplemented() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ProcessedImageDownload; |
|
} |
|
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
|
} cache{PixelFormat::R8Unorm, {200, 300}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.processedImage(); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::processedImage(): feature advertised but not implemented\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImage() { |
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
void doSetProcessedImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector3i{15, 30, 3})); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 2})); |
|
|
|
char pixels0[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
char pixels1[]{ |
|
'0', '1', '2', 0, |
|
'3', '4', '5', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels0}), |
|
DebugTools::CompareImage); |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[1], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels1}), |
|
DebugTools::CompareImage); |
|
} |
|
|
|
bool called = false; |
|
} cache{PixelFormat::RGB16Unorm, {4, 3, 5}, PixelFormat::R8Snorm, {45, 35}}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
'0', '1', '2', 0, |
|
'3', '4', '5', 0, |
|
}; |
|
cache.setProcessedImage({15, 30, 3}, ImageView3D{PixelFormat::R8Snorm, {3, 2, 2}, pixels}); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImage2D() { |
|
/* Like setProcessedImage() but reduced to two dimensions */ |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
void doSetProcessedImage(const Vector3i& offset, const ImageView3D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector3i{15, 30, 0})); |
|
CORRADE_COMPARE(image.size(), (Vector3i{3, 2, 1})); |
|
|
|
char pixels0[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>()[0], |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels0}), |
|
DebugTools::CompareImage); |
|
} |
|
|
|
bool called = false; |
|
} cache{PixelFormat::RGB16Unorm, {4, 3}, PixelFormat::R8Snorm, {45, 35}}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
cache.setProcessedImage({15, 30}, ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImage2DPassthrough2D() { |
|
/* Like setProcessedImage2D() but with 2D doSetProcessedImage() */ |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
void doSetProcessedImage(const Vector2i& offset, const ImageView2D& image) override { |
|
called = true; |
|
|
|
CORRADE_COMPARE(offset, (Vector2i{15, 30})); |
|
CORRADE_COMPARE(image.size(), (Vector2i{3, 2})); |
|
|
|
char pixels0[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
CORRADE_COMPARE_AS(image.pixels<Byte>(), |
|
(ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels0}), |
|
DebugTools::CompareImage); |
|
} |
|
|
|
bool called = false; |
|
} cache{PixelFormat::RGB16Unorm, {4, 3}, PixelFormat::R8Snorm, {45, 35}}; |
|
|
|
/* Capture correct function name */ |
|
CORRADE_VERIFY(true); |
|
|
|
char pixels[]{ |
|
'a', 'b', 'c', 0, |
|
'd', 'e', 'f', 0, |
|
}; |
|
cache.setProcessedImage({15, 30}, ImageView2D{PixelFormat::R8Snorm, {3, 2}, pixels}); |
|
CORRADE_VERIFY(cache.called); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImageNotImplemented() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
|
|
/* The 2D variant shouldn't be called on an array cache */ |
|
void doSetProcessedImage(const Vector2i&, const ImageView2D&) override { |
|
CORRADE_FAIL("This should not be called"); |
|
} |
|
} cache{PixelFormat::R32F, {1024, 512, 8}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setProcessedImage({}, ImageView3D{PixelFormat::R32F, {}}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setProcessedImage(): feature advertised but not implemented\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImagePassthrough2DNotImplemented() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
} cache{PixelFormat::R32F, {1024, 512}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setProcessedImage({}, ImageView3D{PixelFormat::R32F, {}}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setProcessedImage(): feature advertised but not implemented\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImageOutOfRange() { |
|
auto&& data = SetProcessedImageOutOfRangeData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Like flushImage(), but for setProcessedImage() */ |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
/* The source size and padding should not have any effect on the check */ |
|
} cache{PixelFormat::RGBA32F, {1536, 768, 8}, PixelFormat::R8Snorm, {1024, 512}, data.padding}; |
|
|
|
/* Large enough data to fit in all cases below, 4-byte aligned rows */ |
|
Containers::Array<char> image{NoInit, 1012*5*2}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
/* Negative min X, Y, layer */ |
|
cache.setProcessedImage({-1, 30, 4}, |
|
ImageView3D{PixelFormat::R8Snorm, {46, 5, 2}, image}); |
|
cache.setProcessedImage({15, -1, 4}, |
|
ImageView3D{PixelFormat::R8Snorm, {30, 36, 2}, image}); |
|
cache.setProcessedImage({15, 30, -1}, |
|
ImageView3D{PixelFormat::R8Snorm, {30, 5, 7}, image}); |
|
/* Too large max X, Y, layer */ |
|
cache.setProcessedImage({15, 30, 4}, |
|
ImageView3D{PixelFormat::R8Snorm, {1010, 5, 2}}); |
|
cache.setProcessedImage({15, 30, 4}, |
|
ImageView3D{PixelFormat::R8Snorm, {30, 483, 2}}); |
|
cache.setProcessedImage({15, 30, 4}, |
|
ImageView3D{PixelFormat::R8Snorm, {30, 5, 5}}); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::setProcessedImage(): {{-1, 30, 4}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::setProcessedImage(): {{15, -1, 4}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::setProcessedImage(): {{15, 30, -1}, {45, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
|
|
"Text::AbstractGlyphCache::setProcessedImage(): {{15, 30, 4}, {1025, 35, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::setProcessedImage(): {{15, 30, 4}, {45, 513, 6}} out of range for size {1024, 512, 8}\n" |
|
"Text::AbstractGlyphCache::setProcessedImage(): {{15, 30, 4}, {45, 35, 9}} out of range for size {1024, 512, 8}\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImageInvalidFormat() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
/* The source format should not have any effect on the check */ |
|
} cache{PixelFormat::RGBA32F, {1024, 512, 8}, PixelFormat::R8Snorm, {3, 2}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setProcessedImage({}, ImageView3D{PixelFormat::R8Unorm, {3, 2, 1}, "abcdefgh"}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setProcessedImage(): expected PixelFormat::R8Snorm but got PixelFormat::R8Unorm\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::setProcessedImage2DNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
struct: AbstractGlyphCache { |
|
using AbstractGlyphCache::AbstractGlyphCache; |
|
|
|
GlyphCacheFeatures doFeatures() const override { |
|
return GlyphCacheFeature::ImageProcessing; |
|
} |
|
} cache{PixelFormat::R8Unorm, {3, 2, 8}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.setProcessedImage({}, ImageView2D{PixelFormat::R8Unorm, {3, 2}, "abcdefgh"}); |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::setProcessedImage(): use the 3D overload for an array glyph cache\n"); |
|
} |
|
|
|
void AbstractGlyphCacheTest::access() { |
|
/* Padding tested well enough in addGlyph(), resetting it back to 0 here */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
cache.setInvalidGlyph({5, 7}, 2, {{5, 10}, {15, 30}}); |
|
|
|
UnsignedInt font9 = cache.addFont(9); |
|
UnsignedInt font3 = cache.addFont(3); |
|
UnsignedInt font9Glyph6 = cache.addGlyph(font9, 6, {3, 4}, 0, {{15, 30}, {45, 35}}); |
|
UnsignedInt font3Glyph1 = cache.addGlyph(font3, 1, {5, 6}, 1, {{10, 15}, {25, 30}}); |
|
UnsignedInt font9Glyph3 = cache.addGlyph(font9, 3, {6, 9}, 2, {{10, 5}, {25, 10}}); |
|
CORRADE_COMPARE(font9Glyph6, 1); |
|
CORRADE_COMPARE(font3Glyph1, 2); |
|
CORRADE_COMPARE(font9Glyph3, 3); |
|
|
|
/* Mapping to the global glyph ID */ |
|
CORRADE_COMPARE(cache.glyphId(font9, 6), font9Glyph6); |
|
CORRADE_COMPARE(cache.glyphId(font3, 1), font3Glyph1); |
|
CORRADE_COMPARE(cache.glyphId(font9, 3), font9Glyph3); |
|
|
|
/* Both overloads should return the same */ |
|
CORRADE_COMPARE(cache.glyph(font9, 6), Containers::triple( |
|
Vector2i{3, 4}, |
|
0, |
|
Range2Di{{15, 30}, {45, 35}})); |
|
CORRADE_COMPARE(cache.glyph(font9Glyph6), Containers::triple( |
|
Vector2i{3, 4}, |
|
0, |
|
Range2Di{{15, 30}, {45, 35}})); |
|
|
|
CORRADE_COMPARE(cache.glyph(font3, 1), Containers::triple( |
|
Vector2i{5, 6}, |
|
1, |
|
Range2Di{{10, 15}, {25, 30}})); |
|
CORRADE_COMPARE(cache.glyph(font3Glyph1), Containers::triple( |
|
Vector2i{5, 6}, |
|
1, |
|
Range2Di{{10, 15}, {25, 30}})); |
|
|
|
CORRADE_COMPARE(cache.glyph(font9, 3), Containers::triple( |
|
Vector2i{6, 9}, |
|
2, |
|
Range2Di{{10, 5}, {25, 10}})); |
|
CORRADE_COMPARE(cache.glyph(font9Glyph3), Containers::triple( |
|
Vector2i{6, 9}, |
|
2, |
|
Range2Di{{10, 5}, {25, 10}})); |
|
|
|
/* Mapping to the invalid glyph ID if it hasn't been added yet */ |
|
CORRADE_COMPARE(cache.glyphId(font9, 5), 0); |
|
CORRADE_COMPARE(cache.glyphId(font3, 2), 0); |
|
|
|
/* Querying glyphs that haven't been added yet gives back the invalid |
|
glyph properties */ |
|
CORRADE_COMPARE(cache.glyph(font9, 5), Containers::triple( |
|
Vector2i{5, 7}, |
|
2, |
|
Range2Di{{5, 10}, {15, 30}})); |
|
CORRADE_COMPARE(cache.glyph(font3, 2), Containers::triple( |
|
Vector2i{5, 7}, |
|
2, |
|
Range2Di{{5, 10}, {15, 30}})); |
|
CORRADE_COMPARE(cache.glyph(0), Containers::triple( |
|
Vector2i{5, 7}, |
|
2, |
|
Range2Di{{5, 10}, {15, 30}})); |
|
} |
|
|
|
void AbstractGlyphCacheTest::accessBatch() { |
|
/* Padding tested well enough in addGlyph(), resetting it back to 0 here */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
cache.setInvalidGlyph({5, 7}, 2, {{5, 10}, {15, 30}}); |
|
|
|
UnsignedInt font9 = cache.addFont(9); |
|
UnsignedInt font3 = cache.addFont(3); |
|
UnsignedInt font9Glyph6 = cache.addGlyph(font9, 6, {3, 4}, 0, {{15, 30}, {45, 35}}); |
|
UnsignedInt font3Glyph1 = cache.addGlyph(font3, 1, {5, 6}, 1, {{10, 15}, {25, 30}}); |
|
UnsignedInt font9Glyph3 = cache.addGlyph(font9, 3, {6, 9}, 2, {{10, 5}, {25, 10}}); |
|
CORRADE_COMPARE(font9Glyph6, 1); |
|
CORRADE_COMPARE(font3Glyph1, 2); |
|
CORRADE_COMPARE(font9Glyph3, 3); |
|
|
|
/* Direct data access */ |
|
CORRADE_COMPARE_AS(cache.glyphOffsets(), Containers::arrayView<Vector2i>({ |
|
{5, 7}, |
|
{3, 4}, |
|
{5, 6}, |
|
{6, 9}, |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphLayers(), Containers::arrayView({ |
|
2, |
|
0, |
|
1, |
|
2 |
|
}), TestSuite::Compare::Container); |
|
CORRADE_COMPARE_AS(cache.glyphRectangles(), Containers::arrayView<Range2Di>({ |
|
{{5, 10}, {15, 30}}, |
|
{{15, 30}, {45, 35}}, |
|
{{10, 15}, {25, 30}}, |
|
{{10, 5}, {25, 10}} |
|
}), TestSuite::Compare::Container); |
|
|
|
/* Querying glyph IDs in a batch way. Invalid IDs are set to 0. */ |
|
UnsignedInt glyphIds9[5]; |
|
cache.glyphIdsInto(font9, {5, 6, 3, 6, 1}, glyphIds9); |
|
CORRADE_COMPARE_AS(Containers::arrayView(glyphIds9), Containers::arrayView({ |
|
0u, 1u, 3u, 1u, 0u |
|
}), TestSuite::Compare::Container); |
|
|
|
UnsignedInt glyphIds3[3]; |
|
cache.glyphIdsInto(font3, {2, 0, 1}, glyphIds3); |
|
CORRADE_COMPARE_AS(Containers::arrayView(glyphIds3), Containers::arrayView({ |
|
0u, 0u, 2u |
|
}), TestSuite::Compare::Container); |
|
} |
|
|
|
void AbstractGlyphCacheTest::accessInvalid() { |
|
CORRADE_SKIP_IF_NO_DEBUG_ASSERT(); |
|
|
|
/* Silly test name, but these all test debug asserts while |
|
accessBatchInvalid() tests non-debug asserts */ |
|
|
|
/* Default padding of 1 makes it impossible to add a glyph at zero offset |
|
as it's out of range. Don't want to bother with that here so resetting |
|
it to 0. */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
cache.addFont(9); |
|
UnsignedInt fontId = cache.addFont(3); |
|
cache.addGlyph(0, 1, {}, 2, {}); |
|
cache.addGlyph(fontId, 1, {}, 2, {}); |
|
cache.addGlyph(fontId, 2, {}, 2, {}); |
|
|
|
UnsignedInt fontGlyphIds[]{ |
|
0, 0, cache.fontGlyphCount(fontId), 0 |
|
}; |
|
UnsignedInt glyphIds[4]; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.glyph(cache.fontCount(), 0); |
|
cache.glyphId(cache.fontCount(), 0); |
|
cache.glyph(fontId, cache.fontGlyphCount(fontId)); |
|
cache.glyphId(fontId, cache.fontGlyphCount(fontId)); |
|
cache.glyphIdsInto(fontId, fontGlyphIds, glyphIds); |
|
cache.glyph(cache.glyphCount()); |
|
CORRADE_COMPARE_AS(out, |
|
"Text::AbstractGlyphCache::glyph(): index 2 out of range for 2 fonts\n" |
|
"Text::AbstractGlyphCache::glyphId(): index 2 out of range for 2 fonts\n" |
|
"Text::AbstractGlyphCache::glyph(): index 3 out of range for 3 glyphs in font 1\n" |
|
"Text::AbstractGlyphCache::glyphId(): index 3 out of range for 3 glyphs in font 1\n" |
|
"Text::AbstractGlyphCache::glyphIdsInto(): glyph 2 index 3 out of range for 3 glyphs in font 1\n" |
|
"Text::AbstractGlyphCache::glyph(): index 4 out of range for 4 glyphs\n", |
|
TestSuite::Compare::String); |
|
} |
|
|
|
void AbstractGlyphCacheTest::accessBatchInvalid() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
/* Default padding of 1 makes it impossible to add a glyph at zero offset |
|
as it's out of range. Don't want to bother with that here so resetting |
|
it to 0. */ |
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}, {}}; |
|
|
|
cache.addFont(9); |
|
UnsignedInt fontId = cache.addFont(3); |
|
cache.addGlyph(fontId, 1, {}, 2, {}); |
|
cache.addGlyph(fontId, 2, {}, 2, {}); |
|
|
|
UnsignedInt fontGlyphIds[4]; |
|
UnsignedInt glyphIds[4]; |
|
UnsignedInt glyphIdsInvalid[3]; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
cache.glyphIdsInto(cache.fontCount(), fontGlyphIds, glyphIds); |
|
cache.glyphIdsInto(fontId, fontGlyphIds, glyphIdsInvalid); |
|
CORRADE_COMPARE(out, |
|
"Text::AbstractGlyphCache::glyphIdsInto(): index 2 out of range for 2 fonts\n" |
|
"Text::AbstractGlyphCache::glyphIdsInto(): expected fontGlyphIds and glyphIds views to have the same size but got 4 and 3\n"); |
|
} |
|
|
|
#ifdef MAGNUM_BUILD_DEPRECATED |
|
void AbstractGlyphCacheTest::accessDeprecated() { |
|
DummyGlyphCache cache{PixelFormat::R8Unorm, {100, 200}, {2, 3}}; |
|
|
|
cache.setInvalidGlyph({3, 5}, {{10, 10}, {23, 45}}); |
|
|
|
UnsignedInt fontId = cache.addFont(25); |
|
cache.addGlyph(fontId, 15, {3, 4}, {{15, 30}, {45, 35}}); |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_COMPARE(cache[15], std::make_pair( |
|
Vector2i{1, 1}, |
|
Range2Di{{13, 27}, {47, 38}} |
|
)); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
|
|
/* ID 0 gets the invalid glyph */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_COMPARE(cache[0], std::make_pair( |
|
Vector2i{1, 2}, |
|
Range2Di{{8, 7}, {25, 48}} |
|
)); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
|
|
/* Glyph IDs out of bounds get the invalid glyph too */ |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
CORRADE_COMPARE(cache[45], std::make_pair( |
|
Vector2i{1, 2}, |
|
Range2Di{{8, 7}, {25, 48}} |
|
)); |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
} |
|
|
|
void AbstractGlyphCacheTest::accessDeprecatedNot2D() { |
|
CORRADE_SKIP_IF_NO_ASSERT(); |
|
|
|
DummyGlyphCache cache{PixelFormat::R32F, {1024, 512, 3}}; |
|
|
|
Containers::String out; |
|
Error redirectError{&out}; |
|
CORRADE_IGNORE_DEPRECATED_PUSH |
|
cache[5]; |
|
CORRADE_IGNORE_DEPRECATED_POP |
|
CORRADE_COMPARE(out, "Text::AbstractGlyphCache::operator[](): can't be used on an array glyph cache\n"); |
|
} |
|
#endif |
|
|
|
}}}} |
|
|
|
CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractGlyphCacheTest)
|
|
|