mirror of https://github.com/mosra/magnum.git
Browse Source
Allows the Font and FontConverter plugins be built without TARGET_GL enabled. That was the last piece missing for making the magnum-plugins repo completely GL-free.pull/325/head
37 changed files with 1370 additions and 425 deletions
@ -0,0 +1,76 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
||||
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 "AbstractGlyphCache.h" |
||||
|
||||
#include "Magnum/Image.h" |
||||
#include "Magnum/TextureTools/Atlas.h" |
||||
|
||||
namespace Magnum { namespace Text { |
||||
|
||||
AbstractGlyphCache::AbstractGlyphCache(const Vector2i& size, const Vector2i& padding): _size{size}, _padding{padding} { |
||||
/* Default "Not Found" glyph. Can't do just `.insert({0, {}})` because
|
||||
that's ambiguous in C++17, due to a new insert(node_type&&) overload. */ |
||||
glyphs.insert({0, std::pair<Vector2i, Range2Di>{}}); |
||||
} |
||||
|
||||
AbstractGlyphCache::~AbstractGlyphCache() = default; |
||||
|
||||
std::vector<Range2Di> AbstractGlyphCache::reserve(const std::vector<Vector2i>& sizes) { |
||||
CORRADE_ASSERT((glyphs.size() == 1 && glyphs.at(0) == std::pair<Vector2i, Range2Di>()), |
||||
"Text::AbstractGlyphCache::reserve(): reserving space in non-empty cache is not yet implemented", {}); |
||||
glyphs.reserve(glyphs.size() + sizes.size()); |
||||
return TextureTools::atlas(_size, sizes, _padding); |
||||
} |
||||
|
||||
void AbstractGlyphCache::insert(const UnsignedInt glyph, const Vector2i& position, const Range2Di& rectangle) { |
||||
const std::pair<Vector2i, Range2Di> glyphData = {position-_padding, rectangle.padded(_padding)}; |
||||
|
||||
/* Overwriting "Not Found" glyph */ |
||||
if(glyph == 0) glyphs[0] = glyphData; |
||||
|
||||
/* Inserting new glyph */ |
||||
else CORRADE_INTERNAL_ASSERT_OUTPUT(glyphs.insert({glyph, glyphData}).second); |
||||
} |
||||
|
||||
void AbstractGlyphCache::setImage(const Vector2i& offset, const ImageView2D& image) { |
||||
CORRADE_ASSERT((offset >= Vector2i{} && offset + image.size() <= _size).all(), |
||||
"Text::AbstractGlyphCache::setImage():" << Range2Di::fromSize(offset, image.size()) << "out of bounds for texture size" << _size, ); |
||||
|
||||
doSetImage(offset, image); |
||||
} |
||||
|
||||
Image2D AbstractGlyphCache::image() { |
||||
CORRADE_ASSERT(features() & GlyphCacheFeature::ImageDownload, |
||||
"Text::AbstractGlyphCache::image(): feature not supported", Image2D{{}}); |
||||
|
||||
return doImage(); |
||||
} |
||||
|
||||
Image2D AbstractGlyphCache::doImage() { |
||||
CORRADE_ASSERT(false, "Text::AbstractGlyphCache::image(): feature advertised but not implemented", Image2D{{}}); |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,203 @@
|
||||
#ifndef Magnum_Text_AbstractGlyphCache_h |
||||
#define Magnum_Text_AbstractGlyphCache_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
||||
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. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::Text::AbstractGlyphCache |
||||
*/ |
||||
|
||||
#include <vector> |
||||
#include <unordered_map> |
||||
|
||||
#include "Magnum/Magnum.h" |
||||
#include "Magnum/Math/Range.h" |
||||
#include "Magnum/Text/visibility.h" |
||||
|
||||
namespace Magnum { namespace Text { |
||||
|
||||
/**
|
||||
@brief Features supported by a particular glyph cache implementation |
||||
|
||||
@see @ref GlyphCacheFeatures, @ref AbstractGlyphCache::features() |
||||
*/ |
||||
enum class GlyphCacheFeature: UnsignedByte { |
||||
/**
|
||||
* Ability to download glyph cache data using |
||||
* @ref AbstractGlyphCache::image(). May not be supported by glyph caches |
||||
* on embedded platforms that don't have an ability to get texture data |
||||
* back from a GPU. |
||||
*/ |
||||
ImageDownload = 1 << 0 |
||||
}; |
||||
|
||||
/**
|
||||
@brief Set of features supported by a glyph cache |
||||
|
||||
@see @ref AbstractGlyphCache::features() |
||||
*/ |
||||
typedef Containers::EnumSet<GlyphCacheFeature> GlyphCacheFeatures; |
||||
|
||||
CORRADE_ENUMSET_OPERATORS(GlyphCacheFeatures) |
||||
|
||||
/**
|
||||
@brief Base for glyph caches |
||||
|
||||
An API-agnostic base for glyph caches. See @ref GlyphCache and |
||||
@ref DistanceFieldGlyphCache for concrete implementations. |
||||
|
||||
@section Text-AbstractGlyphCache-subclassing Subclassing |
||||
|
||||
The subclass needs to implement the @ref doSetImage() function and manage the |
||||
glyph cache image. The public @ref setImage() function already does checking |
||||
for rectangle bounds so it's not needed to do it again on the implementation |
||||
side. |
||||
*/ |
||||
class MAGNUM_TEXT_EXPORT AbstractGlyphCache { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param size Glyph cache texture size |
||||
* @param padding Padding around every glyph |
||||
*/ |
||||
explicit AbstractGlyphCache(const Vector2i& size, const Vector2i& padding = {}); |
||||
|
||||
virtual ~AbstractGlyphCache(); |
||||
|
||||
/** @brief Features supported by this glyph cache implementation */ |
||||
GlyphCacheFeatures features() const { return doFeatures(); } |
||||
|
||||
/** Glyph cache texture size */ |
||||
Vector2i textureSize() const { return _size; } |
||||
|
||||
/** @brief Glyph padding */ |
||||
Vector2i padding() const { return _padding; } |
||||
|
||||
/** @brief Count of glyphs in the cache */ |
||||
std::size_t glyphCount() const { return glyphs.size(); } |
||||
|
||||
/**
|
||||
* @brief Parameters of given glyph |
||||
* @param glyph Glyph ID |
||||
* |
||||
* First tuple element is glyph position relative to point on baseline, |
||||
* second element is glyph region in texture atlas. |
||||
* |
||||
* Returned values include padding. |
||||
* |
||||
* If no glyph is found, glyph @cpp 0 @ce is returned, which is by |
||||
* default on zero position and has zero region in texture atlas. You |
||||
* can reset it to some meaningful value in @ref insert(). |
||||
* @see @ref padding() |
||||
*/ |
||||
std::pair<Vector2i, Range2Di> operator[](UnsignedInt glyph) const { |
||||
auto it = glyphs.find(glyph); |
||||
return it == glyphs.end() ? glyphs.at(0) : it->second; |
||||
} |
||||
|
||||
/** @brief Iterator access to cache data */ |
||||
std::unordered_map<UnsignedInt, std::pair<Vector2i, Range2Di>>::const_iterator begin() const { |
||||
return glyphs.begin(); |
||||
} |
||||
|
||||
/** @brief Iterator access to cache data */ |
||||
std::unordered_map<UnsignedInt, std::pair<Vector2i, Range2Di>>::const_iterator end() const { |
||||
return glyphs.end(); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Layout glyphs with given sizes to the cache |
||||
* |
||||
* Returns non-overlapping regions in cache texture to store glyphs. |
||||
* The reserved space is reused on next call to @ref reserve() if no |
||||
* glyph was stored there, use @ref insert() to store actual glyph on |
||||
* given position and @ref setImage() to upload glyph image. |
||||
* |
||||
* Glyph @p sizes are expected to be without padding. |
||||
* |
||||
* @attention Cache size must be large enough to contain all rendered |
||||
* glyphs. |
||||
* @see @ref padding() |
||||
*/ |
||||
std::vector<Range2Di> reserve(const std::vector<Vector2i>& sizes); |
||||
|
||||
/**
|
||||
* @brief Insert glyph to cache |
||||
* @param glyph Glyph ID |
||||
* @param position Position relative to point on baseline |
||||
* @param rectangle Region in texture atlas |
||||
* |
||||
* You can obtain unused non-overlapping regions with @ref reserve(). |
||||
* You can't overwrite already inserted glyph, however you can reset |
||||
* glyph @cpp 0 @ce to some meaningful value. |
||||
* |
||||
* Glyph parameters are expected to be without padding. |
||||
* |
||||
* See also @ref setImage() to upload glyph image. |
||||
* @see @ref padding() |
||||
*/ |
||||
void insert(UnsignedInt glyph, const Vector2i& position, const Range2Di& rectangle); |
||||
|
||||
/**
|
||||
* @brief Set cache image |
||||
* |
||||
* Uploads image for one or more glyphs to given offset in cache |
||||
* texture. Calls @ref doSetImage(). The @p offset and |
||||
* @ref ImageView::size() are expected tro be in bounds for |
||||
* @ref textureSize(). |
||||
*/ |
||||
void setImage(const Vector2i& offset, const ImageView2D& image); |
||||
|
||||
/**
|
||||
* @brief Download cache image |
||||
* |
||||
* Downloads the cache texture back. Calls @ref doImage(). Available |
||||
* only if @ref GlyphCacheFeature::ImageDownload is supported. |
||||
* @see @ref features() |
||||
*/ |
||||
Image2D image(); |
||||
|
||||
private: |
||||
/** @brief Implementation for @ref features() */ |
||||
virtual GlyphCacheFeatures doFeatures() const = 0; |
||||
|
||||
/**
|
||||
* @brief Implementation for @ref setImage() |
||||
* |
||||
* The @p offset and @ref ImageView::size() are guaranteed to be in |
||||
* bounds for @ref textureSize(). |
||||
*/ |
||||
virtual void doSetImage(const Vector2i& offset, const ImageView2D& image) = 0; |
||||
|
||||
/** @brief Implementation for @ref image() */ |
||||
virtual Image2D doImage(); |
||||
|
||||
Vector2i _size, _padding; |
||||
std::unordered_map<UnsignedInt, std::pair<Vector2i, Range2Di>> glyphs; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,192 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <tuple> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Image.h" |
||||
#include "Magnum/PixelFormat.h" |
||||
#include "Magnum/Text/AbstractGlyphCache.h" |
||||
|
||||
namespace Magnum { namespace Text { namespace Test { namespace { |
||||
|
||||
struct AbstractGlyphCacheTest: TestSuite::Tester { |
||||
explicit AbstractGlyphCacheTest(); |
||||
|
||||
void initialize(); |
||||
void access(); |
||||
void reserve(); |
||||
|
||||
void setImage(); |
||||
void setImageOutOfBounds(); |
||||
|
||||
void image(); |
||||
void imageNotSupported(); |
||||
void imageNotImplemented(); |
||||
}; |
||||
|
||||
AbstractGlyphCacheTest::AbstractGlyphCacheTest() { |
||||
addTests({&AbstractGlyphCacheTest::initialize, |
||||
&AbstractGlyphCacheTest::access, |
||||
&AbstractGlyphCacheTest::reserve, |
||||
|
||||
&AbstractGlyphCacheTest::setImage, |
||||
&AbstractGlyphCacheTest::setImageOutOfBounds, |
||||
|
||||
&AbstractGlyphCacheTest::image, |
||||
&AbstractGlyphCacheTest::imageNotSupported, |
||||
&AbstractGlyphCacheTest::imageNotImplemented}); |
||||
} |
||||
|
||||
struct DummyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return {}; } |
||||
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
||||
}; |
||||
|
||||
void AbstractGlyphCacheTest::initialize() { |
||||
DummyGlyphCache cache({1024, 2048}); |
||||
|
||||
CORRADE_COMPARE(cache.textureSize(), (Vector2i{1024, 2048})); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::access() { |
||||
DummyGlyphCache cache(Vector2i(236)); |
||||
Vector2i position; |
||||
Range2Di rectangle; |
||||
|
||||
/* Default "Not Found" glyph */ |
||||
CORRADE_COMPARE(cache.glyphCount(), 1); |
||||
std::tie(position, rectangle) = cache[0]; |
||||
CORRADE_COMPARE(position, Vector2i(0, 0)); |
||||
CORRADE_COMPARE(rectangle, Range2Di({0, 0}, {0, 0})); |
||||
|
||||
/* Overwrite the "Not Found" glyph */ |
||||
cache.insert(0, {3, 5}, {{10, 10}, {23, 45}}); |
||||
CORRADE_COMPARE(cache.glyphCount(), 1); |
||||
std::tie(position, rectangle) = cache[0]; |
||||
CORRADE_COMPARE(position, Vector2i(3, 5)); |
||||
CORRADE_COMPARE(rectangle, Range2Di({10, 10}, {23, 45})); |
||||
|
||||
/* Querying available glyph */ |
||||
cache.insert(25, {3, 4}, {{15, 30}, {45, 35}}); |
||||
CORRADE_COMPARE(cache.glyphCount(), 2); |
||||
std::tie(position, rectangle) = cache[25]; |
||||
CORRADE_COMPARE(position, Vector2i(3, 4)); |
||||
CORRADE_COMPARE(rectangle, Range2Di({15, 30}, {45, 35})); |
||||
|
||||
/* Querying not available glyph falls back to "Not Found" */ |
||||
std::tie(position, rectangle) = cache[42]; |
||||
CORRADE_COMPARE(position, Vector2i(3, 5)); |
||||
CORRADE_COMPARE(rectangle, Range2Di({10, 10}, {23, 45})); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::reserve() { |
||||
DummyGlyphCache cache(Vector2i(236)); |
||||
|
||||
/* Verify that this works for "empty" cache */ |
||||
CORRADE_VERIFY(!cache.reserve({{5, 3}}).empty()); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::setImage() { |
||||
struct MyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return {}; } |
||||
void doSetImage(const Vector2i& offset, const ImageView2D& image) override { |
||||
this->offset = offset; |
||||
this->size = image.size(); |
||||
} |
||||
|
||||
Vector2i offset, size; |
||||
} cache{{100, 200}}; |
||||
|
||||
cache.setImage({80, 175}, ImageView2D{{}, {20, 25}, nullptr}); |
||||
|
||||
CORRADE_COMPARE(cache.offset, (Vector2i{80, 175})); |
||||
CORRADE_COMPARE(cache.size, (Vector2i{20, 25})); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::setImageOutOfBounds() { |
||||
DummyGlyphCache cache{{100, 200}}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
cache.setImage({80, 175}, ImageView2D{{}, {20, 25}, nullptr}); |
||||
cache.setImage({81, 175}, ImageView2D{{}, {20, 25}, nullptr}); |
||||
cache.setImage({80, -1}, ImageView2D{{}, {20, 25}, nullptr}); |
||||
|
||||
CORRADE_COMPARE(out.str(), |
||||
"Text::AbstractGlyphCache::setImage(): Range({81, 175}, {101, 200}) out of bounds for texture size Vector(100, 200)\n" |
||||
"Text::AbstractGlyphCache::setImage(): Range({80, -1}, {100, 24}) out of bounds for texture size Vector(100, 200)\n"); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::image() { |
||||
struct MyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return GlyphCacheFeature::ImageDownload; } |
||||
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
||||
|
||||
Image2D doImage() override { return Image2D{PixelFormat::RG8Unorm}; } |
||||
} cache{{200, 300}}; |
||||
|
||||
Image2D image = cache.image(); |
||||
CORRADE_COMPARE(image.format(), PixelFormat::RG8Unorm); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::imageNotSupported() { |
||||
struct MyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return {}; } |
||||
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
||||
} cache{{200, 300}}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
cache.image(); |
||||
CORRADE_COMPARE(out.str(), "Text::AbstractGlyphCache::image(): feature not supported\n"); |
||||
} |
||||
|
||||
void AbstractGlyphCacheTest::imageNotImplemented() { |
||||
struct MyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return GlyphCacheFeature::ImageDownload; } |
||||
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
||||
} cache{{200, 300}}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
cache.image(); |
||||
CORRADE_COMPARE(out.str(), "Text::AbstractGlyphCache::image(): feature advertised but not implemented\n"); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractGlyphCacheTest) |
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <Corrade/Utility/Directory.h> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/GL/OpenGLTester.h" |
||||
#include "Magnum/Text/AbstractFont.h" |
||||
#include "Magnum/Text/AbstractGlyphCache.h" |
||||
#include "Magnum/Trade/AbstractImporter.h" |
||||
|
||||
#include "configure.h" |
||||
|
||||
namespace Magnum { namespace Text { namespace Test { namespace { |
||||
|
||||
struct MagnumFontTest: TestSuite::Tester { |
||||
explicit MagnumFontTest(); |
||||
|
||||
void nonexistent(); |
||||
void properties(); |
||||
void layout(); |
||||
|
||||
/* Explicitly forbid system-wide plugin dependencies */ |
||||
PluginManager::Manager<Trade::AbstractImporter> _importerManager{"nonexistent"}; |
||||
PluginManager::Manager<AbstractFont> _fontManager{"nonexistent"}; |
||||
}; |
||||
|
||||
MagnumFontTest::MagnumFontTest() { |
||||
addTests({&MagnumFontTest::nonexistent, |
||||
&MagnumFontTest::properties, |
||||
&MagnumFontTest::layout}); |
||||
|
||||
/* Load the plugins directly from the build tree. Otherwise they're static
|
||||
and already loaded. */ |
||||
#if defined(TGAIMPORTER_PLUGIN_FILENAME) && defined(MAGNUMFONT_PLUGIN_FILENAME) |
||||
CORRADE_INTERNAL_ASSERT(_importerManager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
CORRADE_INTERNAL_ASSERT(_fontManager.load(MAGNUMFONT_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
#endif |
||||
} |
||||
|
||||
void MagnumFontTest::nonexistent() { |
||||
Containers::Pointer<AbstractFont> font = _fontManager.instantiate("MagnumFont"); |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
CORRADE_VERIFY(!font->openFile("nonexistent.conf", 0.0f)); |
||||
CORRADE_COMPARE(out.str(), "Text::MagnumFont::openFile(): cannot open file nonexistent.conf\n"); |
||||
} |
||||
|
||||
void MagnumFontTest::properties() { |
||||
Containers::Pointer<AbstractFont> font = _fontManager.instantiate("MagnumFont"); |
||||
|
||||
CORRADE_VERIFY(font->openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f)); |
||||
CORRADE_COMPARE(font->size(), 16.0f); |
||||
CORRADE_COMPARE(font->ascent(), 25.0f); |
||||
CORRADE_COMPARE(font->descent(), -10.0f); |
||||
CORRADE_COMPARE(font->lineHeight(), 39.7333f); |
||||
CORRADE_COMPARE(font->glyphAdvance(font->glyphId(U'W')), Vector2(23.0f, 0.0f)); |
||||
} |
||||
|
||||
void MagnumFontTest::layout() { |
||||
Containers::Pointer<AbstractFont> font = _fontManager.instantiate("MagnumFont"); |
||||
|
||||
CORRADE_VERIFY(font->openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f)); |
||||
|
||||
/* Fill the cache with some fake glyphs */ |
||||
struct DummyGlyphCache: AbstractGlyphCache { |
||||
using AbstractGlyphCache::AbstractGlyphCache; |
||||
|
||||
GlyphCacheFeatures doFeatures() const override { return {}; } |
||||
void doSetImage(const Vector2i&, const ImageView2D&) override {} |
||||
} cache{Vector2i{256}}; |
||||
cache.insert(font->glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}}); |
||||
cache.insert(font->glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}}); |
||||
|
||||
auto layouter = font->layout(cache, 0.5f, "Wave"); |
||||
CORRADE_VERIFY(layouter); |
||||
CORRADE_COMPARE(layouter->glyphCount(), 4); |
||||
|
||||
Range2D rectangle; |
||||
Range2D position; |
||||
Range2D textureCoordinates; |
||||
|
||||
/* 'W' */ |
||||
Vector2 cursorPosition; |
||||
std::tie(position, textureCoordinates) = layouter->renderGlyph(0, cursorPosition = {}, rectangle); |
||||
CORRADE_COMPARE(position, Range2D({0.78125f, 1.0625f}, {1.28125f, 4.8125f})); |
||||
CORRADE_COMPARE(textureCoordinates, Range2D({0, 0.03125f}, {0.0625f, 0.5f})); |
||||
CORRADE_COMPARE(cursorPosition, Vector2(0.71875f, 0.0f)); |
||||
|
||||
/* 'a' (not found) */ |
||||
std::tie(position, textureCoordinates) = layouter->renderGlyph(1, cursorPosition = {}, rectangle); |
||||
CORRADE_COMPARE(position, Range2D()); |
||||
CORRADE_COMPARE(textureCoordinates, Range2D()); |
||||
CORRADE_COMPARE(cursorPosition, Vector2(0.25f, 0.0f)); |
||||
|
||||
/* 'v' (not found) */ |
||||
std::tie(position, textureCoordinates) = layouter->renderGlyph(2, cursorPosition = {}, rectangle); |
||||
CORRADE_COMPARE(position, Range2D()); |
||||
CORRADE_COMPARE(textureCoordinates, Range2D()); |
||||
CORRADE_COMPARE(cursorPosition, Vector2(0.25f, 0.0f)); |
||||
|
||||
/* 'e' */ |
||||
std::tie(position, textureCoordinates) = layouter->renderGlyph(3, cursorPosition = {}, rectangle); |
||||
CORRADE_COMPARE(position, Range2D({0.78125f, 0.375f}, {2.28125f, 1.25f})); |
||||
CORRADE_COMPARE(textureCoordinates, Range2D({0.0625f, 0.015625f}, {0.25f, 0.125f})); |
||||
CORRADE_COMPARE(cursorPosition, Vector2(0.375f, 0.0f)); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Text::Test::MagnumFontTest) |
||||
Loading…
Reference in new issue